Информация
Получен из анализа альтернативного варианта прошивки системного монитора для Агат-9.
Использует синтаксис ассемблера xa.
Побайтово совместим с соответствующим вариантом системного монитора.

Всего известно два варианта прошивки системного монитора. В основной прошивке, поставляемой с большинством компьютеров этого семейства и описанной в документации, реализовано переключение 64-х текстовых страниц с использованием механизма выбора банка памяти, выбор палитр, а также загрузка ПЗУ автостарта с использованием битовых флагов, размещаемых по смещению $FE ПЗУ.
Во данном варианте прошивки присутствует большое количество кода от ПЗУ Агат-7. В этом варианте реализуется поддержка 16 текстовых страниц в режиме АЦР32 и 16 текстовых страниц в режиме АЦР64. Управление палитрой не реализуется. Загрузка ПЗУ автостарта выполняется по сигнатурам, аналогично Агат-7.
Особенностью второго варианта прошивки является то, что несмотря на значительно меньший объём кода по сравнению с первым вариантом, адреса большинства точек входа остаются неизменными, а неиспользуемые области памяти заполнены значениями $00.
В обоих вариантах прошивки присутствует ошибка в вызове команды чтения с магнитофона "R". Из-за того, что код этой подпрограммы размещается на странице памяти $FF (адрес $FF07) вместо страницы $FE, реальный вызов происходит по адресу $FE07 и попадает в тело подпрограммы вывода содержимого памяти.
Подпрограмма записи на магнитофон и соответствующая ей команда "W" удалены из системного монитора, по-видимому, из-за нехватки пространства памяти.
Листинг второго варианта
; System Monitor for Agat-9
; without memory banks control for text screen output
; without palette control
; with standard autostart control from Agat-7
; key and control char codes
ENTER_KEY = $8D
SPACE_KEY = $A0
UP_KEY = $99
DOWN_KEY = $9A
LEFT_KEY = $88
RIGHT_KEY = $95
CTRL_G_KEY = $87 ; perform beep
CTRL_L_KEY = $8C ; clear screen
CTRL_J_KEY = $8A
RIGHT_7_KEY = $9D
RIGHT_8_KEY = $9E
CTRL_C_KEY = $83
CTRL_X_KEY = $98
CTRL_E_KEY = $85 ; F2 key
CTRL_F_KEY = $86 ; F3 key
; some constants
num_cmds = 20
num_ctl = 10
line_warn_start= $F8 ; number of chars to warn
num_vars_3Fx = 5
; parameters
beep_pre_delay = $40 ; delay before beep
beep_interval = $C ; delay between signal change
beep_duration = $C0 ; duration of beep signal
tape_delay_1 = $32 ; delay for 1
tape_delay_0 = $2C ; delay for 0
tape_read_delay= $3A
lines_to_disass= $1C ; lines in single disassembly listing
initial_video_page = 4 ; initial video page number
title_pos = 26 ; AGAT title position X
video_mode_text = 2 ; text mode 32x32 or 64x32
cold_boot_const = $A5
inverse_mask = $28 ; bits for inversed attribs
normal_attrs = $2F ; initial value of attribs
cold_boot_code = cold_boot_const ^ (dialog_monitor >> 8)
BIT_OPCODE = $2C ; opcode for choice optimization
color_mask = 7 ; bits for color attribute
color_white = 7 ; white color constant
rom_flags_offset = $FE ; offset of flags byte in device's ROM
rom_type_offset = $FF ; offset of device type byte in device's ROM
; char codes
CHAR_SLASH = $DC
CHAR_MINUS = $AD
CHAR_0 = $B0
CHAR_9 = $B9
CHAR_A = $C1
CHAR_EOL = $8D
CHAR_SPACE = $A0 ; space character
CHAR_EQ = $BD
CHAR_COLON = $BA
CHAR_ASTERISK = $AA
CHAR_COMMA = $AC
CHAR_HASH = $A3
CHAR_LPAR = $A8
CHAR_RPAR = $A9
CHAR_CUR = $A4
CHAR_X = $D8
CHAR_Y = $D9
CHAR_QUEST = $BF
CHAR_E = $C5
CHAR_R = $D2
CHAR_S = $D3
CHAR_P = $D0
CHAR_CYR_G = $E7
CHAR_T = $D4
CHAR_CTRL_G = $87 ; make beep
CHAR_CTRL_L = $8C ; clear screen
CHAR_UNDERLINE = $DF
CHAR_SPACE_LOW = $20 ; space with bit7 = 0, screen fill
; zero page variables
autostart_addr = $00
slot_10_ind = $02
video_page_h = $19
wnd_left_2 = $20
wnd_right_2 = $21
wnd_top = $22
wnd_bottom = $23
cur_pos_x = $24
cur_pos_y = $25
cur_scr_addr = $28
tmp_2a = $2A
tmp_2b = $2B
tmp_2e = $2E
tmp_2f = $2F
prev_mem_page = $30
current_op = $31
cur_attr = $32
prompt_char = $33
prompt_index = $34
old_print_y = $35
print_char_ptr = $36
input_char_ptr = $38
user_pc = $3A
src_user_ptr = $3C
dst_user_ptr = $3E
current_ptr = $40
dest_user_ptr = $42
tmp_44 = $44
user_a = $45
user_x = $46
user_y = $47
user_p = $48
user_s = $49
rnd_counter_l = $4E
rnd_counter_h = $4F
; input buffer
input_buf = $0200
; device types table
dev_table = $0300
; 3Fx variables
brk_addr = $03F0
dialog_proc = $03F2
cold_boot = $03F4
nmi_proc = $03FB
irq_addr = $03FE
; i/o addresses
input_kbd_reg = $C000
reset_kbd_reg = $C010
tape_out_reg = $C020
beeper_out = $C030
palette_regs = $C058
tape_in_reg = $C060
input_lang = $C063
io_addr_base = $C080
mem_selector = $C100
video_selector = $C700
* = $F800
set_text_mode: ; A = text page number
AND #$2F ; 16 (T32) + 16 (T64) video pages allowed
ASL
ASL
ADC #video_mode_text ; video selector offset = (page shl 2) + 2
TAY
STA video_selector,Y
ASL cur_attr ; high bit = T64(1) / T32(0)
ASL ; transfer high selector bit to T64 attrib flag
ROR cur_attr ; high bit = T64(1) / T32(0)
AND #$78 ; compute global video page address
STA video_page_h ; all video pages always maps to address window $2000..$3FFF
RTS
restore_text_page: ; restores text mode and sets normal text attributes
LDA video_page_h
LSR
ADC #video_mode_text ; text mode 32x32 or 64x32
EOR cur_attr ; high bit = T64(1) / T32(0)
AND #$7F ; video selector mask not including 32/64 selector
EOR cur_attr ; high bit = T64(1) / T32(0)
TAY
STA video_selector,Y
set_normal_text:
LDA #color_white ; set white color
JMP set_color
; bank switching is not implemented in this variant of ROM
set_mem_page: RTS
; bank switching is not implemented in this variant of ROM
restore_mem_page:
RTS
; fill unused ROM gap
.dsb 54, $00
; calculate params for current instruction
; prints PC address, "-"
; returns A = command name index
calc_listing_params:
LDX user_pc
LDY user_pc+1
JSR print_eol_xy_minus
JSR print_2_spaces ; => X = 0
LDA (user_pc,X) ; current opcode
TAY ; Y = original opcode
LSR
BCC lower_bit_is_zero
ROR
BCS opcode_is_bad ; two lower bits are 11
CMP #$A2 ; 89h, exceptional opcode
BEQ opcode_is_bad ; replace opcode with 80h for bad commands
AND #$87 ; lower bits are 01, drop command bits, process addressing
lower_bit_is_zero:
LSR
TAX
LDA opcode_info,X ; index in addr_and_len table packed by 4 bits
BCS use_lower_flags ; if lower bits are 10 or 101, use lower 4 bits of flags (ZP/ABS) adressing
LSR
LSR
LSR
LSR
use_lower_flags:
AND #$F
BNE opcode_not_bad
opcode_is_bad: LDY #$80 ; replace opcode with 80h for bad commands
LDA #0 ; flags = 0 for bad commands
opcode_not_bad: TAX
LDA opcode_addr_and_len,X
STA tmp_2e
AND #3 ; max cmd size is 3
STA tmp_2f ; current bit for tape, cmd size-1 for disass
TYA
AND #$8F
TAX
TYA
LDY #3
CPX #$8A
BEQ skip_shift
next_shift: LSR
BCC skip_shift
LSR
retry_shift: LSR
ORA #$20
DEY
BNE retry_shift
INY
skip_shift: DEY
BNE next_shift
RTS
print_disass_line:
JSR calc_listing_params ; calculate params for current instruction
; prints PC address, "-"
; returns A = command name index
PHA
cmd_byte_loop: LDA (user_pc),Y
JSR print_hex_byte
LDX #1
cmd_space_loop: JSR print_x_spaces
CPY tmp_2f ; current bit for tape, cmd size-1 for disass
INY
BCC cmd_byte_loop
LDX #3 ; print 3 spaces instead of byte and space, use 3-char op names
CPY #4 ; total number of chars = 3*4
BCC cmd_space_loop
PLA
TAY
LDA packed_name_l,Y ; packed by 5 bits per char
STA tmp_2a ; current character from screen
LDA packed_name_h,Y ; packed by 5 bits per char
STA tmp_2b
cmd_name_loop: LDA #0
LDY #5 ; number of bits for single char
shift_loop: ASL tmp_2b
ROL tmp_2a ; current character from screen
ROL
DEY
BNE shift_loop
ADC #CHAR_QUEST ; ?
JSR print_char
DEX
BNE cmd_name_loop
JSR print_2_spaces ; => X = 0
LDY tmp_2f ; current bit for tape, cmd size-1 for disass
LDX #6
operand_loop: CPX #3
BEQ ending_chars
operand_char_loop:
ASL tmp_2e
BCC no_second_char
LDA first_op_chars-1,X
JSR print_char
LDA second_op_chars-1,X
BEQ no_second_char
JSR print_char
no_second_char: DEX
BNE operand_loop
RTS
not_rel_addr: DEY
BMI operand_char_loop
JSR print_hex_byte
ending_chars: LDA tmp_2e
CMP #$E8
LDA (user_pc),Y
BCC not_rel_addr
JSR calc_rel_addr ; A = offset => X = offset, A = low addr, Y = high addr
TAX
INX
BNE print_xy
INY
print_xy: TYA
JSR print_hex_byte
TXA
JMP print_hex_byte
next_disass_addr:
SEC
LDA tmp_2f ; current bit for tape, cmd size-1 for disass
; A = offset => X = offset, A = low addr, Y = high addr
calc_rel_addr: LDY user_pc+1
TAX
BPL forward_offset
DEY
forward_offset: ADC user_pc
BCC no_page_cross
INY
no_page_cross: RTS
; ---------------------------------------------------------------------------
opcode_info: .db $40, 2, $45, 3, $D0, 8, $40, 9, $30, $22, $45, $33
.db $D0, 8, $40, 9, $40, 2, $45, $33, $D0, 8, $40, 9 ; index in addr_and_len table packed by 4 bits
.db $40, 2, $45, $B3, $D0, 8, $40, 9, 0, $22, $44, $33
.db $D0, $8C, $44, 0, $11, $22, $44, $33, $D0, $8C, $44
.db $9A, $10, $22, $44, $33, $D0, 8, $40, 9, $10, $22
.db $44, $33, $D0, 8, $40, 9, $62, $13, $78, $A9
opcode_addr_and_len:.db 0, $21, $81, $82, 0, 0, $59, $4D, $91, $92, $86
.db $4A, $85, $9D
first_op_chars: .db CHAR_COMMA, CHAR_RPAR, CHAR_COMMA, CHAR_HASH, CHAR_LPAR
.db CHAR_CUR
second_op_chars:.db CHAR_Y, 0, CHAR_X, CHAR_CUR, CHAR_CUR, 0
packed_name_l: .db $1C, $8A, $1C, $23, $5D, $8B, $1B, $A1, $9D, $8A
.db $1D, $23, $9D, $8B, $1D, $A1, 0, $29, $19, $AE, $69 ; packed by 5 bits per char
.db $A8, $19, $23, $24, $53, $1B, $23, $24, $53, $19
.db $A1, 0, $1A, $5B, $5B, $A5, $69, $24, $24, $AE, $AE
.db $A8, $AD, $29, 0, $7C, 0, $15, $9C, $6D, $9C, $A5
.db $69, $29, $53, $84, $13, $34, $11, $A5, $69, $23
.db $A0
packed_name_h: .db $D8, $62, $5A, $48, $26, $62, $94, $88, $54, $44
.db $C8, $54, $68, $44, $E8, $94, 0, $B4, 8, $84, $74 ; packed by 5 bits per char
.db $B4, $28, $6E, $74, $F4, $CC, $4A, $72, $F2, $A4
.db $8A, 0, $AA, $A2, $A2, $74, $74, $74, $72, $44, $68
.db $B2, $32, $B2, 0, $22, 0, $1A, $1A, $26, $26, $72
.db $72, $88, $C8, $C4, $CA, $26, $48, $44, $44, $A2
.db $C8
start_irq: STA user_a
PLA
PHA
AND #$10
BNE is_brk
JMP (irq_addr)
is_brk: PLP
JSR store_regs
PLA
STA user_pc
PLA
STA user_pc+1
JMP (brk_addr)
brk_proc: JSR calc_listing_params ; prints PC address, "-"
JSR print_regs
JMP dialog_beep
start_rst: CLD
JSR beep_proc
LDA #normal_attrs
ORA cur_attr
STA cur_attr
JSR reset_scr_wnd
JSR default_output
JSR default_input
STA reset_kbd_reg
LDA dialog_proc+1
EOR #cold_boot_const
EOR cold_boot
BNE do_cold_boot
do_soft_boot: JSR restore_text_page
JMP (dialog_proc)
do_cold_boot: LDA #initial_video_page
JSR set_text_mode
JSR set_normal_text
LDX #agat_title - msg_start
JSR print_msg ; X = message offset in table
LDX #num_vars_3Fx
init_vars_loop: LDA init_vecs-1,X
STA brk_addr-1,X
DEX
BNE init_vars_loop
STX autostart_addr
LDA #$C7
STA autostart_addr+1
autostart_loop: LDY #7
DEC autostart_addr+1
LDA autostart_addr+1
CMP #$C0
BEQ do_soft_boot
sig_check_loop: LDA (0),Y
CMP autostart_sig-1,Y
BNE autostart_loop ; try next slot
DEY
DEY
BPL sig_check_loop
JMP (autostart_addr)
autostart_sig: .db $20, 0, 0, 0, 3, 0, $3C
.dsb 7, $00
STX autostart_addr+1
JMP (autostart_addr)
.dsb 57, $00
init_vecs: .dw brk_proc
.dw dialog_monitor
.db cold_boot_code
msg_print_char: JSR print_char
.db BIT_OPCODE
msg_set_pos: STA cur_pos_x
INX
; X = message offset in table
print_msg: LDA msg_start,X
BMI msg_print_char
BNE msg_set_pos
RTS
print_regs_eol: JSR print_eol
print_regs: LDA #user_a
STA current_ptr ; set pointer to register area to enter values
LDA #0
STA current_ptr+1
LDX #<-5 ; number of registers to print
print_reg: JSR print_space
LDA reg_names-$FB,X
JSR print_char
JSR print_eq
LDA user_a+5,X
JSR print_hex_byte
INX
BMI print_reg
RTS
tape_read_byte: LDX #8 ; number of bits to read
tape_pulse_loop: PHA
JSR input_tape_pulses
PLA
ROL
LDY #tape_read_delay
DEX
BNE tape_pulse_loop
RTS
input_tape_pulses:
JSR input_tape_pulse ; Y = pulses count; => ZF = value
; Y = pulses count; => ZF = value
input_tape_pulse:
DEY
LDA tape_in_reg ; bit 7 = input signal
EOR tmp_2f ; current bit for tape, cmd size-1 for disass
BPL input_tape_pulse ; Y = pulses count; => ZF = value
EOR tmp_2f ; current bit for tape, cmd size-1 for disass
STA tmp_2f ; current bit for tape, cmd size-1 for disass
CPY #$80 ; check bit 7
RTS
write_preamble: LDY #$4B
JSR tape_bit_out ; Y=retries, CF=output => X = X - 1, Y = delay0
BNE write_preamble
ADC #<-2
BCS write_preamble
LDY #33
JSR tape_bit_out ; Y=retries, CF=output => X = X - 1, Y = delay0
INY
INY
; Y=retries, CF=output => X = X - 1, Y = delay0
tape_bit_out: DEY
BNE tape_bit_out ; Y=retries, CF=output => X = X - 1, Y = delay0
BCC tape_output_0
LDY #tape_delay_1 ; delay for 1
second_delay_loop:
DEY
BNE second_delay_loop
tape_output_0: LDY tape_out_reg
LDY #tape_delay_0 ; delay for 0
DEX
RTS
inc_user_addr: INC dest_user_ptr
BNE inc_user_ptr
INC dest_user_ptr+1
inc_user_ptr: LDA src_user_ptr
CMP dst_user_ptr
LDA src_user_ptr+1
SBC dst_user_ptr+1
INC src_user_ptr
BNE end_user_ptr
INC src_user_ptr+1
end_user_ptr: RTS
print_eol_cur_addr_minus:
LDY src_user_ptr+1
LDX src_user_ptr
print_eol_xy_minus:
JSR print_eol
JSR print_xy
LDY #0
JMP print_minus
; A = cursor Y, not uses window
calc_scr_addr: STA cur_scr_addr+1
LDA #0
LSR cur_scr_addr+1
ROR
LSR cur_scr_addr+1
ROR
STA cur_scr_addr
LDA video_page_h
ADC cur_scr_addr+1
STA cur_scr_addr+1
RTS
msg_start: .db CHAR_E ; E
.db CHAR_R ; R
.db CHAR_R ; R
msg_beep_eol: .db CHAR_CTRL_G ; make BEEP
.db CHAR_EOL
.db 0
; ---------------------------------------------------------------------------
delay_proc: JMP some_delay
; ---------------------------------------------------------------------------
agat_title: .db CHAR_CTRL_L ; clear screen
.db title_pos ; AGAT title position X
.db CHAR_A ; A
.db CHAR_CYR_G ; Г
.db CHAR_A ; A
.db CHAR_T ; T
.db CHAR_MINUS ; -
.db CHAR_9 ; 9
.db 0
; X = 1 to set new address
set_user_pc:
TXA
BEQ nothing_to_copy
ptr_copy_loop: LDA src_user_ptr,X
STA user_pc,X
DEX
BPL ptr_copy_loop
nothing_to_copy: RTS
ctl_char_table: .db CTRL_E_KEY ; F2 key
.db CTRL_F_KEY ; F3 key
.db UP_KEY
.db DOWN_KEY
.db CTRL_J_KEY
.db LEFT_KEY
.db RIGHT_KEY
.db CTRL_L_KEY ; clear screen
.db RIGHT_7_KEY
.db RIGHT_8_KEY
.db CTRL_G_KEY ; perform beep
ctl_addr_l: .db <(char_del_proc-1) ; delete character, move line left
.db <(char_ins_proc-1) ; insert character, move line right
.db <(up_key_proc-1) ; move cursor up
.db <(down_key_proc-1) ; move cursor down
ctl_addr_eol_l: .db <(eol_key_proc-1) ; move to start of next line
.db <(left_key_proc-1) ; move cursor left
.db <(right_key_proc-1) ; move cursor right
.db <(clr_scr_proc-1) ; clear screen contents, reset cursor
.db <(clr_eol_proc-1) ; clear to end of line
.db <(clr_eos_proc-1) ; clear to end of screen
.db <(beep_proc-1) ; perform beep
process_char_output:
CMP #CHAR_EOL
BNE not_eol ; do not need to scroll lock
LDY input_kbd_reg
CPY #CHAR_SPACE ; space character
BNE not_eol_out ; not a space, do not lock
STY reset_kbd_reg
scroll_lock_loop:
LDY input_kbd_reg
BPL scroll_lock_loop
CPY #CTRL_C_KEY
BEQ not_eol_out ; do not clear Ctrl+C
STY reset_kbd_reg
not_eol_out: LDY #ctl_addr_eol_l - ctl_addr_l
ctl_char_found: LDA #>beep_proc ; all ctl procs are in single page
PHA
LDA ctl_addr_l,Y
PHA
ctl_char_none: RTS
reset_scr_wnd: LDA #0
STA user_p
STA wnd_top
STA wnd_left_2
LDA #64 ; text line size in bytes
STA wnd_right_2
LDA #32 ; number of lines
STA wnd_bottom
LDA #31 ; starting cursor position
STA cur_pos_y
BNE calc_cur_pos_addr
not_eol: BIT ctl_char_none ; 0x60 - check if bit6 and bit5 are both 0
BNE char_output
LDY #num_ctl
ctl_char_loop: CMP ctl_char_table,Y
BEQ ctl_char_found
DEY
BPL ctl_char_loop
BCS ctl_char_none
char_output: LDY cur_pos_x
STA (cur_scr_addr),Y
INY
LDA cur_attr ; high bit = T64(1) / T32(0)
BMI out_for_t64
STA (cur_scr_addr),Y
INY
BNE out_for_t64
right_key_proc: LDY cur_pos_x ; move cursor right
JSR inc_pos ; Y = pos
out_for_t64: STY cur_pos_x
CPY wnd_right_2
BCS eol_key_proc ; move to start of next line
do_nothing: RTS
left_key_proc: LDY cur_pos_x ; move cursor left
BNE not_jump_right
JSR up_key_proc ; move cursor up
LDY wnd_right_2
not_jump_right: JSR dec_pos ; Y = pos
STY cur_pos_x
LDA (cur_scr_addr),Y
ADC #<-34
RTS
up_key_proc: LDA wnd_top ; move cursor up
CMP cur_pos_y
BCS do_nothing
DEC cur_pos_y
BCC calc_cur_pos_addr
clr_scr_proc: LDA wnd_top ; clear screen contents, reset cursor
STA cur_pos_y
LDY #0
STY cur_pos_x
BEQ do_clear
clr_eos_proc: LDY cur_pos_x ; clear to end of screen
LDA cur_pos_y
do_clear: PHA
JSR upd_scr_addr ; A = cursor Y, uses window
JSR clear_scr_block ; CF = 1
LDY #0
PLA
ADC #0
CMP wnd_bottom
BCC do_clear
calc_cur_pos_addr:
LDA cur_pos_y
; A = cursor Y, uses window
upd_scr_addr: JSR calc_scr_addr ; A = cursor Y, not uses window
LDA cur_scr_addr
ADC wnd_left_2
STA cur_scr_addr
RTS
eol_key_proc: LDA #0 ; move to start of next line
STA cur_pos_x
down_key_proc: INC cur_pos_y ; move cursor down
LDA cur_pos_y
CMP wnd_bottom
BCC upd_scr_addr ; A = cursor Y, uses window
DEC cur_pos_y
LDA wnd_top
PHA
JSR upd_scr_addr ; A = cursor Y, uses window
retry_scroll: LDA cur_scr_addr
STA tmp_2a ; current character from screen
LDA cur_scr_addr+1
STA tmp_2b
LDY wnd_right_2
DEY
PLA
ADC #1
CMP wnd_bottom
BCS clear_last_line
PHA
JSR upd_scr_addr ; A = cursor Y, uses window
scroll_loop: LDA (cur_scr_addr),Y
STA (tmp_2a),Y ; current character from screen
DEY
BPL scroll_loop
BMI retry_scroll
clear_last_line: LDY #0
JSR clear_scr_block ; CF = 1
BCS calc_cur_pos_addr
.db 0
some_delay: SEC
outer_loop: PHA
inner_loop: SBC #1
BNE inner_loop
PLA
SBC #1
BNE outer_loop
RTS
clr_eol_proc: LDY cur_pos_x ; clear to end of line
clear_scr_block:
LDA #CHAR_SPACE_LOW ; space with bit7 = 0, screen fill
STA (cur_scr_addr),Y
INY
LDA cur_attr ; high bit = T64(1) / T32(0)
BMI clear_scr_t64
STA (cur_scr_addr),Y
INY
clear_scr_t64: CPY wnd_right_2
BCC clear_scr_block
RTS ; CF = 1
; perform beep
beep_proc: LDA #beep_pre_delay ; delay before beep
JSR some_delay
LDY #beep_duration ; duration of beep signal
beep_loop: LDA #beep_interval ; delay between signal change
JSR some_delay
LDA beeper_out
DEY
BNE beep_loop
RTS
; delete character, move line left
char_del_proc: LDY cur_pos_x
char_del_loop: JSR inc_pos ; Y = pos
LDA (cur_scr_addr),Y
JSR dec_pos ; Y = pos
STA (cur_scr_addr),Y
CMP #CHAR_SPACE_LOW ; space with bit7 = 0, screen fill
BEQ char_del_end
JSR inc_pos ; Y = pos
BNE char_del_loop
char_del_end: RTS
; insert character, move line right
char_ins_proc: LDY cur_pos_x
skip_to_end_of_block:
JSR inc_pos ; Y = pos
BEQ char_ins_loop
LDA (cur_scr_addr),Y
CMP #CHAR_SPACE_LOW ; space with bit7 = 0, screen fill
BNE skip_to_end_of_block
char_ins_loop: JSR dec_pos ; Y = pos
LDA (cur_scr_addr),Y
JSR inc_pos ; Y = pos
STA (cur_scr_addr),Y
JSR dec_pos ; Y = pos
CPY cur_pos_x
BNE char_ins_loop
LDA #CHAR_SPACE ; space character
STA (cur_scr_addr),Y
RTS
inc_pos: BIT cur_attr ; high bit = T64(1) / T32(0)
BMI inc_pos_t64
INY
inc_pos_t64: INY
RTS
dec_pos: BIT cur_attr ; high bit = T64(1) / T32(0)
BMI dec_pos_t64
DEY
dec_pos_t64: DEY
RTS
; input char using current char proc vector => A = char
input_char: JMP (input_char_ptr)
; input character with cursor blinking => A = char
input_char_proc:
JSR set_mem_page ; switch bank 1 to specified video page bank
LDY cur_pos_x
LDA (cur_scr_addr),Y
STA tmp_2a ; store current character from screen
cursor_toggle: LDA (cur_scr_addr),Y
EOR #CHAR_UNDERLINE ; _
EOR tmp_2a ; current character from screen
STA (cur_scr_addr),Y ; toggle cursor
input_loop: INC rnd_counter_l ; random counter from key input proc, low part
BNE no_inc_rnd_h
INC rnd_counter_h ; random counter, high part
LDA rnd_counter_h ; random counter, high part
AND #$3F ; toggle interval
BEQ cursor_toggle
no_inc_rnd_h: LDA input_kbd_reg
BPL input_loop
PHA
ASL
ASL
BCC not_switch_reg ; bit6 = 0, not are letters
EOR input_lang ; bit7 = 1 for lat, 0 for rus
BMI not_switch_reg ; default are latin keys on input
PLA
EOR #$A0 ; toggle bit5 (rus) and bit7 (small chars)
PHA
not_switch_reg: STA reset_kbd_reg
LDA tmp_2a ; current character from screen
STA (cur_scr_addr),Y ; restore character on screen
JSR restore_mem_page ; restore bank 1
PLA
RTS
do_print_char: JSR print_char
handle_edit_mode:
JSR input_char ; input char using current char proc vector => A = char
LDY #3 ; process first 4 control keys for immediate output
control_key_loop:
CMP ctl_char_table,Y
BEQ do_print_char
DEY
BPL control_key_loop
RTS
print_current_char:
JSR print_char
EOR #$20
BEQ no_input_overflow
EOR #$B8 ; $98 (Ctrl+X) xor $20
BEQ on_overflow
EOR #$10 ; $88 (Left) xor $98 xor $20
BNE not_control_key
BCS do_left_key
BCC no_input_overflow
not_control_key:
CPX #line_warn_start ; number of chars to warn
BCC not_overflow
JSR beep_proc ; perform beep
not_overflow: INX
BNE no_input_overflow
on_overflow: LDA #CHAR_SLASH ; /
JSR print_char
do_prompt: JSR print_eol
LDA prompt_char
JSR print_char
LDX #1
do_left_key: TXA
BEQ do_prompt
DEX
no_input_overflow:
JSR handle_edit_mode
CMP #RIGHT_KEY
BNE not_right
LDA tmp_2a ; current character from screen
not_right: STA input_buf,X
CMP #ENTER_KEY
BNE print_current_char
LDA #RIGHT_7_KEY
JSR print_char
BNE print_eol
.db 0
do_add_sub: LSR
BCC dump_addr
LSR
LSR
LDA dst_user_ptr
BCC do_subtract
EOR #$FF
do_subtract: ADC src_user_ptr
PHA
JSR print_eq
PLA
print_hex_byte: PHA
LSR
LSR
LSR
LSR
JSR print_hex_digit
PLA
AND #$F
print_hex_digit:
ORA #CHAR_0 ; 0
CMP #CHAR_9+1
BCC print_char
ADC #(CHAR_A - CHAR_0 - $0A - 1)
.db BIT_OPCODE
print_space: LDA #CHAR_SPACE ; space character
.db BIT_OPCODE
print_eol: LDA #CHAR_EOL ; end of line
.db BIT_OPCODE
print_minus: LDA #CHAR_MINUS ; -
.db BIT_OPCODE
print_eq: LDA #CHAR_EQ ; =
.db BIT_OPCODE
print_ctrl_l: LDA #CTRL_L_KEY ; clear screen
print_char: JMP (print_char_ptr)
print_char_proc:
STY old_print_y
PHA
JSR set_mem_page ; switch bank 1 to specified video page bank
PLA
PHA
JSR process_char_output
JSR restore_mem_page ; restore bank 1
LDY old_print_y
PLA
RTS
dump_next_byte: LDA src_user_ptr
ORA #7
read_broken_ptr: ; real read command locates at the next page
STA dst_user_ptr
LDA src_user_ptr+1
STA dst_user_ptr+1
mem_print_loop: LDA src_user_ptr
AND #7
BNE dump_not_eol
dump_addr: JSR print_eol_cur_addr_minus
dump_not_eol: JSR print_space
LDA (src_user_ptr),Y
LDX current_op
BEQ dump_as_hex
BIT ctl_char_none ; check if char is printable
BEQ dump_as_hex
JSR print_char
JSR print_space
BNE dump_end
dump_as_hex: JSR print_hex_byte
dump_end: JSR inc_user_ptr
BCC mem_print_loop
RTS
process_empty_cmd:
DEC prompt_index
BEQ dump_next_byte
space_cmd: DEX
BNE not_empty_line
CMP #CHAR_COLON ; :
BEQ do_enter_val
JMP do_add_sub
do_enter_val: STA current_op
LDA dst_user_ptr
STA (current_ptr),Y
INC current_ptr
BNE not_current_ptr_h_inc
INC current_ptr+1
not_current_ptr_h_inc:
RTS
set_current_op: LDY prompt_index
LDA input_buf-1,Y
not_empty_line: STA current_op
RTS
less_op: LDX #1
copy_loop: LDA dst_user_ptr,X
STA dest_user_ptr,X
STA tmp_44,X
DEX
BPL copy_loop
RTS
move_cmd: LDA (src_user_ptr),Y
STA (dest_user_ptr),Y
JSR inc_user_addr
BCC move_cmd
RTS
verify_cmd: LDA (src_user_ptr),Y
CMP (dest_user_ptr),Y
BEQ verify_cmd_ok
JSR print_eol_cur_addr_minus
LDA (src_user_ptr),Y
JSR print_hex_byte
JSR print_space
LDA #CHAR_LPAR ; (
JSR print_char
LDA (dest_user_ptr),Y
JSR print_hex_byte
LDA #CHAR_RPAR ; )
JSR print_char
verify_cmd_ok: JSR inc_user_addr
BCC verify_cmd
RTS
list_cmd: JSR set_user_pc ; X = 1 to set new address
LDA #lines_to_disass ; lines in single disassembly listing
list_cmd_loop: PHA
JSR print_disass_line
JSR next_disass_addr
STA user_pc
STY user_pc+1
PLA
SEC
SBC #1
BNE list_cmd_loop
RTS
dump_text_cmd: STA current_op
JSR dump_addr
JMP clear_cur_op
inverse_cmd: LDA #0 ; set inverse bits to 00
.db BIT_OPCODE
normal_cmd: LDA #inverse_mask ; bits for inversed attribs
EOR cur_attr ; high bit = T64(1) / T32(0)
AND #inverse_mask ; bits for inversed attribs
set_attribs: EOR cur_attr ; high bit = T64(1) / T32(0)
STA cur_attr ; high bit = T64(1) / T32(0)
RTS
default_input: LDA #0
STA dst_user_ptr
cmd_ctrl_K: LDX #input_char_ptr
LDY #<input_char_proc ; input character with cursor blinking => A = char
BNE set_io_proc
default_output: LDA #0
STA dst_user_ptr
cmd_ctrl_1: LDX #print_char_ptr
LDY #<print_char_proc
set_io_proc: LDA dst_user_ptr
AND #$F
BEQ reset_io_proc
ORA #$C0
LDY #0
.db BIT_OPCODE
reset_io_proc: LDA #>print_char_proc
STY 0,X
STA 1,X
RTS
call_user_proc: JSR set_user_pc ; X = 1 to set new address
JSR load_regs
JMP (user_pc)
cmd_regs: JMP print_regs_eol
cmd_text_page: LDA dst_user_ptr
JMP set_text_mode ; A = page number, 0..63. Pages 0..31 are 32x32, pages 32..63 are 64x32
cmd_set_color: LDA dst_user_ptr
set_color: EOR cur_attr ; high bit = T64(1) / T32(0)
AND #color_mask ; bits for color attribute
JMP set_attribs
NOP
call_proc: JSR process_empty_cmd
PLA
PLA
BNE dialog_monitor
RTS
cmd_read_real: ; located on wrong page, call is broken
JSR input_tape_pulses
LDA #22
JSR write_preamble
STA tmp_2e
JSR input_tape_pulses
skip_preamble: LDY #36
JSR input_tape_pulse ; Y = pulses count; => ZF = value
BCS skip_preamble
JSR input_tape_pulse ; Y = pulses count; => ZF = value
LDY #59
tape_read_loop: JSR tape_read_byte
STA (src_user_ptr,X)
EOR tmp_2e
STA tmp_2e
JSR inc_user_ptr
LDY #53
BCC tape_read_loop
JSR tape_read_byte
CMP tmp_2e
BNE tape_cs_error
LDX #msg_beep_eol - msg_start
.db BIT_OPCODE
tape_cs_error: LDX #msg_start - msg_start
JMP print_msg ; X = message offset in table
load_regs: LDA user_p
PHA
LDA user_a
LDX user_x
LDY user_y
PLP
RTS
store_all_regs: STA user_a
store_regs: STX user_x
STY user_y
PHP
PLA
STA user_p
TSX
STX user_s
CLD
RTS
print_2_spaces: LDX #2
print_x_spaces: JSR print_space
DEX
BNE print_x_spaces
RTS ; => X = 0
.db 0, 0, 0
dialog_beep: CLD
JSR beep_proc ; perform beep
dialog_monitor: LDA #CHAR_ASTERISK ; *
STA prompt_char
JSR do_prompt
JSR clear_cur_op
next_prompt: JSR parse_number ; => X = 1 for number, 0 for command
STY prompt_index
LDY #num_cmds
next_code: DEY
BMI dialog_beep
CMP cmd_char_codes,Y
BNE next_code
JSR call_cmd_proc
LDY prompt_index
JMP next_prompt
parse_digit: LDX #3 ; A = char, => X = 1
ASL
ASL
ASL
ASL
digit_loop: ASL
ROL dst_user_ptr
ROL dst_user_ptr+1
DEX
BPL digit_loop
copy_params_loop:
LDA current_op
BNE has_cur_op
LDA dst_user_ptr+1,X
STA src_user_ptr+1,X
STA current_ptr+1,X
has_cur_op: INX
BEQ copy_params_loop
BNE parse_next
parse_number: LDX #0
STX dst_user_ptr
STX dst_user_ptr+1
parse_next: LDA input_buf,Y
INY
EOR #CHAR_0 ; 0
CMP #10
BCC parse_digit ; A = char, => X = 1
ADC #$88
CMP #<-6
BCS parse_digit ; A = char, => X = 1
RTS ; => X = 1 for number, 0 for command
call_cmd_proc: LDA #>cmd_regs ; high byte of address
PHA
LDA cmd_low_bytes,Y
PHA
LDA current_op
clear_cur_op: LDY #0
STY current_op
RTS
cmd_char_codes: .db $E9, $EF, $ED, 8, $C4, $A9, $A6, $A4, 6, $95, 7 ; E9=P, EF=V, ED=T, 08=O, C4=Ctrl+K, A9="1", A6=-, A4=+, 6=M, 95=<, 7=N
.db 2, 5, $F1, $EB, 0, $93, $A7, $C6, $99 ; 2=I, 5=L, F1=X, EB=R, 0=G, 93=colon, A7=. , C6=ENTER, 99=SPACE
cmd_low_bytes: .db <(cmd_regs-1)
.db <(verify_cmd-1)
.db <(cmd_text_page-1)
.db <(cmd_set_color-1)
.db <(cmd_ctrl_K-1)
.db <(cmd_ctrl_1-1)
.db <(set_current_op-1)
.db <(set_current_op-1)
.db <(move_cmd-1)
.db <(less_op-1)
.db <(normal_cmd-1)
.db <(inverse_cmd-1)
.db <(list_cmd-1)
.db <(dump_text_cmd-1)
.db <(read_broken_ptr+1-1) ; READ command is broken!
.db <(call_user_proc-1)
.db <(set_current_op-1)
.db <(set_current_op-1)
.db <(call_proc-1)
.db <(space_cmd-1)
reg_names: .db CHAR_A ; A
.db CHAR_X ; X
.db CHAR_Y ; Y
.db CHAR_P ; P
.db CHAR_S ; S
.db 0
.dw nmi_proc
.dw start_rst
.dw start_irq
Дополнительные материалы
Файлы ПЗУ системного монитора: перейти.
Файл листинга: альтернативный вариант.
В начало
Вернуться на основную страницу
К прочим материалам
Прочие материалы
Реплики Агат-7
Посмотреть реплики узлов 7-й версии ПЭВМ Агат
Реплики Агат-9
Посмотреть реплики узлов 9-й версии ПЭВМ Агат