Информация

Получен из анализа альтернативного варианта прошивки системного монитора для Агат-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-й версии ПЭВМ Агат