Информация

Получен из анализа прошивки системного монитора для Агат-7.

Использует синтаксис ассемблера xa.

Побайтово совместим с штатным системным монитором.

Вид экрана системного монитора

Листинг

; Byte compatible system monitor for Agat-7
; For use with XA assembler

; key and control char codes
ENTER_KEY      = $8D
SPACE_KEY      = $A0
UP_KEY         = $99
DOWN_KEY       = $9A
LEFT_KEY       = $88
RIGHT_KEY      = $95
ESC_KEY        = $9B
CTRL_G_KEY     = $87
CTRL_L_KEY     = $8C
CTRL_J_KEY     = $8A
RIGHT_6_KEY    = $9C
RIGHT_7_KEY    = $9D
RIGHT_8_KEY    = $9E
CTRL_C_KEY     = $83
CTRL_X_KEY     = $98

; some constants
num_cmds       = $17
num_ctl        = 10
line_warn_start= $F8
title_num_bytes= $14
num_vars_3Fx   = 5

; parameters
beep_pre_delay = $40
beep_interval  = $0C
beep_duration  = $C0

tape_delay_1   = $32
tape_delay_0   = $2C
tape_delay_preamble= $4B
tape_read_delay= $3A
tape_preamble_duration= $40

lines_to_disass= $1C
initial_video_page= $0F
flash_cursor_attr= $0F
video_mode_text= $2
cold_boot_const= $A5
cold_boot_code = cold_boot_const ^ (dialog_monitor >> 8)
inverse_attr   = $87
normal_attr    = $AF
attr_title_green= $2A
attr_title_red = $29
attr_title_white= $2F

; char codes
CHAR_SLASH     = $DC
CHAR_MINUS     = $AD
CHAR_0         = $B0
CHAR_9         = $B9
CHAR_A         = $C1
CHAR_EOL       = $8D
CHAR_SPACE     = $A0
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_A     = $E1
CHAR_CYR_G     = $E7
CHAR_CYR_T     = $F4


; zero page variables
autostart_addr	= $00
video_page_h	= $19
video_page_next_h	= $1E
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_addr	= $2A
tmp_2c		= $2C
tmp_2d		= $2D
tmp_2e		= $2E
tmp_2f		= $2F
current_op	= $31
cur_attr	= $32
prompt_char	= $33
prompt_index	= $34
tmp_35		= $35
store_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
other_mode_page	= $D0

; input buffer
input_buf	= $200

; 3Fx variables
brk_addr	= $3F0
rst_proc	= $3F2
cold_boot	= $3F4
ctrl_Y_addr	= $3F8
nmi_proc	= $3FB
irq_addr	= $3FE

; other variables
some_autostart_addr	= $7F8

; video page address
title_video_addr	= $7810

; i/o addresses
input_kbd	= $C000
reset_kbd	= $C010
tape_out	= $C020
beeper_out	= $C030
tape_in		= $C060
pdl_input_port	= $C064
pdl_reset_port	= $C070
mem_selector_c0f0	= $C0F0
mem_selector_c0f1	= $C0F1
video_selector	= $C700

; basic vectors
basic_init	= $E000
basic_start	= $E003

* = $F800

translate_codes: ; unused subroutine
                PHA
                LSR
                LSR
                LSR
                LSR
                TAY
                PLA
                EOR     tbl1,Y
                CMP     #$A0
                BCS     tbl_skip
                CMP     #$90
                BCC     tbl_skip
                TAY
                LDA     tbl2-$90, Y
tbl_skip:       LDY     cur_pos_x
                RTS

; ---------------------------------------------------------------------------
tbl1:           .db $80, $B0, $D0, $D0, $D0, $E0, $B0, $B0
tbl2:           .db $88, $A0, $8D, $93, $94, $98, $96, $97, $95, $99
                .db $9A, $9B, $9C, $9D, $9E, $9B

; A = page, X = mode (2 = text)
set_video_mode:
                STX     tmp_2c
                LDY     video_page_variable,X
                ASL
                ASL
                PHA
                ASL
                CMP     #$C0
                BCC     wrap_addr
                SBC     #$3F
wrap_addr:      STA     0,Y
                ADC     video_page_size_h,X ; page size for different video modes
                EOR     video_page_next_h ; h byte of next page address
                AND     #$F8
                EOR     video_page_next_h ; h byte of next page address
                STA     video_page_next_h ; h byte of next page address
                PLA
                ADC     tmp_2c
                TAX
                STA     video_selector,X
                RTS
video_page_size_h:.db $08, $20, $08, $20   ; page size for different video modes
video_page_variable:.db other_mode_page, other_mode_page, video_page_h, other_mode_page

; A = video page address high byte
set_mem_bank:
                AND     #7
                TAY
                LDA     mem_banks,Y
                TAY
                STA     mem_selector_c0f0,Y
                RTS
mem_banks:      .db 0, 1, 10, 11, 6, 7, 2, 3

; calculate params for current instruction
; 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               ; lower bits are 00 or 001, use higher 4 bits of flags
use_lower_flags:
                AND     #$0F            ; check if index is zero (bad opcode)
                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              ; number of max shift iterations
                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

; disassemble single line
print_disass_line:
                JSR     calc_listing_params ; calculate params for current instruction
                                            ; returns A = command name index
                PHA
cmd_byte_loop:  LDA     (user_pc),Y
                JSR     print_hex_byte
                LDX     #1              ; spaces between command bytes
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_2c
                LDA     packed_name_h,Y ; packed by 5 bits per char
                STA     tmp_2d
cmd_name_loop:  LDA     #0
                LDY     #5              ; number of bits for single char
shift_loop:     ASL     tmp_2d
                ROL     tmp_2c
                ROL               ; insert bits from lower byte
                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 ; need ending chars
                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                     ; increment calculated addr
                INX
                BNE     print_xy        ; no page cross
                INY
print_xy:       TYA
                JSR     print_hex_byte
                TXA
                JMP     print_hex_byte


next_disass_addr:
                SEC
                LDA     tmp_2f          ; 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, $02, $45, $03, $D0, $08, $40, $09, $30, $22, $45, $33, $D0, $08, $40, $09 ; index in addr_and_len table packed by 4 bits
                .db $40, $02, $45, $33, $D0, $08, $40, $09, $40, $02, $45, $B3, $D0, $08, $40, $09
                .db $00, $22, $44, $33, $D0, $8C, $44, $00, $11, $22, $44, $33, $D0, $8C, $44, $9A
                .db $10, $22, $44, $33, $D0, $08, $40, $09, $10, $22, $44, $33, $D0, $08, $40, $09
                .db $62, $13, $78, $A9
opcode_addr_and_len:.db $00, $21, $81, $82, $00, $00, $59, $4D, $91, $92, $86, $4A, $85, $9D
first_op_chars: .db CHAR_COMMA, CHAR_RPAR, CHAR_COMMA, CHAR_HASH, CHAR_LPAR, 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, $1D, $23, $9D, $8B, $1D, $A1 ; packed by 5 bits per char relatively to '?'
                .db $00, $29, $19, $AE, $69, $A8, $19, $23, $24, $53, $1B, $23, $24, $53, $19, $A1
                .db $00, $1A, $5B, $5B, $A5, $69, $24, $24, $AE, $AE, $A8, $AD, $29, $00, $7C, $00
                .db $15, $9C, $6D, $9C, $A5, $69, $29, $53, $84, $13, $34, $11, $A5, $69, $23, $A0
packed_name_h:  .db $D8, $62, $5A, $48, $26, $62, $94, $88, $54, $44, $C8, $54, $68, $44, $E8, $94
                .db $00, $B4, $08, $84, $74, $B4, $28, $6E, $74, $F4, $CC, $4A, $72, $F2, $A4, $8A
                .db $00, $AA, $A2, $A2, $74, $74, $74, $72, $44, $68, $B2, $32, $B2, $00, $22, $00
                .db $1A, $1A, $26, $26, $72, $72, $88, $C8, $C4, $CA, $26, $48, $44, $44, $A2, $C8



start_irq:      STA     user_a
                PLA
                PHA
                ASL
                ASL
                ASL
                BMI     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 ; calculate params for current instruction
                                            ; returns A = command name index
                JSR     print_regs
                JMP     dialog_beep

start_rst:      CLD
                JSR     norm_cmd
                JSR     reset_scr_wnd
                JSR     default_output
                JSR     default_input
                BIT     reset_kbd
                CLD
                JSR     do_beep
                LDA     rst_proc+1
                EOR     #cold_boot_const
                CMP     cold_boot
                BNE     do_cold_boot
                JSR     select_text_mode
                LDA     rst_proc
                CMP     #<dialog_monitor
                BNE     do_soft_boot
                LDA     #>dialog_monitor
                CMP     rst_proc+1
                BNE     do_soft_boot
init_rst_proc:  LDY     #<dialog_monitor
                STY     rst_proc
                JMP     dialog_monitor

do_soft_boot:   JMP     (rst_proc)

do_cold_boot:   BIT     mem_selector_c0f1
                LDY     #0
                STY     video_page_next_h ; h byte of next page address
                LDA     #initial_video_page
                LDX     #video_mode_text ; text mode 32x32
                JSR     set_video_mode  ; A = page, X = mode (2 = text)
                JSR     clear_scr

                LDY     #title_num_bytes
title_loop:     LDA     title_text-1, Y
                STA     title_video_addr-1, Y
                DEY
                BNE     title_loop
                BIT     mem_selector_c0f0

                LDX     #num_vars_3Fx
init_vars_loop: LDA     init_vars-1, X
                STA     brk_addr-1, X
                DEX
                BNE     init_vars_loop  ; on exit loop X = 0

                LDA     #$C7            ; last slot + 1
                STX     autostart_addr
                STA     autostart_addr+1
autostart_loop: LDY     #7              ; autostart signature size
                DEC     autostart_addr+1
                LDA     autostart_addr+1
                CMP     #$C0            ; first slot + 1
                BEQ     init_rst_proc
                STA     some_autostart_addr
sig_check_loop: LDA     (autostart_addr), Y
                CMP     autostart_sig-1, Y
                BNE     autostart_loop  ; autostart signature size
                DEY
                DEY
                BPL     sig_check_loop
                JMP     (autostart_addr)

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:      LDA     #CHAR_SPACE
                JSR     print_char
                LDA     reg_names-$FB, X
                JSR     print_char
                LDA     #CHAR_EQ        ; =
                JSR     print_char
                LDA     user_a+5, X
                JSR     print_hex_byte
                INX
                BMI     print_reg
                RTS

init_vars:      .dw brk_proc
                .dw dialog_monitor
                .db cold_boot_code
autostart_sig:  .db $20, $FF, $00, $FF, $03, $FF, $3C
title_text:     .db CHAR_ASTERISK       ; *
                .db attr_title_green
                .db CHAR_ASTERISK       ; *
                .db attr_title_green
                .db CHAR_SPACE
                .db attr_title_white
                .db CHAR_CYR_A          ; А
                .db attr_title_red
                .db CHAR_CYR_G          ; Г
                .db attr_title_red
                .db CHAR_CYR_A          ; А
                .db attr_title_red
                .db CHAR_CYR_T          ; Т
                .db attr_title_red
                .db CHAR_SPACE
                .db attr_title_white
                .db CHAR_ASTERISK       ; *
                .db attr_title_green
                .db CHAR_ASTERISK       ; *
                .db attr_title_green
reg_names:      .db CHAR_A, CHAR_X, CHAR_Y, CHAR_P, CHAR_S


pdl_input_proc: ; unused
                LDA     pdl_reset_port
                LDY     #0
                NOP
                NOP
pdl_input_loop: LDA     pdl_input_port,X
                BPL     pdl_input_end
                NOP
                NOP
                NOP
                INY
                BNE     pdl_input_loop
                DEY
pdl_input_end:  RTS

                .db $10
                .db $08

select_text_mode:
                LDA     video_page_h
                LSR
                BCC     low_mode
                ADC     #$1F            ; add 20h to mode
low_mode:       ADC     #video_mode_text ; text mode 32x32
                TAY
                STA     video_selector,Y
                RTS

reset_scr_wnd:  LDA     #0
                STA     user_p
                STA     wnd_top
                LDA     #0
                STA     wnd_left_2
                LDA     #64
                STA     wnd_right_2
                LDA     #32
                STA     wnd_bottom
                LDA     #31
                STA     cur_pos_y
                JMP     calc_cur_pos_addr

is_esc_ctl:     JSR     check_print_space
handle_esc_chars:
                JSR     input_char
                CMP     #RIGHT_KEY      ; RIGHT
                BEQ     is_esc_ctl
                CMP     #LEFT_KEY       ; LEFT
                BEQ     is_esc_ctl
leave_edit_mode:
                JSR     check_print_space


handle_edit_mode:
                JSR     input_char
                CMP     #ESC_KEY        ; ESC
                BEQ     handle_esc_chars
                CMP     #UP_KEY         ; UP
                BEQ     leave_edit_mode
                CMP     #DOWN_KEY       ; DOWN
                BEQ     leave_edit_mode
is_invisible_char:
                RTS


check_print_space:
                CMP     #SPACE_KEY      ; SPACE
                BCS     is_invisible_char
                JMP     print_char

; A = cursor Y, not uses window
calc_scr_addr:  STA     cur_scr_addr+1
                LDA     #0
                STA     cur_scr_addr
                LSR     cur_scr_addr+1
                ROR     cur_scr_addr
                LSR     cur_scr_addr+1
                ROR     cur_scr_addr
                LDA     video_page_h
                AND     #$F8
                ADC     cur_scr_addr+1
                STA     cur_scr_addr+1
                RTS

some_delay:     SEC                     ; A = delay value
outer_loop:     PHA
inner_loop:     SBC     #1
                BNE     inner_loop
                PLA
                SBC     #1
                BNE     outer_loop
                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

ctl_char_table: .db ENTER_KEY, CTRL_J_KEY, LEFT_KEY, RIGHT_KEY, UP_KEY
                .db DOWN_KEY, CTRL_L_KEY, RIGHT_7_KEY, RIGHT_8_KEY, CTRL_G_KEY
                .db RIGHT_6_KEY
ctl_addr_l:     .db <eol_ctl_proc
                .db <eol_ctl_proc
                .db <left_key_proc
                .db <right_key_proc
                .db <up_key_proc
                .db <down_key_proc
                .db <clear_scr
                .db <clr_eol_proc
                .db <clr_eos_proc
                .db <beep_proc
                .db <caps_lock_proc

process_char_output:
                CMP     #CHAR_EOL
                BNE     not_eol
                LDY     input_kbd
                BPL     not_eol         ; nothing pressed
                BIT     reset_kbd
                CPY     #CHAR_SPACE     ; space char pressed, stop output
                BNE     not_eol
scroll_lock_loop:
                LDY     input_kbd
                BPL     scroll_lock_loop
                CPY     #CTRL_C_KEY
                BEQ     not_eol         ; do not clear Ctrl+C
                BIT     reset_kbd
not_eol:        CMP     #SPACE_KEY
                BCS     char_is_visible
                TAY
                BPL     char_is_visible
                LDY     #num_ctl
ctl_char_loop:  CMP     ctl_char_table,Y
                BEQ     ctl_char_found
                DEY
                BPL     ctl_char_loop
                RTS


ctl_char_found: LDA     ctl_addr_l,Y
                STA     tmp_addr
                LDA     #>left_key_proc
                STA     tmp_addr+1
                JMP     (tmp_addr)

char_is_visible:
                LDY     cur_pos_x
                STA     (cur_scr_addr),Y
                INY
                LDA     cur_attr
                STA     (cur_scr_addr),Y

right_key_proc: INC     cur_pos_x
                INC     cur_pos_x
                LDA     cur_pos_x
                CMP     wnd_right_2
                BCS     eol_ctl_proc
not_jump_right: RTS

left_key_proc:  DEC     cur_pos_x
                DEC     cur_pos_x
                BPL     not_jump_right
                LDA     wnd_right_2
                STA     cur_pos_x
                DEC     cur_pos_x
                DEC     cur_pos_x
up_key_proc:    LDA     wnd_top
                CMP     cur_pos_y
                BCS     not_on_top
                DEC     cur_pos_y

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
not_on_top:     RTS


clear_scr:      LDA     wnd_top
                STA     cur_pos_y
                LDY     #0
                STY     cur_pos_x
                BEQ     do_clear

clr_eos_proc:   LDY     cur_pos_x
                LDA     cur_pos_y
do_clear:       PHA
                JSR     upd_scr_addr    ; A = cursor Y, uses window
                JSR     clear_scr_block
                LDY     #0
                PLA
                ADC     #0
                CMP     wnd_bottom
                BCC     do_clear
                BCS     calc_cur_pos_addr
eol_ctl_proc:   LDA     #0
                STA     cur_pos_x

down_key_proc:  INC     cur_pos_y
                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_addr
                LDA     cur_scr_addr+1
                STA     tmp_addr+1
                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_addr),Y
                DEY
                BPL     scroll_loop
                BMI     retry_scroll
clear_last_line:
                LDY     #0
                JSR     clear_scr_block
                JMP     calc_cur_pos_addr


clr_eol_proc:
                LDY     cur_pos_x
clear_scr_block:
                LDA     #CHAR_SPACE
                STA     (cur_scr_addr),Y
                INY
                LDA     cur_attr
                STA     (cur_scr_addr),Y
                INY
                CPY     wnd_right_2
                BCC     clear_scr_block
                RTS

caps_lock_proc: LDA     cur_attr
                EOR     #$80            ; toggle top bit of attribs
                STA     cur_attr
                RTS

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

; X = preamble duration
write_preamble:
                LDY     #tape_delay_preamble
                JSR     tape_bit_out    ; Y=retries, CF=output => X = X - 1, Y = delay0
                BNE     write_preamble  ; X = preamble duration
                ADC     #<-2
                BCS     write_preamble  ; X = preamble duration
                LDY     #33


; Y=delay, CF=bit, X = X - 2
tape_output_bit:
                JSR     tape_bit_out    ; Y=retries, CF=output => X = X - 1, Y = delay0
                INY
                INY
tape_bit_out:   DEY                     ; Y=retries, CF=output => X = X - 1, Y = delay0
                BNE     tape_bit_out    ; Y=retries, CF=output => X = X - 1, Y = delay0
                BCC     tape_output_0
                LDY     #tape_delay_1   ; delay for 1
secod_delay_loop:
                DEY
                BNE     secod_delay_loop
tape_output_0:  LDY     tape_out
                LDY     #tape_delay_0   ; delay for 0
                DEX
                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
                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
                RTS


input_char:     JMP     (input_char_ptr)

input_char_proc:
                LDA     video_page_h
                JSR     set_mem_bank    ; A = video page address high byte
                LDY     cur_pos_x
                LDA     (cur_scr_addr),Y
                STA     tmp_35          ; old Y for print_char, current char for input
                INY
                LDA     (cur_scr_addr),Y
                PHA
                LDA     #flash_cursor_attr
                STA     (cur_scr_addr),Y
                PLA
input_loop:     INC     rnd_counter_l
                BNE     no_inc_rnd_h
                INC     rnd_counter_h
no_inc_rnd_h:   BIT     input_kbd
                BPL     input_loop
                STA     (cur_scr_addr),Y
                LDA     video_page_next_h ; h byte of next page address
                JSR     set_mem_bank    ; A = video page address high byte
                LDA     input_kbd
                ORA     #$80
                BIT     reset_kbd
                LDY     cur_pos_x
                RTS

print_current_char:
                JSR     print_char
                CMP     #LEFT_KEY       ; LEFT
                BEQ     do_left_key
                CMP     #CTRL_X_KEY     ; CTRL+X
                BEQ     on_overflow
                CPX     #line_warn_start ; number of chars to warn
                BCC     not_overflow
                JSR     do_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       ; is buffer empty?
                DEX                     ; decrease buffer index
no_input_overflow:
                JSR     handle_edit_mode
                CMP     #RIGHT_KEY      ; RIGHT
                BNE     not_right       ; store char from screen
                LDA     tmp_35          ; old Y for print_char, current char for input
not_right:      STA     input_buf,X     ; store char from screen
                CMP     #ENTER_KEY      ; ENTER
                BNE     print_current_char
                LDA     #RIGHT_7_KEY
                JSR     print_char

print_eol:      LDA     #ENTER_KEY
                BNE     print_char

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
                LDA     #CHAR_MINUS     ; -
                JMP     print_char

dump_next_bytes:
                LDA     src_user_ptr
                ORA     #7
                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:   LDA     #SPACE_KEY
                JSR     print_char
                LDA     (src_user_ptr),Y
                JSR     print_hex_byte
                JSR     inc_user_ptr
                BCC     mem_print_loop
                RTS


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
                LDA     #CHAR_EQ        ; =
                JSR     print_char
                PLA

print_hex_byte:
                PHA
                LSR
                LSR
                LSR
                LSR
                JSR     print_hex_digit
                PLA
                AND     #$0F            ; lower 4 bits
print_hex_digit:
                ORA     #CHAR_0         ; 0
                CMP     #CHAR_9+1
                BCC     print_char
                ADC     #CHAR_A - CHAR_0 - $0A - 1

print_char:     JMP     (print_char_ptr)

print_char_proc:
                STY     store_y         ; old Y for print_char
                PHA
                LDA     video_page_h
                JSR     set_mem_bank    ; A = video page address high byte
                PLA
                PHA
                CMP     #SPACE_KEY
                BCC     skip_caps
                BIT     cur_attr
                BMI     skip_caps
                AND     #$7F            ; clear higher bit
skip_caps:      JSR     process_char_output
                LDA     video_page_next_h ; h byte of next page address
                JSR     set_mem_bank    ; A = video page address high byte
                PLA
                LDY     store_y         ; old Y for print_char
                RTS

; 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

process_empty_cmd:
                DEC     prompt_index
                BEQ     dump_next_bytes
space_cmd:      DEX
                BNE     not_empty_line
                CMP     #CHAR_COLON     ; :
                BNE     do_add_sub
                STA     current_op
                LDA     dst_user_ptr
                STA     (current_ptr),Y
                INC     current_ptr
                BNE     no_current_ptr_h_inc
                INC     current_ptr+1
no_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
                LDA     #SPACE_KEY
                JSR     print_char
                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

inverse_cmd:    LDY     #inverse_attr
                BNE     cont_attr

norm_cmd:       LDY     #normal_attr
cont_attr:      STY     cur_attr
                RTS

default_input:  LDA     #0
                STA     dst_user_ptr

cmd_ctrl_I:     LDX     #input_char_ptr ; redirect input to slot
                LDY     #<input_char_proc
                BNE     set_io_proc

default_output: LDA     #0
                STA     dst_user_ptr

cmd_ctrl_O:     LDX     #print_char_ptr ; redirect output to slot
                LDY     #<print_char_proc
set_io_proc:    LDA     dst_user_ptr
                AND     #$0F
                BEQ     reset_io_proc
                ORA     #$C0
                LDY     #0
                BEQ     store_io_proc
reset_io_proc:  LDA     #>print_char_proc
store_io_proc:  STY     0,X
                STA     1,X
                RTS

init_basic:     JMP     basic_init
call_basic:     JMP     basic_start

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

jump_ctrl_y:    JMP     ctrl_Y_addr

cmd_text_page:  LDA     dst_user_ptr
                AND     #$1F            ; 32 text pages allowed?
                LDX     #video_mode_text ; text mode 32x32
                JMP     set_video_mode  ; A = page, X = mode (2 = text)

cmd_set_color:  LDA     dst_user_ptr
                EOR     cur_attr
                AND     #7
                EOR     cur_attr
                STA     cur_attr
                RTS

cmd_write:      LDA     #tape_preamble_duration
                JSR     write_preamble  ; X = preamble duration
                LDY     #39

tape_write_loop:
                LDX     #0
                EOR     (src_user_ptr,X)
                PHA
                LDA     (src_user_ptr,X)
                JSR     tape_output_byte ; A=byte, Y=initial delay
                JSR     inc_user_ptr
                LDY     #29
                PLA
                BCC     tape_write_loop
                LDY     #34
                JSR     tape_output_byte ; write checksum
                BEQ     do_beep

tape_output_byte:  ; A=byte, Y=initial delay
                LDX     #2*8            ; double byte size
tape_output_loop:
                ASL
                JSR     tape_output_bit ; Y=delay, CF=bit, X = X - 2
                BNE     tape_output_loop
                RTS

no_cmd:         JSR     process_empty_cmd
                PLA
                PLA
                BNE     dialog_monitor


cmd_read:       JSR     input_tape_pulses
                LDA     #22
                JSR     write_preamble  ; X = preamble duration
                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
                BEQ     do_beep         ; GOOD
                LDA     #CHAR_E         ; E
                JSR     print_char
                LDA     #CHAR_R         ; R
                JSR     print_char
                JSR     print_char

do_beep:        LDA     #CTRL_G_KEY
                JMP     print_char


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
; => X = 0
print_2_spaces: LDX     #2
print_x_spaces: LDA     #SPACE_KEY
print_x_chars:  JSR     print_char
                DEX
                BNE     print_x_chars
                RTS

dialog_beep:    CLD
                JSR     do_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

; => X = 1 for number, 0 for command
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

call_cmd_proc:  LDA     #>cmd_regs
                PHA
                LDA     cmd_low_bytes,Y
                PHA
                LDA     current_op

clear_cur_op:   LDY     #0
                STY     current_op
                RTS

; ---------------------------------------------------------------------------
cmd_char_codes: .db $BC, $B2, $BE, $EF, $E9, $08, $C2, $C8, $BB                ; BC="=", B2=UP, BE=F2, EF=V, E9=P, 08=O, C2=Ctrl+I, C8=Ctrl+O, BB="."
                .db $A6, $A4, $06, $95, $07, $02, $05, $F0, $00, $EB, $93, $A7 ; A6=-, A4=+, 6=M, 95=<, 7=N, 2=I, 5=L, F0=W, 0=G, EB=R, 93=colon, A7=.
                .db $C6, $99                                                   ; C6=ENTER, 99=SPACE
cmd_low_bytes:  .db <(call_basic-1)
                .db <(jump_ctrl_y-1)
                .db <(cmd_regs-1)
                .db <(verify_cmd-1)
                .db <(cmd_text_page-1)
                .db <(cmd_set_color-1)
                .db <(cmd_ctrl_I-1)
                .db <(cmd_ctrl_O-1)
                .db <(init_basic-1)
                .db <(set_current_op-1)
                .db <(set_current_op-1)
                .db <(move_cmd-1)
                .db <(less_op-1)
                .db <(norm_cmd-1)
                .db <(inverse_cmd-1)
                .db <(list_cmd-1)
                .db <(cmd_write-1)
                .db <(call_user_proc-1)
                .db <(cmd_read-1)
                .db <(set_current_op-1)
                .db <(set_current_op-1)
                .db <(no_cmd-1)
                .db <(space_cmd-1)
vec_NMI:        .dw nmi_proc
vec_RST:        .dw start_rst
vec_IRQ:        .dw start_irq
                            

Перейти к проекту

Дополнительные материалы

Файлы ПЗУ системного монитора: перейти.

Файл листинга: посмотреть.

В начало

Вернуться на основную страницу

К прочим материалам

Прочие материалы

Реплики Агат-7

Посмотреть реплики узлов 7-й версии ПЭВМ Агат

Реплики Агат-9

Посмотреть реплики узлов 9-й версии ПЭВМ Агат