OK240.2-Firmware/MON_r6_291f2b76/monitor.asm
2026-02-19 19:21:24 +03:00

4936 lines
102 KiB
NASM

; ======================================================
; Ocean-240.2
; Monitor r7
; crc32: 93bd95db
;
; Disassembled by Romych 2026-02-16
; ======================================================
DEVICE NOSLOT64K
INCLUDE "io.inc"
INCLUDE "equates.inc"
INCLUDE "ram.inc"
INCLUDE "bios_entries.inc"
OUTPUT mon_E000.bin
MODULE MONITOR
ORG 0xe000
; ------------------------------------------------------
; Monitor Entry points
; ------------------------------------------------------
mon_start: JP m_start ; E000
mon_cold_start: JP m_cold_start ; E003
mon_con_status: JP m_con_status ; E006
mon_con_in: JP m_con_in ; E009
mon_con_out: JP m_con_out ; E00C
mon_serial_in: JP m_serial_in ; E00F
mon_serial_out: JP m_serial_out ; E012
mon_char_print: JP m_char_print ; E015
mon_tape_read: JP m_tape_read ; E018
mon_tape_write: JP m_tape_write ; E01B
mon_ram_disk_read: JP m_ramdisk_read ; E01E
mon_ram_disk_write: JP m_ramdisk_write ; E021
mon_tape_read_ram: JP m_tape_read_ram ; E024
mon_tape_write_ram: JP m_tape_write_ram ; E027
mon_tape_wait: JP m_tape_wait ; E02A
mon_tape_detect: JP m_tape_blk_detect ; E02D
mon_read_floppy: JP m_read_floppy ; E030
mon_write_floppy: JP m_write_floppy ; E033
; ------------------------------------------------------
; Init system devices
; ------------------------------------------------------
m_start:
DI
LD A, 10000000b ; DD17 all ports to out
OUT (SYS_DD17CTR), A ; VV55 Sys CTR
OUT (DD67CTR), A ; VV55 Video CTR
; init_kbd_tape
LD A, 010010011b
OUT (KBD_DD78CTR), A
LD A, 01111111b ; VSU=0, C/M=1, FL=111, COL=111
OUT (VID_DD67PB), A ; color mode
LD A, 00000001b
OUT (SYS_DD17PB), A ; Access to VRAM
LD B, 0x0 ; TODO: replace to LD HL, 0x3f00 LD B,L
LD HL, 0x3f00
LD A, H
ADD A, 0x41 ; A=128 0x80
; Clear memory from 0x3F00 to 0x7FFF
.fill_video:
LD (HL), B
INC HL
CP H
JP NZ, .fill_video
;XOR A
LD A, 0
OUT (SYS_DD17PB), A ; Disable VRAM
LD A, 00000111b
OUT (SYS_DD17PC), A ; pix shift to 7
LD (M_VARS.pix_shift), A
XOR A
LD (M_VARS.screen_mode), A
LD (M_VARS.row_shift), A
; Set color mode and palette
LD (M_VARS.curr_color+1), A
CPL
LD (M_VARS.curr_color), A
LD A, 00000011b
LD (M_VARS.cur_palette), A
; VSU=0, C/M=1, FL=000, COL=011
; color mode, black border
; 00-black, 01-red, 10-purple, 11-white
LD A, 01000011b
OUT (VID_DD67PB), A
; config LPT
LD A, 0x4
OUT (DD67PC), A ; bell=1, strobe=0
LD (M_VARS.strobe_state), A ; store strobe
LD HL, 1024 ; 683us
LD (M_VARS.beep_period), HL
LD HL, 320 ; 213us
LD (M_VARS.beep_duration), HL
conf_uart:
; Config UART
LD A, 11001110b
OUT (UART_DD72RR), A
LD A, 00100101b
OUT (UART_DD72RR), A
; Config Timer#1 for UART clock
LD A, 01110110b ; tmr#1, load l+m bin, sq wave
OUT (TMR_DD70CTR), A
; 1.5M/20 = 75kHz
LD A, 20
OUT (TMR_DD70C2), A
XOR A
OUT (TMR_DD70C2), A
conf_pic:
; Config PIC
LD A,00010010b ; ICW1 edge trigger, interval 8, sin...
OUT (PIC_DD75RS), A
XOR A
OUT (PIC_DD75RM), A ; ICW2
CPL
OUT (PIC_DD75RM), A ; ICW3 no slave
LD A,00100000b
OUT (PIC_DD75RS), A ; Non-specific EOI command, End of I...
LD A, PIC_POLL_MODE
OUT (PIC_DD75RS), A ; Poll mode, poll on next RD
; Config KBD
LD A, 0x80
OUT (KBD_DD78PC), A ; TODO: - Check using this 7th bit
NOP
NOP
XOR A
OUT (KBD_DD78PC), A
; Init cursor
LD SP, M_VARS.stor_de
CALL m_draw_cursor
; Init BIOS entry
LD HL, M_VARS.stor_sp
LD (M_VARS.stack_0), HL
LD A, JP_OPCODE
LD (RST1), A
LD HL, m_rst1_handler
LD (RST1_handler_addr), HL
; Beep
LD C, ASCII_BELL
CALL m_con_out
jump_bios:
; If CP/M BIOS exists, jump to it
LD A, (BIOS.boot_f)
CP JP_OPCODE
JP Z, BIOS.boot_f
; No CP/M, Go to monitor
LD HL, msg_hw_mon
CALL m_out_strz
JP m_cold_start
; --------------------------------------------------
; Output ASCIIZ string
; Inp: HL -> string
; --------------------------------------------------
m_out_strz:
LD C, (HL)
LD A, C
OR A
RET Z
CALL m_con_out
INC HL
JP m_out_strz
msg_hw_mon:
DB "\r\n240/7 MONITOR\r\n", 0
; ---------------------------------------------------
reset_m_stack:
LD HL, M_VARS.stor_e
LD SP, HL
CALL get_cmd_letter
INC HL
; ---------------------------------------------------
; Monitor entry point
; ---------------------------------------------------
m_cold_start:
LD HL, M_VARS.stor_e
LD SP, HL
DI
CALL get_a_ref_sp
CALL get_cmd_letter
LD L, 205
DB 0xdd
PUSH AF
CP ASCII_CR
JP Z, m_cold_start
LD HL, cmd_handlers
LD C, 11
seek_cmd:
CP (HL)
JP Z, cmd_found
INC HL
INC HL
INC HL
DEC C
JP NZ, seek_cmd
JP reset_m_stack
cmd_found:
INC HL
; get cmd handler address
LD A, (HL)
INC HL
LD H, (HL)
LD L, A
; RET to cold_start
LD DE, m_cold_start
PUSH DE
; Jump to cmd handler
LD C, 2
JP (HL)
; ---------------------------------------------------
; Monitor commands handlers table
; ---------------------------------------------------
cmd_handlers:
DB 'D'
DW cmd_D
DB 'F'
DW cmd_F
DB 'G'
DW cmd_G
DB 'L'
DW cmd_L
DB 'M'
DW cmd_M
DB 'R'
DW cmd_R
DB 'S'
DW cmd_S
DB 'W'
DW cmd_W
DB 'X'
DW cmd_X
DB 'B'
DW cmd_B
DB 'A'
DW cmd_A
; ---------------------------------------------------
; B[n] - Move block n from RAM2 to RAM1
; ---------------------------------------------------
cmd_B
DEC C
CALL get_address
POP DE
LD HL, tpa_start
CALL m_ramdisk_read
RET
; ---------------------------------------------------
; A[n] - Move block n from RAM1 to RAM2
; ---------------------------------------------------
cmd_A:
DEC C
CALL get_address
POP DE
LD HL, 256
CALL m_ramdisk_write
RET
; ---------------------------------------------------
; D[addr] Dump 128 bytes
; ---------------------------------------------------
cmd_D:
DEC C
CALL get_address
POP HL
LD DE, 127
EX DE, HL
ADD HL, DE
EX DE, HL
d_next_line:
CALL get_a_ref_sp
CALL out_sp_key
CALL out_hex_word
d_next_byte:
CALL out_sp_key
LD A, (HL)
CALL out_hex_byte
CALL next_hl_de
RET C
LD A, L
AND 0x7
JP NZ, d_next_byte
JP d_next_line
; ---------------------------------------------------
; F[addr1][addr2]val Fill RAM ares
; ---------------------------------------------------
cmd_F:
INC C
CALL get_address
POP BC
POP DE
POP HL
f_next_b:
LD (HL), C
CALL next_hl_de
JP NC, f_next_b
RET
; ---------------------------------------------------
; M[addr1][addr2][addr3] - Move mem blk ad
; ---------------------------------------------------
cmd_M:
INC C
CALL get_address
POP BC
POP DE
POP HL
m_next_b:
LD A, (HL)
LD (BC), A
INC BC
CALL next_hl_de
JP NC, m_next_b
RET
; ---------------------------------------------------
; L - Load Intel HEX from serial interface
; ---------------------------------------------------
cmd_L:
CALL get_key_with_check
JP NC, reset_m_stack
CALL get_a_ref_sp
; wait for hex line start
l_wait_colon:
CALL m_serial_in
CP ':'
JP NZ, l_wait_colon
XOR A
LD D,A
CALL read_hex_serial
JP Z, l_exit
; read line len and addr
LD E, A
CALL read_hex_serial
LD H, A
CALL read_hex_serial
LD L, A
CALL read_hex_serial
LD C, E
l_next_byte:
CALL read_hex_serial
LD (HL), A
INC HL
DEC E
JP NZ, l_next_byte
CALL read_hex_serial
JP NZ, reset_m_stack
JP l_wait_colon
; read and ignore final 4 hex bytes in las
l_exit:
CALL read_hex_serial
CALL read_hex_serial
CALL read_hex_serial
CALL read_hex_serial
JP NZ, reset_m_stack
RET
; ---------------------------------------------------
; S[addr] Out and modify ram byte
; ---------------------------------------------------
cmd_S:
CALL s_get_hex_addr
RET C
s_next_byte:
LD A, (HL)
CALL out_hex_byte
CALL get_cmd_letter
DEC L
; get new value
CALL get_key_with_check
RET C
JP Z, s_next_in
EX DE, HL
CALL hex_keys_to_addr
EX DE, HL
LD (HL), E
RET C
s_next_in:
INC HL
JP s_next_byte
; ---------------------------------------------------
; X[r] - Out and modify register value
; ---------------------------------------------------
cmd_X:
LD HL, registers_tab
CALL get_key_with_check
JP C, x_ret
LD C, 9
x_seek_reg:
CP (HL)
JP Z, x_reg_found
INC HL
INC HL
INC HL
DEC C
JP NZ, x_seek_reg
JP reset_m_stack
x_reg_found:
CALL out_sp_key
CALL out_reg_value
CALL get_cmd_letter
DEC L
CALL get_key_with_check
RET C
JP Z, reset_m_stack
PUSH BC
; get new reg value and store
CALL hex_keys_to_addr
LD A, L
LD (DE), A
POP AF
OR A
JP M, x_wreg
INC DE
LD A,H
LD (DE), A
x_wreg:
CALL get_a_ref_sp
RET
x_ret:
CALL get_a_ref_sp
x_next_reg:
XOR A
OR (HL)
RET M
CP 'M'
CALL Z, get_a_ref_sp
CALL out_sp_key
LD C, (HL)
CALL get_key_out
CALL get_cmd_letter
DEC A
CALL out_reg_value
JP x_next_reg
; ---------------------------------------------------
registers_tab:
DB 'A', LOW(M_VARS.stor_a), 0
DB 'B', LOW(M_VARS.stor_b), 0
DB 'C', LOW(M_VARS.stor_c), 0
DB 'D', LOW(M_VARS.stor_d), 0
DB 'E', LOW(M_VARS.stor_e), 0
DB 'F', LOW(M_VARS.stor_f), 0
DB 'M', LOW(M_VARS.stor_m), 1
DB 'P', LOW(M_VARS.stor_p), 1
DB 'S', LOW(M_VARS.stor_s), 1
DB 0xff
; ------------------------------------------------------
; Console status
; Out: A = 0 - not ready
; A = 0xFF - ready (key pressed)
; ------------------------------------------------------
m_con_status:
IN A, (PIC_DD75RS) ; Read PIC status
NOP
AND KBD_IRQ ; Check keyboard request RST1
LD A, 0
RET Z ; no key pressed
CPL
RET ; key pressed
; ------------------------------------------------------
; Wait and read data from UART
; Out: A - 7 bit data
; ------------------------------------------------------
m_serial_in:
IN A, (UART_DD72RR)
AND RX_READY
JP Z, m_serial_in ; wait for rx data ready
IN A, (UART_DD72RD)
AND 0x7f ; leave 7 bits
RET
; ------------------------------------------------------
; Read key
; Out: A
; ------------------------------------------------------
m_con_in:
CALL m_con_status
OR A
JP Z, m_con_in ; wait key
IN A, (KBD_DD78PA) ; get key
AND 0x7f ; reset hi bit, leave 0..127 code
PUSH AF
; TODO: Check if it is keyboard ACK
; PC7 Set Hi (ACK?)
LD A, 0x80
OUT (KBD_DD78PC), A
; PC7 Set Lo
XOR A
OUT (KBD_DD78PC), A
POP AF
RET
; ------------------------------------------------------
; Send data by UART
; Inp: C - data to transmitt
; ------------------------------------------------------
m_serial_out:
IN A, (UART_DD72RR)
AND TX_READY
JP Z, m_serial_out ; Wait for TX ready
LD A, C
OUT (UART_DD72RD), A
RET
; ------------------------------------------------------
;
; ------------------------------------------------------
read_key_if_pressed:
CALL m_con_status
OR A
RET Z ; ret if no key pressed
JP handle_key_pressed
; ------------------------------------------------------
;
; ------------------------------------------------------
get_a_ref_sp:
CALL get_cmd_letter
DEC C
CALL get_cmd_letter
LD A, (BC)
RET
; ------------------------------------------------------
;
; ------------------------------------------------------
get_cmd_letter:
EX (SP), HL
LD C, (HL)
INC HL
EX (SP), HL
JP get_key_out
; ------------------------------------------------------
; Send character to printer
; Inp: C - character
; ------------------------------------------------------
m_char_print:
; wait printer ready
IN A, (PIC_DD75RS)
AND PRINTER_IRQ
JP Z, m_char_print
LD A, C
;NOP
OUT (LPT_DD67PA), A
; set LP strobe
LD A, 00010100b
OUT (DD67PC),A
.wait_lp:
; wait printer ack
IN A, (PIC_DD75RS)
AND PRINTER_IRQ
JP NZ, .wait_lp
; remove LP strobe
LD A, 00000100b
OUT (DD67PC), A
RET
; ------------------------------------------------------
;
; ------------------------------------------------------
out_sp_key:
LD C, ASCII_SP
; ------------------------------------------------------
;
; ------------------------------------------------------
get_key_out:
CALL read_key_if_pressed
; ------------------------------------------------------
; Out char to console
; Inp: C - char
; ------------------------------------------------------
m_con_out:
PUSH HL
PUSH DE
PUSH BC
CALL m_con_out_int
POP BC
POP DE
POP HL
RET
; ------------------------------------------------------
; Out char C to console
; ------------------------------------------------------
m_con_out_int:
LD DE, M_VARS.esc_mode
LD A, (DE)
DEC A
OR A ; TODO: unused (save 1b 4t)
JP M, m_print_no_esc ; esc_mode=0 - standart print no ESC mode
JP NZ, m_print_at_xy ; esc_mode=2 (graphics)
; handle ESC param (esc_mode=1)
INC DE ; TODO: replace to INC E E=0xd3 save 2t
LD A, (DE)
OR A
JP P, get_esc_param
LD A, C
AND 0xf ; convert char to command code
LD (DE), A
INC DE ; TODO: replace to INC E E=0xd3 save 2t
XOR A
LD (DE), A
RET
get_esc_param:
LD HL, M_VARS.esc_cmd
LD B, (HL)
INC HL
LD A, (HL)
INC A
LD (HL), A
LD E, A
LD D, 0x0
ADD HL, DE
LD (HL), C
LD HL, esc_params_tab
LD E, B
ADD HL, DE
CP (HL)
RET M
; -----------------
LD A, (M_VARS.esc_cmd)
AND 0xf
CP 0xf
JP Z, .l1
CP 0xb
LD C, 0x5
JP Z, .l2
CP 0x4
JP P, .l6
.l1:
LD C, 0x4
.l2:
LD HL, M_VARS.esc_param
LD D, H
LD E, L
.l3:
LD A, (HL)
CP ':'
JP M, .l4
SUB 0x7
.l4:
AND 0xf
ADD A, A
ADD A, A
ADD A, A
ADD A, A
LD B, A
INC HL
LD A, (HL)
CP ':'
JP M, .l5
SUB 0x7
.l5:
AND 0xf
OR B
INC HL
LD (DE), A
INC DE
DEC C
JP NZ, .l3
.l6:
LD HL, M_VARS.esc_cmd
LD A, (HL)
AND 0xf
LD E, A
DEC HL
OR A
LD (HL), 0x2
RET Z
LD D, 0x0
LD (HL), D
DEC DE
LD HL, esc_handler_tab
ADD HL, DE
ADD HL, DE
LD E, (HL)
INC HL
LD D, (HL)
EX DE, HL
CP 0x4
JP P, .no_draw_fn
LD A, (M_VARS.screen_mode)
AND 0x7
JP NZ, esc_exit
.no_draw_fn:
LD DE, esc_exit
PUSH DE
JP (HL)
esc_exit:
XOR A
LD (M_VARS.esc_mode), A
RET
; --------------------------------------------------
; Count of parameters for ESC commands
; --------------------------------------------------
esc_params_tab:
DB 4, 8, 8, 4, 1, 2, 1, 1
DB 1, 1, 1, 10, 1, 1, 1, 8
esc_handler_tab:
DW esc_draw_fill_rect ;8 <ESC>1x1y1x2y2m
DW esc_draw_line ;8 <ESC>2x1y1x2y2
DW esc_draw_dot ;4 <ESC>3xxyy
DW esc_set_color ;1 <ESC>4N N=1..4
DW esc_set_cursor ;2 <ESC>5rc r-Row, c-Col
DW esc_set_vmode ;1 <ESC>6m m-mode:
; C 0 - 40x25 cursor on
; M 1,2 - 64x25 cursor on
; M 3 - 80x25 cursor on
; C 4 - 40x25 cursor off
; M 5,6 - 64x25 cursor off
; M 7 - 80x25 cursor off
; M 8 - 20rows mode
; 9 - cursor off
; 10 - cursor on
DW esc_set_charset ;1 <ESC>7n where n is:
; 0 - LAT Both cases
; 1 - RUS Both cases
; 2 - LAT+RUS Upper case
DW esc_set_palette ;1 <ESC>8c c - Foreground+Backgound
DW esc_set_cursor2 ;1 <ESC>9xy
DW esc_print_screen ;1 <ESC>:
DW esc_draw_circle ;10 <ESC>;xyraxay X,Y, Radius, aspect ratio X, aspect ratio Y
DW esc_unimpl ;1 <ESC><
DW esc_unimpl ;1 <ESC>=
DW esc_unimpl ;1 <ESC>>
DW esc_set_beep ;8 <ESC>?ppdd pp-period (word), dd - duration (word)
; --------------------------------------------------
;
; --------------------------------------------------
esc_unimpl:
RET
; --------------------------------------------------
;
; --------------------------------------------------
esc_set_beep:
; param byte 1+2 -> period
LD DE, M_VARS.esc_param
LD A, (DE)
LD H, A
INC DE
LD A, (DE)
LD L, A
LD (M_VARS.beep_period), HL
; param byte 3+4 -> duration
INC DE
LD A, (DE)
LD H, A
INC DE
LD A, (DE)
LD L, A
LD (M_VARS.beep_duration), HL
RET
; --------------------------------------------------
;
; --------------------------------------------------
esc_set_cursor2:
POP DE
XOR A
LD (M_VARS.esc_mode), A
LD A, (M_VARS.screen_mode)
RET
; --------------------------------------------------
;
; --------------------------------------------------
esc_print_screen:
LD A, (M_VARS.screen_mode)
AND 00000111b
RET NZ ; ret if not 0-3 mode
LD DE, 0x30ff
CALL m_print_hor_line
DEC E
LD D, 0xf0
.chk_keys:
CALL m_con_status
OR A
JP Z, .no_keys
CALL m_con_in
CP ASCII_ESC
RET Z
.no_keys:
CALL m_print_hor_line
DEC E
JP NZ, .chk_keys
LD D, 0xe0 ; 224d
CALL m_print_hor_line
RET
; ------------------------------------------------------
; Print line to printer
; D - width
; ------------------------------------------------------
m_print_hor_line:
LD HL, cmd_esc_set_X0
; Set printer X coordinate = 0
CALL m_print_cmd
LD HL, 4
LD (M_VARS.ul_var0), HL ; Set start coord X = 4
LD B, 0x0 ; TODO: LD B, H (save 1b 3t)
.print_next_col:
LD C, 0x0
; 1
CALL m_get_7vpix
AND D
CALL NZ, m_print_vert_7pix
LD HL, (M_VARS.ul_var0)
INC HL
; inc X
LD (M_VARS.ul_var0), HL
LD C, 0x1
; 2
CALL m_get_7vpix
AND D
CALL NZ, m_print_vert_7pix
LD HL, (M_VARS.ul_var0)
INC HL
; inc X
LD (M_VARS.ul_var0), HL
INC B
LD A, B
CP 236
JP C, .print_next_col
LD HL, cmd_esc_inc_Y2
CALL m_print_cmd
RET
; ------------------------------------------------------
; Send command to printer
; Inp: HL -> command bytes array
; ------------------------------------------------------
m_print_cmd:
PUSH BC
.print_nxt:
LD A, (HL)
CP ESC_CMD_END
JP Z, .cmd_end
LD C, A
CALL m_char_print
INC HL
JP .print_nxt
.cmd_end:
POP BC
RET
; ------------------------------------------------------
; Print 7 vertical pixels to printer
; Inp: A - value to print
; ------------------------------------------------------
m_print_vert_7pix:
PUSH AF
; Set coordinate X to 0
LD HL, cmd_esc_set_X
CALL m_print_cmd
LD HL, (M_VARS.ul_var0)
LD C,H
CALL m_char_print
LD C,L
CALL m_char_print
; Set column print mode
LD HL, cmd_esc_print_col
CALL m_print_cmd
POP AF
; Print 7 vertical pixels
LD C, A
CALL m_char_print
RET
; ------------------------------------------------------
; Control codes for printer УВВПЧ-30-004
; ------------------------------------------------------
; <ESC>Zn - Increment Y coordinate
cmd_esc_inc_Y2:
DB ASCII_ESC
DB 'Z'
DB 2h
DB ESC_CMD_END
; <ESC>Xnn - Set X coordinate
cmd_esc_set_X0:
DB ASCII_ESC
DB 'X'
DB 0h ; 0..479
DB 0h
DB ESC_CMD_END
; ------------------------------------------------------
; <ESC>X - Start on "Set X coordinate" command
; ------------------------------------------------------
cmd_esc_set_X:
DB ASCII_ESC
DB 'X'
DB ESC_CMD_END
; <ESC>O - Column print (vertical 7 bit)
cmd_esc_print_col:
DB ASCII_ESC
DB 'O'
DB ESC_CMD_END
; ------------------------------------------------------
; Get 7 vertical pixels from screen
; Inp: C - sheet
; Out: A - byte
; ------------------------------------------------------
m_get_7vpix:
LD A, (M_VARS.row_shift)
ADD A, B
ADD A, 19 ; skip first 20pix
LD L, A
PUSH DE
PUSH BC
LD A, E
.calc_pix_no:
AND 0x7
LD B, A
LD A, E
; calc hi addr
RRA ; /8
RRA
RRA
AND 0x1f
ADD A, A ; *2
ADD A, 64 ; bytes per row
LD H, A
; select sheet 0|1
LD A, C
AND 0x1
ADD A, H
LD H, A
; HL = pix addr, turn on VRAM access
LD A, 0x1
OUT (SYS_DD17PB), A
LD E, (HL) ; read pixel
INC H ; HL += 512
INC H
LD D, (HL) ; read pixel row+1
; turn off VRAM access
;v8 XOR A
LD A, 0
OUT (SYS_DD17PB), A
.for_all_pix:
DEC B
JP M, .all_shifted
; shift pixels D >> [CF] >> E
LD A, D
RRA
LD D, A
LD A, E
RRA
LD E, A
JP .for_all_pix
.all_shifted:
LD A, E
LD D, 0
RRA
JP NC,.not_1_1
LD D,00110000b
.not_1_1:
RRA
JP NC, .not_1_2
LD A, D
OR 11000000b
LD D, A
.not_1_2:
LD A, D
POP BC
POP DE
RET
; --------------------------------------------------
;
; --------------------------------------------------
esc_set_palette:
LD A, (M_VARS.esc_param)
AND 00111111b ; bgcol[2,1,0],pal[2,1,0]
LD (M_VARS.cur_palette), A
LD B, A
LD A, (M_VARS.screen_mode)
AND 00000011b
LD A, 0x0
JP NZ, .no_colr
LD A, 0x40
.no_colr:
OR B
OUT (VID_DD67PB), A
RET
; --------------------------------------------------
;
; --------------------------------------------------
esc_set_charset:
LD A, (M_VARS.esc_param)
AND 0x3 ; charset 0..3
LD (M_VARS.codepage), A
RET
; ------------------------------------------------------
; Get address for draw symbol glyph
; Inp: A - ascii code
; Out: HL -> glyph offset
; ------------------------------------------------------
m_get_glyph:
LD L, A ; L = ascii code
LD E, A ; E = ascii code
XOR A
LD D, A
LD H, A
; HL = DE = ascii code
ADD HL, HL
ADD HL, DE
ADD HL, HL
ADD HL, DE
; HL = A * 7
LD A, E ; A = A at proc entry
CP '@'
; First 64 symbols is same for all codepages
JP M, .cp_common
LD A, (M_VARS.codepage)
OR A
; cp=0 - Latin letters
JP Z, .cp_common
DEC A
; cp=1 - Russian letters
JP Z, .cp_rus
; cp=2 - 0x40..0x5F - displayed as Lat
; 0x60 - 0x7F - displayed as Rus
LD A, E
CP 0x60
JP M, .cp_common
.cp_rus:
LD DE, 448 ; +448=64*7 Offset for cp1
ADD HL, DE
.cp_common:
LD DE, m_font_cp0-224 ; m_font_cp0-32*7
ADD HL, DE ; add symbol glyph offset
RET
; --------------------------------------------------
; Console output
; Inp: C - char
; --------------------------------------------------
m_print_no_esc:
LD A, C
AND 0x7f
CP 0x20
JP M, m_handle_esc_code
CALL m_get_glyph
EX DE, HL
LD A, (M_VARS.screen_mode)
AND 0x3
JP NZ, mp_mode_64
CALL calc_addr_40
LD A, 0x1
OUT (SYS_DD17PB), A
EX DE, HL
LD A, B
OR B
JP Z, mpn_l1
DEC B
JP Z, mpn_l2
DEC B
JP Z, mpn_l4
JP mpn_l6
mpn_l1:
XOR A
LD (DE), A
INC D
LD (DE), A
DEC D
INC E
mpn_l1_1:
LD A, (M_VARS.curr_color)
AND (HL)
LD B, A
LD A, (DE)
AND 0xc0
OR B
LD (DE), A
LD A, (M_VARS.curr_color+1)
AND (HL)
LD B, A
INC D
LD A, (DE)
AND 0xc0
OR B
LD (DE), A
DEC D
INC HL
INC E
DEC C
JP NZ, mpn_l1_1
JP mpn_clos_vram
mpn_l2:
XOR A
LD (DE), A
INC D
LD (DE), A
DEC D
DEC D
LD (DE), A
DEC D
LD (DE), A
INC D
INC D
INC E
mpn_l3:
LD A, (M_VARS.curr_color+1)
AND (HL)
RRCA
RRCA
LD (M_VARS.ul_var3), A
LD A, (M_VARS.curr_color)
AND (HL)
RRCA
RRCA
LD (M_VARS.ul_var2), A
AND 0xf
LD B, A
LD A, (DE)
AND 0xf0
OR B
LD (DE), A
LD A, (M_VARS.ul_var3)
AND 0xf
LD B, A
INC D
LD A, (DE)
AND 0xf0
OR B
LD (DE), A
DEC D
LD A, (M_VARS.ul_var3)
AND 0xc0
LD B, A
DEC D
LD A, (DE)
AND 0x3f
OR B
LD (DE), A
LD A, (M_VARS.ul_var2)
AND 0xc0
LD B, A
DEC D
LD A, (DE)
AND 0x3f
OR B
LD (DE), A
INC D
INC D
INC HL
INC E
DEC C
JP NZ, mpn_l3
JP mpn_clos_vram
mpn_l4:
XOR A
LD (DE), A
INC D
LD (DE), A
DEC D
DEC D
LD (DE), A
DEC D
LD (DE), A
INC D
INC D
INC E
mpn_l5:
LD A, (M_VARS.curr_color+1)
AND (HL)
RRCA
RRCA
RRCA
RRCA
LD (M_VARS.ul_var3), A
LD A, (M_VARS.curr_color)
AND (HL)
RRCA
RRCA
RRCA
RRCA
LD (M_VARS.ul_var2), A
AND 0x3
LD B, A
LD A, (DE)
AND 0xfc
OR B
LD (DE), A
LD A, (M_VARS.ul_var3)
AND 0x3
LD B, A
INC D
LD A, (DE)
AND 0xfc
OR B
LD (DE), A
DEC D
LD A, (M_VARS.ul_var3)
AND 0xf0
LD B, A
DEC D
LD A, (DE)
AND 0xf
OR B
LD (DE), A
LD A, (M_VARS.ul_var2)
AND 0xf0
LD B, A
DEC D
LD A, (DE)
AND 0xf
OR B
LD (DE), A
INC D
INC D
INC HL
INC E
DEC C
JP NZ, mpn_l5
JP mpn_clos_vram
mpn_l6:
DEC D
XOR A
LD (DE), A
DEC D
LD (DE), A
INC D
INC E
mpn_l7:
LD A, (M_VARS.curr_color+1)
AND (HL)
RLCA
RLCA
LD B, A
LD A, (DE)
AND 0x3
OR B
LD (DE), A
LD A, (M_VARS.curr_color)
AND (HL)
RLCA
RLCA
LD B, A
DEC D
LD A, (DE)
AND 0x3
OR B
LD (DE), A
INC D
INC HL
INC E
DEC C
JP NZ, mpn_l7
INC D
mpn_clos_vram:
LD A, 0x0
OUT (SYS_DD17PB), A
LD HL, m_draw_cursor
PUSH HL
LD HL, M_VARS.cursor_row
; --------------------------------------------------
; Handle ASCII_CAN (cursor right)
; Inp: HL - cursor pos
; --------------------------------------------------
m40_rt:
INC HL
LD A, (HL) ; a = col
ADD A, 1 ; col+1
AND 0x3f ; screen column 0..63
LD (HL), A ; save new col
CP 40
DEC HL
RET M ; Return if no wrap
m40_wrap_rt:
INC HL
XOR A
LD (HL), A
DEC HL
LD A, (M_VARS.screen_mode)
AND 0x08 ; screen_mode=8?
JP NZ, m2_lf
; --------------------------------------------------
; Handle ASCII_LF (cursor down)
; Inp: HL - cursor pos
; --------------------------------------------------
m40_lf:
LD A, (HL)
ADD A, 11
CP 250
JP NC, scroll_up
LD (HL), A
RET
; --------------------------------------------------
; Handle ASCII_BS (cursor left)
; Inp: HL - cursor pos
; --------------------------------------------------
m40_bksp:
INC HL
LD A, (HL)
SUB 1 ; TODO: DEC A
AND 0x3f ; A=0..63
CP 0x3f
JP Z, .wrap
LD (HL), A
DEC HL
RET
.wrap:
LD A, 39
LD (HL), A
DEC HL
; and cursor up
; --------------------------------------------------
; Handle ASCII_EM (cursor up)
; Inp: HL - cursor pos
; --------------------------------------------------
m40_up:
LD A, (HL)
SUB 11 ; 10 rows per symbol
JP NC, .up_no_minus
LD A, 242 ; wrap to bottom
.up_no_minus:
LD (HL), A
RET
; --------------------------------------------------
; Handle ASCII_TAB (cursor right 8 pos) 20rows mode
; Inp: HL - cursor pos
; --------------------------------------------------
m20_tab:
INC HL
LD A, (HL)
ADD A, 8
AND 0x3f ; wrap A=0..63
LD (HL), A
CP 40
DEC HL
RET M ; ret if column <40
JP m40_wrap_rt ; or wrap to next line
; --------------------------------------------------
; Calculate VRAM address in 40 column mode
; --------------------------------------------------
calc_addr_40:
LD HL, (M_VARS.cursor_row)
LD A, (M_VARS.row_shift)
ADD A, L
LD L, A
LD A, H
CP 0x4
LD B, A
JP M, .l2
AND 0x3
LD B, A
LD A, H
OR A
RRA
OR A
RRA
LD C, A
LD H, 0x6
XOR A
.l1:
ADD A, H
DEC C
JP NZ, .l1
ADD A, B
.l2:
ADD A, B
ADD A, 0x42
LD H, A
LD C, 0x7
RET
; --------------------------------------------------
;
; --------------------------------------------------
m2_lf:
LD A, (HL)
ADD A, 11
CP 15
JP NC, .lf_nowr
LD (HL), A
RET
.lf_nowr:
LD A, (M_VARS.row_shift)
LD L, A
ADD A, 11
LD E, A
LD C, 8
; Access to VRAM
LD A, 0x1
OUT (SYS_DD17PB), A
.cas_l5:
LD B, 0x40
LD H, 0x40 ; TODO: LD H, B save 1b 3t
LD D, H
.cas_l6:
LD A, (DE)
LD (HL), A
INC H
INC D
DEC B
JP NZ, .cas_l6
INC L
INC E
DEC C
JP NZ, .cas_l5
LD C, 11
LD A, (M_VARS.row_shift)
ADD A, 8
LD E, A
.cas_l7:
LD B, 0x40
LD D, 0x40 ; TODO: LD D, B save 1b 3t
XOR A
.cas_l8:
LD (DE), A
INC D
DEC B
JP NZ, .cas_l8
INC E
DEC C
JP NZ, .cas_l7
LD A, 0
OUT (SYS_DD17PB), A
RET
; ---------------------------------------------------
; Handle ASCII_BS (cursor left) in 20row mode
; ---------------------------------------------------
m20_bksp:
INC HL
LD A, (HL)
OR A
DEC HL
RET Z
INC HL
SUB 1 ; TODO: DEC A - save 1b 2t
AND 0x3f
LD (HL), A
DEC HL
RET
; ---------------------------------------------------
; Print symbol in 64x25 mode
; ---------------------------------------------------
mp_mode_64:
CP 0x3
JP Z, mp_mode_80
PUSH AF
LD HL, (M_VARS.cursor_row)
LD A, (M_VARS.row_shift)
ADD A, L
LD L, A
LD A, H
ADD A, 0x40
LD H, A
LD C, 0x7
POP AF
CP 0x2
JP Z, m64_put_vram
LD A, 0x1
OUT (SYS_DD17PB), A
EX DE, HL
XOR A
LD (DE), A
INC E
m64_next_row:
LD A, (HL)
ADD A, A
LD (DE), A
INC HL
INC E
DEC C
JP NZ, m64_next_row
LD A, 0x0
OUT (SYS_DD17PB), A
LD HL, m_draw_cursor
PUSH HL
LD HL, M_VARS.cursor_row
; --------------------------------------------------
; Handle ASCII_CAN (cursor right) in 64x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m64_rt:
INC HL
LD A, (HL)
ADD A, 0x1
AND 0x3f
LD (HL), A
DEC HL
RET NZ
; --------------------------------------------------
; Handle ASCII_LF (cursor down) in 64x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m64_lf:
LD A, (HL)
ADD A, 11
CP 0xfa
JP NC, scroll_up
LD (HL), A
RET
; --------------------------------------------------
; Scroll Up for 10 rows
; --------------------------------------------------
scroll_up:
LD A, (M_VARS.row_shift)
ADD A, 11
OUT (SYS_DD17PA), A ; Scroll via VShift register
LD (M_VARS.row_shift), A ; store new VShift value
; calc bottom 16 rows address in VRAM
LD HL, 0x40f0 ; 240th VRAM byte
ADD A, L
LD L, A
LD C, H
; Access to VRAM
LD A, 0x1
OUT (SYS_DD17PB), A
XOR A
LD DE, 0x1040 ; D=16 E=64 (512/8 bytes in row)
.next_row:
LD H, C
LD B, E
; clear 64 bytes (512px in mono or 256px in color mode)
.next_col:
LD (HL), A
INC H ; next column
DEC B
JP NZ, .next_col
INC L ; next row address
DEC D ; row counter - 1
JP NZ, .next_row
; Disable VRAM access
LD A, 0x0
OUT (SYS_DD17PB), A
RET
; --------------------------------------------------
; Handle ASCII_BS (cursor left) in 64x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m64_bs:
INC HL
LD A, (HL)
SUB 1 ; TODO: DEC A - save 1b 2t
AND 0x3f ; wrap column (0..63)
LD (HL), A
CP 63
DEC HL
RET NZ
; cursor up if wrapped
; --------------------------------------------------
; Handle ASCII_EM (cursor up) in 64x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m64_up:
LD A, (HL)
SUB 11
JP NC, .no_wrap
LD A, 242
.no_wrap:
LD (HL), A
RET
; --------------------------------------------------
; Handle ASCII_TAB (cursor column + 8) in 64x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m64_tab:
INC HL
LD A, (HL)
ADD A, 8
AND 0x38
LD (HL), A
DEC HL
RET NZ ; return if no wrap
; cursor down if wrap
JP m64_lf
; --------------------------------------------------
; Print symbols in 80x25 mode
; --------------------------------------------------
mp_mode_80:
CALL calc_addr_80
LD A, 0x1
OUT (SYS_DD17PB), A
EX DE, HL
LD A, B
OR B
JP Z, m80_l1
DEC B
JP Z, m80_l3
DEC B
JP Z, m80_l5
JP m80_l7
m80_l1:
XOR A
LD (DE), A
INC E
m80_l2:
LD B, (HL)
LD A, (DE)
AND 0xc0
OR B
LD (DE), A
INC HL
INC E
DEC C
JP NZ, m80_l2
JP m80_l9
m80_l3:
XOR A
LD (DE), A
DEC D
LD (DE), A
INC D
INC E
m80_l4:
LD A, (HL)
RRCA
RRCA
AND 0x7
LD B, A
LD A, (DE)
AND 0xf0
OR B
LD (DE), A
LD A, (HL)
RRCA
RRCA
AND 0xc0
LD B, A
DEC D
LD A, (DE)
AND 0x1f
OR B
LD (DE), A
INC D
INC HL
INC E
DEC C
JP NZ, m80_l4
JP m80_l9
m80_l5:
XOR A
LD (DE), A
DEC D
LD (DE), A
INC D
INC E
m80_l6:
LD A, (HL)
RRCA
RRCA
RRCA
RRCA
AND 0x1
LD B, A
LD A, (DE)
AND 0xfc
OR B
LD (DE), A
LD A, (HL)
RRCA
RRCA
RRCA
RRCA
AND 0xf0
LD B, A
DEC D
LD A, (DE)
AND 0x7
OR B
LD (DE), A
INC D
INC HL
INC E
DEC C
JP NZ, m80_l6
JP m80_l9
m80_l7:
DEC D
XOR A
LD (DE), A
INC E
m80_l8:
LD A, (HL)
RLCA
RLCA
LD B, A
LD A, (DE)
AND 0x1
OR B
LD (DE), A
INC HL
INC E
DEC C
JP NZ, m80_l8
INC D
m80_l9:
LD A, 0x0
OUT (SYS_DD17PB), A
LD HL, m_draw_cursor
PUSH HL
LD HL, M_VARS.cursor_row
; --------------------------------------------------
; Handle ASCII_CAN (cursor right) in 80x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m80_rt:
INC HL
LD A, (HL)
ADD A, 0x1
AND 0x7f
LD (HL), A
CP 0x50
DEC HL
RET M
m80_col_wrap:
INC HL
XOR A
LD (HL), A
DEC HL
; and move cursor to next row
; --------------------------------------------------
; Handle ASCII_LF (cursor down) in 80x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m80_lf:
LD A, (HL)
ADD A, 11
CP 250
JP NC, scroll_up
LD (HL), A
RET
; --------------------------------------------------
; Handle ASCII_BS (cursor left) in 80x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m80_bs:
INC HL
LD A, (HL)
SUB 0x1
AND 0x7f
CP 0x7f
JP Z, .wrap
LD (HL), A
DEC HL
RET
.wrap:
LD A, 0x4f
LD (HL), A
DEC HL
; and move cursor to previous line
; --------------------------------------------------
; Handle ASCII_EM (cursor up) in 80x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m80_up:
LD A, (HL)
SUB 0xb
JP NC, .wrap
LD A, 0xf2
.wrap
LD (HL), A
RET
; --------------------------------------------------
; Handle ASCII_TAB (cursor column + 8) in 80x25 mode
; Inp: HL - cursor pos
; --------------------------------------------------
m80_tab:
INC HL
LD A, (HL)
ADD A, 0x8
AND 0x7f
LD (HL), A
CP 0x50
DEC HL
RET M
JP m80_col_wrap
; --------------------------------------------------
; Calculate address for cursor pos for 80x25 mode
; Out: HL -> VRAM
; B -> pixel pos in byte
; --------------------------------------------------
calc_addr_80:
LD HL, (M_VARS.cursor_row)
LD A, (M_VARS.row_shift)
ADD A, L
LD L, A
LD A, H
CP 0x4
LD B, A
JP M, ca80_l2
AND 0x3
LD B, A
LD A, H
OR A
RRA
OR A
RRA
LD C, A
LD H, 0x3
XOR A
ca80_l1:
ADD A, H
DEC C
JP NZ, ca80_l1
ADD A, B
ca80_l2:
ADD A, 0x42
LD H, A
LD C, 0x7
RET
; --------------------------------------------------
m64_put_vram:
LD A, (M_VARS.cursor_col)
CP 0x40
JP M, pv_access_vram
LD HL, M_VARS.cursor_row
CALL m_draw_cursor
RET
pv_access_vram:
LD A, 0x1
OUT (SYS_DD17PB), A
EX DE, HL
XOR A
LD (DE), A
INC E
pv_rept:
LD A, (HL)
ADD A, A
LD (DE), A
INC HL
INC E
DEC C
JP NZ, pv_rept
LD A, 0x0
OUT (SYS_DD17PB), A
LD HL, m_draw_cursor
PUSH HL
LD HL, M_VARS.cursor_row
INC HL
LD A, (HL)
ADD A, 0x1
CP 0x40
JP M, pv_end
LD A, 0x40
pv_end:
LD (HL), A
DEC HL
RET
; --------------------------------------------------
; Clear screen and set cursor to 0,0
; Inp: HL -> cursor position
; --------------------------------------------------
m_clear_screen:
LD A, (M_VARS.screen_mode)
AND 0x8
JP NZ, m_clear_20_rows ; for bit 4 is set, clear only 20 rows
; all in black
LD A, 01111111b
OUT (VID_DD67PB), A ; C/M=1 FL=111 CL=111 All black
; Access VRAM
LD A, 0x1
OUT (SYS_DD17PB), A
LD DE, video_ram
EX DE, HL
LD A, H
ADD A, 0x40 ; A=0x80
LD B, 0
.fill_scrn:
LD (HL), B
INC HL
CP H
JP NZ, .fill_scrn ; fill while HL<0x8000
EX DE, HL
LD A, (M_VARS.cur_palette)
LD B, A ; B = current palette
LD A, (M_VARS.screen_mode)
AND 0x3 ; color?
LD A, 0x0
JP NZ, .mono_mode
LD A, 01000000b
.mono_mode:
OR B
; Restore mode and palette
OUT (VID_DD67PB), A
; And set cursor to home position
; --------------------------------------------------
; Set cursor to 0,0 and close VRAM access
; Inp: HL -> cursor_row
; --------------------------------------------------
m_cursor_home:
XOR A
NOP
NOP
LD (HL), A
INC HL
XOR A
LD (HL), A
DEC HL
;XOR A
LD A, 0
; Disable VRAM access
OUT (SYS_DD17PB), A
RET
; Clear only 20 rows
m_clear_20_rows:
; take row shift in account
LD A, (M_VARS.row_shift)
LD L, A
LD C, 20
; Access VRAM
LD A, 0x1
OUT (SYS_DD17PB), A
.next_row:
LD H, 0x40 ; HL = 0x4000 + shift_row
LD B, 64 ; 64 bytes at row
XOR A
.next_col:
LD (HL), A
INC H ; next column
DEC B
JP NZ, .next_col
INC L ; next row
DEC C
JP NZ, .next_row
; Disabe VRAM access
LD A, 0
OUT (SYS_DD17PB), A
JP m_cursor_home
; --------------------------------------------------
; Draw cursor at current cursor position
; if not hidden
; --------------------------------------------------
m_draw_cursor:
LD A, (M_VARS.screen_mode)
AND 0x4
RET NZ
LD A, (M_VARS.screen_mode)
AND 0x3
JP NZ, .dc_mode_64
EX DE, HL
LD HL, (M_VARS.cursor_row)
LD A, H
CP 0x28
EX DE, HL
RET P
EX DE, HL
CALL calc_addr_40
LD A, 0x1
OUT (SYS_DD17PB), A
LD C, 0x8
LD A, B
OR B
JP Z, .l1
DEC B
JP Z, .l2
DEC B
JP Z, .l3
JP .l4
.l1:
LD A, (HL)
AND 0xc0
LD B, A
LD A, (HL)
XOR 0x1f
AND 0x1f
OR B
LD (HL), A
INC H
LD A, (HL)
AND 0xc0
LD B, A
LD A, (HL)
XOR 0x1f
AND 0x1f
OR B
LD (HL), A
DEC H
INC L
DEC C
JP NZ, .l1
JP .l6
.l2:
DEC H
LD A, (HL)
AND 0x3f
LD B, A
LD A, (HL)
XOR 0xc0
AND 0xc0
OR B
LD (HL), A
DEC H
LD A, (HL)
AND 0x3f
LD B, A
LD A, (HL)
XOR 0xc0
AND 0xc0
OR B
LD (HL), A
INC H
INC H
LD A, (HL)
AND 0xf0
LD B, A
LD A, (HL)
XOR 0x7
AND 0x7
OR B
LD (HL), A
INC H
LD A, (HL)
AND 0xf0
LD B, A
LD A, (HL)
XOR 0x7
AND 0x7
OR B
LD (HL), A
DEC H
INC L
DEC C
JP NZ, .l2
JP .l6
.l3:
DEC H
LD A, (HL)
AND 0xf
LD B, A
LD A, (HL)
XOR 0xf0
AND 0xf0
OR B
LD (HL), A
DEC H
LD A, (HL)
AND 0xf
LD B, A
LD A, (HL)
XOR 0xf0
AND 0xf0
OR B
LD (HL), A
INC H
INC H
LD A, (HL)
AND 0xfc
LD B, A
LD A, (HL)
XOR 0x1
AND 0x1
OR B
LD (HL), A
INC H
LD A, (HL)
AND 0xfc
LD B, A
LD A, (HL)
XOR 0x1
AND 0x1
LD (HL), A
DEC H
INC L
DEC C
JP NZ, .l3
JP .l6
.l4:
DEC H
.l5:
LD A, (HL)
AND 0x3
LD B, A
LD A, (HL)
XOR 0x7c
AND 0x7c
OR B
LD (HL), A
DEC H
LD A, (HL)
AND 0x3
LD B, A
LD A, (HL)
XOR 0x7c
AND 0x7c
OR B
LD (HL), A
INC H
INC L
DEC C
JP NZ, .l5
INC H
.l6:
EX DE, HL
LD A, 0x0
OUT (SYS_DD17PB), A
RET
.dc_mode_64:
CP 0x3
JP Z, .l8
EX DE, HL
LD HL, (M_VARS.cursor_row)
LD A, (M_VARS.row_shift)
ADD A, L
LD L, A
LD A, H
CP 0x40
EX DE, HL
RET P
EX DE, HL
ADD A, 0x40
LD H, A
LD A, 0x1
OUT (SYS_DD17PB), A
LD BC, 0x7f08
.l7:
LD A, (HL)
XOR B
LD (HL), A
INC L
DEC C
JP NZ, .l7
EX DE, HL
LD A, 0x0
OUT (SYS_DD17PB), A
RET
.l8:
EX DE, HL
LD HL, (M_VARS.cursor_row)
LD A, H
CP 0x50
EX DE, HL
RET P
EX DE, HL
CALL calc_addr_80
LD C, 0x8
LD A, 0x1
OUT (SYS_DD17PB), A
LD A, B
OR B
JP Z, .l9
DEC B
JP Z, .l10
DEC B
JP Z, .l11
JP .l12
.l9:
LD A, (HL)
AND 0xc0
LD B, A
LD A, (HL)
XOR 0x1f
AND 0x1f
OR B
LD (HL), A
INC L
DEC C
JP NZ, .l9
JP .exit
.l10:
DEC H
LD A, (HL)
AND 0x1f
LD B, A
LD A, (HL)
XOR 0xc0
AND 0xc0
OR B
LD (HL), A
INC H
LD A, (HL)
AND 0xf0
LD B, A
LD A, (HL)
XOR 0x7
AND 0x7
OR B
LD (HL), A
INC L
DEC C
JP NZ, .l10
JP .exit
.l11:
DEC H
LD A, (HL)
AND 0x7
LD B, A
LD A, (HL)
XOR 0xf0
AND 0xf0
OR B
LD (HL), A
INC H
LD A, (HL)
AND 0xfc
LD B, A
LD A, (HL)
XOR 0x1
AND 0x1
OR B
LD (HL), A
INC L
DEC C
JP NZ, .l11
JP .exit
.l12:
DEC H
.l13:
LD A, (HL)
AND 0x1
LD B, A
LD A, (HL)
XOR 0x7c
AND 0x7c
OR B
LD (HL), A
INC L
DEC C
JP NZ, .l13
INC H
.exit:
EX DE, HL
LD A, 0x0
OUT (SYS_DD17PB), A
RET
; --------------------------------------------------
; If ESC character, turn esc_mode ON
; Inp: A - ASCII symbol
; --------------------------------------------------
m_handle_esc_code:
CP ASCII_ESC
JP NZ, m_handle_control_code
; turn on ESC mode for next chars
LD HL, M_VARS.esc_mode
LD (HL), 0x1 ; turn on ESC mode
INC HL
LD (HL), 0xff ; esc_cmd = 0xff
RET
; --------------------------------------------------
; Handle one byte ASCII control code
; Inp: A - ASCII symbol
; --------------------------------------------------
m_handle_control_code:
CP ASCII_BELL
JP Z, m_beep
LD HL, m_draw_cursor
PUSH HL
LD HL, M_VARS.cursor_row
PUSH AF
CALL m_draw_cursor
LD A, (M_VARS.screen_mode)
AND 0x08 ; 20-rows mode?
JP Z, handle_cc_common ; jump for normal screen modes
; for hidden cursor modes
POP AF
CP ASCII_TAB ; TAB
JP Z, m20_tab
CP ASCII_BS ; BKSP
JP Z, m20_bksp
CP ASCII_CAN ; Cancel
JP Z, m40_rt
CP ASCII_US ; ASCII Unit separator
JP Z, m_clear_20_rows
CP ASCII_LF ; LF
JP Z, m2_lf
CP ASCII_CR ; CR
RET NZ ; ret on unknown
INC HL
LD (HL), 0x0
DEC HL
RET
; --------------------------------------------------
; Handle cursor for 40x25, 64x25, 80x25 modes
; --------------------------------------------------
handle_cc_common:
POP AF
CP ASCII_US
JP Z, m_clear_screen
CP ASCII_FF
JP Z, m_cursor_home
PUSH AF
LD A, (M_VARS.screen_mode)
AND 3 ; check for color modes
JP NZ, handle_cc_mono
; 32x25 text mode
POP AF
CP ASCII_TAB ; cursor right +8
JP Z, m20_tab
CP ASCII_BS ; cursor left
JP Z, m40_bksp
CP ASCII_CAN ; cursor right
JP Z, m40_rt
CP ASCII_EM ; cursor up
JP Z, m40_up
CP ASCII_SUB
JP Z, m40_lf ; cursor down
CP ASCII_LF
JP Z, m40_lf
CP ASCII_CR
RET NZ
INC HL
LD (HL), 0x0 ; move cursor to first column for CR
DEC HL
RET
; --------------------------------------------------
; Handle control chars for 64x25 or 80x25 modes
; --------------------------------------------------
handle_cc_mono:
LD A, (M_VARS.screen_mode)
CP 0x3
JP Z, handle_cc_80x25
CP 0x7
JP Z, handle_cc_80x25
AND 0x2
JP NZ, handle_cc_colr
POP AF
CP ASCII_TAB
JP Z, m64_tab
CP ASCII_BS
JP Z, m64_bs
CP ASCII_CAN
JP Z, m64_rt
CP ASCII_EM
JP Z, m64_up
CP ASCII_SUB
JP Z, m64_lf
CP ASCII_LF
JP Z, m64_lf
CP ASCII_CR
RET NZ
INC HL
LD (HL), 0x0
DEC HL
RET
handle_cc_colr:
POP AF
CP ASCII_LF
JP Z, m64_lf
CP ASCII_CR
RET NZ
INC HL
LD (HL), 0x0
DEC HL
RET
; --------------------------------------------------
; Handle control chars for 80x25 modes
; --------------------------------------------------
handle_cc_80x25:
POP AF
CP ASCII_TAB
JP Z, m80_tab
CP ASCII_BS
JP Z, m80_bs
CP ASCII_CAN
JP Z, m80_rt
CP ASCII_EM
JP Z, m80_up
CP ASCII_SUB
JP Z, m80_lf
CP ASCII_LF
JP Z, m80_lf
CP ASCII_CR
RET NZ
INC HL
LD (HL), 0x0
DEC HL
RET
; --------------------------------------------------
;
; --------------------------------------------------
m_beep:
LD HL, (M_VARS.beep_duration)
EX DE, HL
LD HL, (M_VARS.beep_period)
LD A, 00110110b ; TMR#0 LSB+MSB Square Wave Generator
OUT (TMR_DD70CTR), A
LD A, L ; LSB
OUT (TMR_DD70C1), A
LD A, H ; MSB
OUT (TMR_DD70C1), A
LD A, (M_VARS.strobe_state)
LD B, A
m_bell_cont:
LD A, D ; DE=duration
OR E
RET Z ; ret if enough
DEC DE
LD A, B
XOR BELL_PIN
LD B, A
OUT (DD67PC), A ; Invert bell pin
m_bell_wait_tmr1:
IN A, (PIC_DD75RS)
AND TIMER_IRQ ; 0x10
JP NZ, m_bell_wait_tmr1
LD A, B
XOR BELL_PIN ; Flip pin again
LD B, A
OUT (DD67PC), A
m_bell_wait_tmr2:
IN A, (PIC_DD75RS)
AND TIMER_IRQ
JP Z,m_bell_wait_tmr2
JP m_bell_cont
; ------------------------------------------------------
; <ESC>5<row><col> Set cursor position
; ------------------------------------------------------
esc_set_cursor:
LD A, (M_VARS.screen_mode)
AND 0x8
RET NZ
CALL m_draw_cursor
LD DE, M_VARS.esc_param
LD HL, M_VARS.cursor_col
INC DE
LD A, (DE)
SUB 0x20
LD B, A
LD A, (M_VARS.screen_mode)
CP 0x3
JP Z, .mode80
CP 0x7
JP Z, .mode80
OR A
JP Z, .mode40
CP 0x4
JP Z, .mode40
LD A, B
CP 0x40
JP M, .common
LD A, 0x40
JP .common
.mode40:
LD A, B
CP 40
JP M, .common
LD A, 40
JP .common
.mode80:
LD A, B
CP 80
JP M, .common
LD A, 80
.common:
LD (HL), A
DEC DE
DEC HL
LD A, (DE)
SUB 32
CP 22
JP C, .le_24
LD A, 22
.le_24:
LD B, A
ADD A, A
ADD A, A
ADD A, B
ADD A, A
ADD A, B
LD (HL), A
CALL m_draw_cursor
RET
; ------------------------------------------------------
; <ESC>6n Set video mode or cursor visibility
; Inp: n is
; 0 - C 32x25 with cursor; 0000
; 1 - M 64x25 with cursor; 0001
; 2 - M 64x25 with cursor; 0010
; 3 - M 80x25 with cursor; 0011
; 4 - C 32x25 no cursor; 0100
; 5 - M 64x25 no cursor; 0101
; 6 - M 64x25 no cursor; 0110
; 7 - M 80x25 no cursor; 0111
; 8 - M 20rows mode 1000
; 9 - hide cursor 1001
; 10 - show cursor 1010
; ------------------------------------------------------
esc_set_vmode:
LD HL, M_VARS.screen_mode
LD A, (M_VARS.cur_palette)
LD B, A
LD A, (M_VARS.esc_param)
LD C, A
AND 0x8
LD A, C
JP Z, .no_20_mode
LD A, 0x8
.no_20_mode:
AND 0xf
LD (HL), A
CP 0x4
JP Z, .m32x25c
AND 0x3
LD A, 0x0
JP NZ, .t_mode
.m32x25c:
LD A, 0x40
.t_mode:
OR B
OUT (VID_DD67PB), A
LD HL, M_VARS.cursor_row
CALL m_clear_screen
CALL m_draw_cursor
RET
; ------------------------------------------------------
; <ESC>4n n=1..4 Set drawing color
; ------------------------------------------------------
esc_set_color:
LD A, (M_VARS.esc_param)
m_set_color:
AND 0x3
RRA
LD B, A
LD A, 0x0 ; TODO: unused
SBC A, A
LD (M_VARS.curr_color), A
LD A, B
DEC A
CPL
LD (M_VARS.curr_color+1), A
RET
;---------------------------------------------------
; Print symbol or print sprite at X,Y coordinates
; Inp: param x,y
; C - character or sprite_no to draw
;---------------------------------------------------
m_print_at_xy:
LD A,(M_VARS.screen_mode)
AND 0x7
JP NZ,esc_exit
LD A,C
AND 0x7f
LD C,A
CP 0x20
JP M,esc_exit
LD HL,M_VARS.esc_param
LD A,(HL)
LD E,A
ADD A,0x8
JP C,esc_exit
LD (HL),A
INC HL
LD A,0xf7
CP (HL)
JP C,esc_exit
LD D,(HL)
CALL calc_px_addr
LD A,L
SUB 0x7
LD L,A
PUSH HL
LD A,C
CALL m_get_glyph
POP DE
LD C,0x7
.l1:
PUSH HL
LD A,0x1
OUT (SYS_DD17PB),A
LD L,(HL)
LD H,0x0
LD A,B
OR A
JP Z,.l3
.l2:
ADD HL,HL
DEC A
JP NZ,.l2
.l3:
EX DE,HL
PUSH BC
LD A,(M_VARS.curr_color)
CPL
LD B,A
LD A,(HL)
XOR B
OR E
XOR B
LD (HL),A
INC H
INC H
LD A,(HL)
XOR B
OR D
XOR B
LD (HL),A
DEC H
LD A,(M_VARS.curr_color+1)
CPL
LD B,A
LD A,(HL)
XOR B
OR E
XOR B
LD (HL),A
INC H
INC H
LD A,(HL)
XOR B
OR D
XOR B
LD (HL),A
DEC H
DEC H
DEC H
INC L
EX DE,HL
POP BC
LD A,0x0
OUT (SYS_DD17PB),A
POP HL
INC HL
DEC C
JP NZ,.l1
RET
; --------------------------------------------------
; Calculate address of pixel in Video RAM
; Inp: DE - Y, X
; Out: HL - address
; B - offset in byte
; --------------------------------------------------
calc_px_addr:
; take into account the vertical displacement
LD A, (M_VARS.row_shift)
SUB D
DEC A
LD L, A
LD A, E
AND 0x07 ; X mod 8 - offset in byte
LD B, A
LD A, E
RRA
RRA
AND 00111110b
ADD A, 0x40 ; VRAM at 0x4000
LD H, A
RET
;---------------------------------------------------
; Draw Filled Rectange
; Inp: esc param X1,Y2,X2,Y2
; --------------------------------------------------
esc_draw_fill_rect:
LD HL, M_VARS.esc_param+3
LD DE, M_VARS.esc_param+1
LD A, (DE)
LD B, (HL)
CP B
JP NC, .l1
LD (HL), A
LD A, B
LD (DE), A
.l1:
DEC DE
DEC HL
LD A, (DE)
LD B, (HL)
CP B
JP C, .l2
LD (HL), A
LD A, B
LD (DE), A
.l2:
EX DE, HL
LD E, (HL)
INC HL
LD D, (HL)
CALL calc_px_addr
PUSH HL
XOR A
.l3:
SCF
RLA
DEC B
JP P, .l3
RRA
LD D, A
LD HL, M_VARS.esc_param+2
LD A, (HL)
AND 0x7
LD B, A
XOR A
.l4:
SCF
RLA
DEC B
JP P, .l4
CPL
LD E, A
LD A, (HL)
DEC HL
DEC HL
SUB (HL)
RRCA
RRCA
RRCA
AND 0x1f
LD C, A
INC HL
LD A, (HL)
INC HL
INC HL
SUB (HL)
JP NZ, .l5
INC A
.l5:
LD B, A
POP HL
LD A, E
LD (M_VARS.esc_param+4), A
.l6:
PUSH DE
PUSH HL
PUSH BC
LD A, 0x1
OUT (SYS_DD17PB), A
LD A, C
OR A
JP NZ, .l8
LD A, D
OR E
.l7:
LD D, A
.l8:
LD B, D
EX DE, HL
LD HL, (M_VARS.curr_color)
EX DE, HL
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
INC H
LD A, C
OR A
JP Z, .l11
DEC C
.l9:
LD A, (M_VARS.esc_param+4)
JP Z, .l7
.l10:
LD (HL), E
INC H
LD (HL), D
INC H
DEC C
JP NZ, .l10
JP .l9
.l11:
LD A, 0x0
OUT (SYS_DD17PB), A
POP BC
POP HL
POP DE
INC L
DEC B
JP NZ, .l6
RET
;---------------------------------------------------
; <ESC>2x1y1x2y2 Draw Line
;---------------------------------------------------
esc_draw_line:
LD HL, M_VARS.esc_param
LD E, (HL) ; E=X1
INC HL
LD D, (HL) ; D=Y1
INC HL
LD A, (HL)
INC HL
LD H, (HL) ; H=Y2
LD L, A ; L=X2
CP E
JP C, .x1_le_x2
EX DE, HL ; exchange if X1>X2
.x1_le_x2:
LD (M_VARS.esc_param), HL ; store x1,y1 back
LD A, E
SUB L
LD L, A ; L - width
LD A, D
SUB H
LD H, A ; H - height
PUSH AF
JP NC, .pos_height
; change sign
CPL
INC A
LD H, A
.pos_height:
EX DE, HL
LD HL, (M_VARS.esc_param)
EX DE, HL
JP Z, height0
LD A, L
OR A
JP Z, .width0
LD B, A
POP AF
LD A, 0x0
ADC A, A
LD (M_VARS.esc_param+4), A
; HL = E/B height/width
LD E, H
LD C, 16
LD D, 0
.next_16:
ADD HL, HL
EX DE, HL
ADD HL, HL
EX DE, HL
LD A, D
JP C, .edl_l4
CP B
JP C, .edl_l5
.edl_l4:
SUB B
LD D, A
INC HL
.edl_l5:
DEC C
JP NZ, .next_16
LD DE, 0x0
PUSH DE
; save result at stack
PUSH HL
LD HL, (M_VARS.esc_param) ; x1,y1
EX DE, HL
LD C, B
CALL calc_px_addr
; HL - address, B - offset in byte
; make mask
LD A, 10000000b
.roll_l:
RLCA
DEC B
JP P, .roll_l
CPL
LD B, A ; b - inv mask
.edl_l7
POP DE
EX (SP), HL ; save HL on top of stack
LD A, H
ADD HL, DE
SUB H
CPL
INC A
EX (SP), HL
PUSH DE
PUSH BC
LD C, A
EX DE, HL
LD HL, (M_VARS.curr_color)
EX DE, HL
; Access VideoRAM
LD A, 0x1
OUT (SYS_DD17PB), A
LD A, (M_VARS.esc_param+4) ; sign of delta Y
OR A
JP NZ, .next_down
.next_up:
; firs byte
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
; second byte
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
DEC H
LD A, C
OR A
JP Z, .is_last
DEC C
; draw up
DEC L
JP .next_up
.next_down:
; first byte
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
; second byte
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
;
DEC H
LD A, C
OR A
JP Z, .is_last
DEC C
; draw down
INC L
JP .next_down
.is_last:
; Disable VideoRAM access
LD A, 0x0
OUT (SYS_DD17PB), A
POP BC
LD A, B
; <<1px
SCF
RLA
JP C, .edl_l11
RLA
INC H
INC H
.edl_l11
LD B, A
DEC C
JP NZ, .edl_l7
POP HL
POP HL
RET
; --------------------------------------------------
; draw vertical line
; Inp: DE - YX
; L - length
; --------------------------------------------------
.width0
LD C, H
CALL calc_px_addr
; make pixel mask
LD A, 10000000b
.edl_l13:
RLCA
DEC B
JP P, .edl_l13
CPL
LD B, A
EX DE, HL
LD HL, (M_VARS.curr_color)
EX DE, HL
POP AF
; Enable VRAM
LD A, 0x1
OUT (SYS_DD17PB), A
JP C, .next_row_down
.next_row_up:
; first byte
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
; second byte
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
; next Y
DEC H
LD A, C
OR A
JP Z, close_vram_ret
DEC C
; dec row
DEC L
JP .next_row_up
.next_row_down:
; first byte
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
; second byte
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
; next address
DEC H
LD A, C
OR A
JP Z, close_vram_ret
DEC C
; inc row
INC L
JP .next_row_down
close_vram_ret:
; Disable VRAM access
LD A, 0x0
OUT (SYS_DD17PB), A
RET
; --------------------------------------------------
; Draw horizontal line
; Inp: DE - YX
; L - length
; --------------------------------------------------
height0:
POP AF
LD C, L
LD A, L
OR A
JP NZ, .len_ne0
INC C ; length 1 at least
.len_ne0:
CALL calc_px_addr
; make pixel mask
LD A, 10000000b
.edl_l19
RLCA
DEC B
JP P, .edl_l19
CPL
LD B, A
EX DE, HL
LD HL, (M_VARS.curr_color)
EX DE, HL
; Enable VRAM access
LD A, 0x1
OUT (SYS_DD17PB), A
.next_col:
; set 1st byte
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
; set 2nd byte
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
; next byte
DEC H
; next (right) horizontal pixel
LD A, B
SCF
RLA
JP C, .edl_l21
RLA
INC H
INC H
.edl_l21
LD B, A
DEC C
JP NZ, .next_col
; Disable VRAM access
LD A, 0x0
OUT (SYS_DD17PB), A
RET
; --------------------------------------------------
; ESC Draw Dot
; --------------------------------------------------
esc_draw_dot:
LD HL, (M_VARS.esc_param)
EX DE, HL
CALL calc_px_addr
LD A, 0x80
.l1:
RLCA
DEC B
JP P, .l1
LD B, A
EX DE, HL
LD HL, (M_VARS.curr_color)
EX DE, HL
LD A, 0x1
OUT (SYS_DD17PB), A
LD A, (HL)
XOR B
LD (HL), A
INC H
LD A, (HL)
XOR B
LD (HL), A
LD A, 0x0
OUT (SYS_DD17PB), A
RET
; ---------------------------------------------------
; Draw circle
; Inp: param x,y,radius, aspect_x, aspect_y
; ---------------------------------------------------
esc_draw_circle:
LD A, (M_VARS.esc_param+2) ; radius
LD B, A
OR A
RET Z ; exit ir radius 0
LD A, 0x7f
CP B
RET M ; exit if radius>127
XOR A
LD D, A ; 0
LD E, B ; r
CALL dc_draw_8px
LD A, 1
LD H, A
SUB B
LD C, A
LD A, B
RLCA
LD B, A
LD A, 0x1
SUB B
LD L, A
CCF ; TODO: unused
.l1:
INC D
LD A, E
CP D
JP Z, dc_draw_8px
CALL dc_draw_8px
LD A, H
ADD A, 0x2
LD H, A
LD A, L
ADD A, 0x2
LD L, A
LD A, C
ADD A, H
LD C, A
JP NC, .l1
.l2:
CCF ; TODO: unused
INC D
DEC E
LD A, D
CP E
JP Z, dc_draw_8px
SUB E
CP 0x1
RET Z
LD A, E
SUB D
CP 0x1
JP Z, dc_draw_8px
CALL dc_draw_8px
LD A, H
ADD A, 0x2
LD H, A
LD A, L
ADD A, 0x4
LD L, A
JP NC, .l3
CCF ; TODO: unused
.l3:
LD A, C
ADD A, L
LD C, A
JP NC, .l1
JP .l2
; ---------------------------------------------------
;
; ---------------------------------------------------
dc_draw_8px:
PUSH HL
PUSH DE
PUSH BC
PUSH DE
CALL dc_aspect_ratio_1
LD HL, (M_VARS.esc_param) ; HL=Y,X
CALL dc_draw_4px_bc
POP DE
CALL dc_aspect_ratio2
LD HL, (M_VARS.esc_param) ; HL=Y,X
CALL dc_draw_4px_cb
POP BC
POP DE
POP HL
XOR A
RET
; ---------------------------------------------------
; Scale circle axis dy specified aspect ratio
; if aspect_x = 0 C = D else C = D * aspect_x / 256
; if aspect_y = 0 B = E else B = E * aspect_y / 256
; ---------------------------------------------------
dc_aspect_ratio_1:
LD HL, (M_VARS.esc_param+3) ; aspect_x -> L, aspect_y -> H
LD A, L
OR A
LD C, D
LD B, E
JP NZ, .dc_ax_ne0
LD A, H
OR A
JP NZ, .dc_ay_ne0
RET
.dc_ax_ne0:
LD A, H
LD H, L
LD E, C
CALL dc_mul_e_h
LD C, E
OR A
RET Z
.dc_ay_ne0:
LD H, A
LD E, B
CALL dc_mul_e_h
LD B, E
RET
; ---------------------------------------------------
; if aspect_x = 0 B = E else B = E * aspect_x / 256
; if aspect_y = 0 C = D else C = D * aspect_y / 256
; ---------------------------------------------------
dc_aspect_ratio2:
LD HL, (M_VARS.esc_param+3) ; aspect_x -> L, aspect_y -> H
LD A, L
OR A
LD C, D
LD B, E
JP NZ, .dc_ax_ne0
LD A, H
OR A
JP NZ, .dc_ay_ne0
RET
.dc_ax_ne0:
LD A, H
LD H, L
LD E, B
CALL dc_mul_e_h
LD B, E
OR A
RET Z
.dc_ay_ne0:
LD H, A
LD E, C
CALL dc_mul_e_h
LD C, E
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
dc_mul_e_h:
LD D, 0x0
LD L, D
ADD HL, HL
JP NC, .l1
ADD HL, DE
.l1:
ADD HL, HL
JP NC, .l2
ADD HL, DE
.l2:
ADD HL, HL
JP NC, .l3
ADD HL, DE
.l3:
ADD HL, HL
JP NC, .l4
ADD HL, DE
.l4:
ADD HL, HL
JP NC, .l5
ADD HL, DE
.l5:
ADD HL, HL
JP NC, .l6
ADD HL, DE
.l6:
ADD HL, HL
JP NC, .l7
ADD HL, DE
.l7:
ADD HL, HL
JP NC, .l8
ADD HL, DE
.l8:
LD E, H
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
dc_draw_4px_bc:
; draw pixel(H+B, L+C) if in screen
LD A, H
ADD A, B
JP C, .l1
LD D, A
LD A, L
ADD A, C
LD E, A
CALL dc_put_pixel
.l1:
; draw pixel(H+B, L-C) if in screen
LD A, H
ADD A, B
JP C, .l2
LD D, A
LD A, L
SUB C
LD E, A
CALL dc_put_pixel
.l2:
; draw pixel(H-B, L-C) if in screen
LD A, H
SUB B
JP C, .l3
LD D, A
LD A, L
SUB C
LD E, A
CALL dc_put_pixel
.l3:
; draw pixel(H-B, L+C) if in screen
LD A, H
SUB B
RET C
LD D, A
LD A, L
ADD A, C
LD E, A
CALL dc_put_pixel ; TODO: replace call+ret to jp
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
dc_draw_4px_cb:
; draw pixel(H+C, L+B) if in screen
LD A, H
ADD A, C
JP C, .l1
LD D, A
LD A, L
ADD A, B
LD E, A
CALL dc_put_pixel
.l1:
; draw pixel(H+C, L-B) if in screen
LD A, H
ADD A, C
JP C, .l2
LD D, A
LD A, L
SUB B
LD E, A
CALL dc_put_pixel
.l2:
; draw pixel(H-C, L-B) if in screen
LD A, H
SUB C
JP C, .l3
LD D, A
LD A, L
SUB B
LD E, A
CALL dc_put_pixel
.l3:
; draw pixel(H-C, L+B) if in screen
LD A, H
SUB C
RET C
LD D, A
LD A, L
ADD A, B
LD E, A
CALL dc_put_pixel ; TODO: replace call+ret to jp
RET
; ---------------------------------------------------
; Draw pixel on screen
; Inp: DE - X, Y
; ---------------------------------------------------
dc_put_pixel:
RET C ; return if CF set (out of screen)
PUSH HL
PUSH BC
CALL calc_px_addr
; calculate B = pixel mask
LD A, 10000000b
.roll:
RLCA ; [07654321] <- [76547210], [7] -> CF
DEC B
JP P, .roll
CPL
LD B, A
; DE = foreground color low and hi bytes
EX DE, HL
LD HL, (M_VARS.curr_color)
EX DE, HL
; Turn on Video RAM
LD A, 0x1
OUT (SYS_DD17PB), A
; Load VRAM[HL] byte (low byte), mask and set
LD A, (HL)
XOR E
AND B
XOR E
LD (HL), A
; Load VRAM[HL+1] byte (low byte), mask and set
INC H
LD A, (HL)
XOR D
AND B
XOR D
LD (HL), A
; Turn off Video RAM
LD A, 0x0
OUT (SYS_DD17PB), A
POP BC
POP HL
RET
; Full charset, Common + RU letters (160*7=1120b)
INCLUDE "font-6x7.inc"
; ---------------------------------------------------
; Read hex value from serial interface
; Out: A - value
; ---------------------------------------------------
read_hex_serial:
PUSH BC
CALL m_serial_in
CALL hex_nibble
RLCA
RLCA
RLCA
RLCA
LD C, A
CALL m_serial_in
CALL hex_nibble
OR C
LD C, A
ADD A, D
LD D, A
LD A, C
POP BC
RET
; ---------------------------------------------------
; Convert digit 0..F to character '0'..'F'
; Inp: A - digit
; Out: A - character
; ---------------------------------------------------
hex_to_char:
AND 0xf
ADD A, 0x90
DAA
ADC A, 0x40
DAA
LD C, A
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
out_reg_value:
INC HL ; second value in register t
LD E, (HL)
LD D, HIGH M_VARS.stor_de ; DE -> 0xBFxx - var reg sto
INC HL
LD B, (HL)
INC HL
LD A, (DE) ; Load register value
CALL out_hex_byte
DEC B
RET M ; ret if single register
; print word register
DEC DE
LD A, (DE)
JP out_hex_byte
get_address:
CALL s_get_hex_addr
EX (SP), HL
PUSH HL
DEC C
JP NC, ga_word
JP NZ, reset_m_stack
RET
ga_word:
JP NZ, get_address
JP reset_m_stack
; ---------------------------------------------------
; Next HL address until DE
; Inp: HL -start address
; DE - end address
; Out: HL = HL + 1
; CF set if no more
; ---------------------------------------------------
next_hl_de:
INC HL
LD A, H
OR L
SCF
RET Z ; return if HL=0
LD A, E
SUB L
LD A, D
SBC A, H
RET
; ---------------------------------------------------
; Out hex word to screen
; Inp: HL - word to display
; ---------------------------------------------------
out_hex_word:
LD A, H
CALL out_hex_byte
LD A, L
; ---------------------------------------------------
; Out hex byte to screen
; Inp: A - byte to display
; ---------------------------------------------------
out_hex_byte:
PUSH AF
RRCA
RRCA
RRCA
RRCA
CALL out_hex_nibble
POP AF
; ---------------------------------------------------
;
; ---------------------------------------------------
out_hex_nibble:
CALL hex_to_char
JP get_key_out
; ---------------------------------------------------
;
; ---------------------------------------------------
s_get_hex_addr:
CALL get_key_with_check
JP Z, reset_m_stack
; ---------------------------------------------------
; Out: HL - address
; ---------------------------------------------------
hex_keys_to_addr:
LD HL, 0x0
cvt_next_hex:
LD B, A
CALL hex_nibble
JP C, non_hex_symb
; HL << 4
ADD HL, HL ; HL*2
ADD HL, HL ; HL*4
ADD HL, HL ; HL*8
ADD HL, HL ; HL*16
OR L
LD L, A
CALL handle_key_pressed
JP cvt_next_hex
non_hex_symb:
LD A, B
CALL check_sep_key
JP NZ, reset_m_stack ; jump if no separator key
RET
hex_nibble:
SUB '0'
RET C
ADD A, 233
RET C
ADD A, 6
JP P, .is_alpha
ADD A, 7
RET C
.is_alpha
ADD A, 10
OR A
RET
; ---------------------------------------------------
; Read key from keyboard with check for separator cha
; Out: A - key pressed, converted to Upper Case
; ZF set if sep or CR
; CF set if CR
; ---------------------------------------------------
get_key_with_check:
CALL handle_key_pressed
; ---------------------------------------------------
; Inp: A - key
; Out: ZF set - if ', ' or <CR> or <SP>
; CF set - if <CR>
; ---------------------------------------------------
check_sep_key:
CP ASCII_SP
RET Z
CP ','
RET Z
CP ASCII_CR
SCF
RET Z
CCF
RET
; ---------------------------------------------------
; Read key, reset stack if ESC. Print symbol to console
; Out: A - key code
; ---------------------------------------------------
handle_key_pressed:
PUSH BC
CALL m_con_in
CALL hex_to_upper
CP ASCII_ESC
JP Z, reset_m_stack
LD C, A
CALL m_con_out
LD A, C
POP BC
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
hex_to_upper:
CP 'a'
RET M
CP 155
RET P
AND 11011111b
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
m_rst1_handler:
DI
LD (M_VARS.store_hl), HL
LD HL, 0x2
ADD HL, SP
LD (M_VARS.stack_0), HL
POP HL
LD SP, M_VARS.stack_0
PUSH AF
LD A, 0x0
PUSH AF
LD A, 0x0
NOP
NOP
PUSH BC
PUSH DE
LD A, 0x0
NOP
NOP
LD (M_VARS.store_pc), HL
CALL get_cmd_letter
INC HL
CALL out_hex_word
JP m_cold_start
; ---------------------------------------------------
; G[addr] Run program from addr
; ---------------------------------------------------
cmd_G:
CALL get_key_with_check
JP Z, .sep
CALL hex_keys_to_addr
LD (M_VARS.store_pc), HL
.sep:
JP NC, reset_m_stack ; reset if unknown key
CALL get_a_ref_sp
LD A, JP_OPCODE ; JP
LD (M_VARS.start_jp), A
LD SP, M_VARS.stor_e
; restore registers and stack
POP DE
POP BC
POP AF
NOP
NOP
POP AF
POP HL
LD SP, HL
; restore HL and start code at specified address
LD HL, (M_VARS.store_hl)
JP M_VARS.start_jp
; ---------------------------------------------------
; W - Write RAM to tape
; ---------------------------------------------------
cmd_W:
CALL get_key_with_check
JP NC, reset_m_stack
CALL get_a_ref_sp
; ---------------------------------------------------
; Wtite RAM-Disk 64K to TAPE
; ---------------------------------------------------
m_tape_write_ram:
LD HL, M_VARS.buffer
LD C, 128
.cl_stack:
LD (HL), 0x0
INC HL
DEC C
JP NZ, .cl_stack
LD HL, M_VARS.buffer
LD DE, 0xffff
; write empty block
; DE - block ID
; HL -> block
CALL m_tape_write
CALL twr2_delay
LD DE, 0x0
CALL m_tape_write
CALL twr2_delay
LD BC, 512
LD DE, 0x0
.nxt_blk:
PUSH BC
LD HL, M_VARS.buffer
CALL m_ramdisk_read
INC DE
CALL m_tape_write
CALL twr2_delay
POP BC
DEC BC
LD A, B
OR C
JP NZ, .nxt_blk
RET
; ---------------------------------------------------
; Pause between blocks on tape
; ---------------------------------------------------
twr2_delay:
LD BC, 250
.delay:
DEC BC
LD A, B
OR C
JP NZ, .delay
RET
; ---------------------------------------------------
; R - Read from tape to RAM
; ---------------------------------------------------
cmd_R:
CALL get_key_with_check
JP NC, reset_m_stack
CALL get_a_ref_sp
; ---------------------------------------------------
; Read RAM-Disk 64K from TAPE
; ---------------------------------------------------
m_tape_read_ram:
LD A, 100
CALL m_tape_wait
OR A
JP NZ, .end
LD E, 6
.srch_first:
DEC E
JP Z, .not_found
; read block
LD HL, M_VARS.buffer
CALL m_tape_read
CP 4
JP Z, .end
OR A
JP NZ, .srch_first
LD A, B
OR C
JP NZ, .srch_first
LD BC, 512
LD DE, 0x0
.rd_next:
PUSH BC
; Read block from tape
CALL m_tape_read
OR A
JP NZ, .rd_error
DEC BC
LD A, B
CP D
JP NZ, .inv_id
LD A, C
CP E
JP NZ, .inv_id
; Ok, write block to RAM disk
CALL m_ramdisk_write
INC DE
POP BC
DEC BC
LD A, B
OR C
JP NZ, .rd_next
RET
.not_found:
LD HL, msg_no_start_rec
CALL me_out_strz ; TODO: replace call+ret to jp
RET
.rd_error:
CP 2
JP Z, .err_ubi
CP 4
JP Z, .err_ibu
LD HL, msg_checksum
CALL me_out_strz
CALL out_hexw
POP BC
RET
; Illegal sequence of blocks
.inv_id:
LD HL, msg_sequence
CALL me_out_strz
INC BC
CALL out_hexw
POP BC
RET
.err_ubi:
LD HL, msg_ibg
CALL me_out_strz
POP BC
RET
; Interrupted by user
.err_ibu:
POP BC
.end:
LD HL, msg_break
CALL me_out_strz ; TODO: replace call+ret to jp
RET
; --------------------------------------------------
; Output hex word
; Inp: BC - word to output
; --------------------------------------------------
out_hexw:
PUSH BC
LD A, B
CALL out_hex_byte
POP BC
LD A, C
CALL out_hex_byte ; TODO: replace call+ret to jp
RET
msg_no_start_rec:
DB "NO START RECORD", 0
msg_checksum:
DB "CHECKSUM ", 0
msg_sequence:
DB "SEQUENCE ", 0
msg_ibg:
DB "IBG", 0
msg_break:
DB "BREAK", 0
; ---------------------------------------------------
; Out ASCIIZ message
; Inp: HL -> zero ended string
; ---------------------------------------------------
me_out_strz:
LD A, (HL)
OR A
RET Z
PUSH BC
LD C, A
CALL m_con_out
INC HL
POP BC
JP me_out_strz
; ---------------------------------------------------
; Read from RAM-disk to RAM
; Inp: DE - source sector
; HL -> destination buffer
; ---------------------------------------------------
m_ramdisk_read:
PUSH HL
PUSH DE
LD A, D
; Build value to access ext RAM (A17, A16, 32k bits)
AND 00000001b ; Low 32K
OR 0x2 ; Set A16 address line
OR 0x0 ; TODO: nothing, remove
LD B, A ; B - value to turn on access to Ext RAM
; Calculate DE = address from sector number
XOR A
LD A, E ; E - low address
RRA ; [CF] -> [7:0] -> [CF]
LD D, A ; D = E/2
LD A, 0x0
RRA ; [CF] -> E
LD E, A
.read:
; Access to ExtRAM
LD A, B
OUT (SYS_DD17PB), A
; Get Byte
LD A, (DE)
LD C, A
; Access to RAM
LD A, 0x0
OUT (SYS_DD17PB), A
; Set Byte
LD (HL), C
; HL++, DE++
INC HL
INC DE
LD A, E
ADD A, A
JP NZ, .read ; jump if has more bytes
; Access to RAM
LD A, 0x0
OUT (SYS_DD17PB), A
POP DE
POP HL
RET
; ---------------------------------------------------
; Write sector to RAM disk
; Inp: HL -> source buffer
; DE - destination sector
; ---------------------------------------------------
m_ramdisk_write:
PUSH HL
PUSH DE
LD A, D
AND 0x1
OR 0x2 ; build value to access ext RAM (A16, 32k bits)
OR 0x0 ; TODO: remove unused
LD B, A
XOR A
LD A, E
RRA
LD D, A
LD A, 0x0
RRA
LD E, A
.wr_byte:
LD A, 0x0
OUT (SYS_DD17PB), A
LD C, (HL)
LD A, B
OUT (SYS_DD17PB), A
LD A, C
LD (DE), A
INC HL
INC DE
LD A, E
ADD A, A
JP NZ, .wr_byte
LD A, 0x0
OUT (SYS_DD17PB), A
POP DE
POP HL
RET
; --------------------------------------------------
; Write block to Tape
; Inp: DE - block ID,
; HL -> block of data.
; --------------------------------------------------
m_tape_write:
PUSH HL
PUSH DE
PUSH DE
LD BC, 2550
LD A, PIC_POLL_MODE ; pool mode
OUT (PIC_DD75RS), A
LD A,TMR0_SQWAVE ; tmr0, load lsb+msb, sq wave, bin
OUT (TMR_DD70CTR), A
LD A, C
OUT (TMR_DD70C1), A
LD A, B
OUT (TMR_DD70C1), A
; Write Hi+Lo, Hi+Lo
LD DE, 4 ; repeat next 4 times
.l1:
IN A, (PIC_DD75RS)
AND TIMER_IRQ ; check rst4 from timer#0
JP NZ, .l1
LD A, D
CPL
LD D, A
OR A
LD A, TL_HIGH ; tape level hi
JP NZ, .set_lvl
LD A, TL_LOW ; tape level low
.set_lvl:
OUT (DD67PC), A ; set tape level
LD A, TMR0_SQWAVE ; tmr0, load lsb+msb, swq, bin
; timer on
OUT (TMR_DD70CTR), A
LD A, C
OUT (TMR_DD70C1), A
LD A, B
OUT (TMR_DD70C1), A
DEC E
JP NZ, .l1
.l2:
IN A, (PIC_DD75RS)
AND TIMER_IRQ
JP NZ, .l2
; Write 00 at start
LD A, 0x0
CALL m_tape_wr_byte
; Write 0xF5 marker
LD A, 0xf5
CALL m_tape_wr_byte
LD E, 0x0 ; checksum=0
; Write block ID
POP BC
LD A, C
CALL m_tape_wr_byte
LD A, B
CALL m_tape_wr_byte
; Write 128 data bytes
LD B, 128
.next_byte:
LD A, (HL)
CALL m_tape_wr_byte
INC HL
DEC B
JP NZ, .next_byte
; Write checksum
LD A, E
CALL m_tape_wr_byte
; Write final zero byte
LD A, 0x0
CALL m_tape_wr_byte
.wait_end:
IN A, (PIC_DD75RS)
AND TIMER_IRQ
JP NZ, .wait_end
LD A, TL_MID ; tape level middle
OUT (DD67PC), A
POP DE
POP HL
RET
; ------------------------------------------------------
; Write byte to tape
; Inp: A - byte top write
; D - current level
; E - current checksum
; ------------------------------------------------------
m_tape_wr_byte:
PUSH BC
; calc checksum
LD B, A
LD A, E
SUB B
LD E, A
LD C, 8 ; 8 bit in byte
.get_bit:
LD A, B
RRA
LD B, A
JP C, .bit_hi
.wait_t:
IN A, (PIC_DD75RS)
AND TIMER_IRQ
JP NZ, .wait_t
LD A, TMR0_SQWAVE
OUT (TMR_DD70CTR), A
; program for 360 cycles
LD A, 0x68
OUT (TMR_DD70C1), A
LD A, 0x1
OUT (TMR_DD70C1), A
; change amplitude
LD A, D
CPL
LD D, A
OR A
LD A, TL_HIGH
JP NZ, .out_bit
LD A, TL_LOW
.out_bit:
OUT (DD67PC), A
DEC C
JP NZ,.get_bit
POP BC
RET
.bit_hi:
IN A, (PIC_DD75RS)
AND TIMER_IRQ
JP NZ, .bit_hi
; program for 660 cycles
LD A, TMR0_SQWAVE
OUT (TMR_DD70CTR), A
LD A, 0x94
OUT (TMR_DD70C1), A
LD A, 0x2
OUT (TMR_DD70C1), A
; change amplitude
LD A, D
CPL
LD D, A
OR A
LD A, TL_HIGH
JP NZ, .out_bit_hi
LD A, TL_LOW
.out_bit_hi:
OUT (DD67PC), A
DEC C
JP NZ, .get_bit
POP BC
RET
; ------------------------------------------------------
; Load block from Tape
; Inp: HL -> buffer to receive bytes from Tape
; Out: A = 0 - ok,
; 1 - CRC error,
; 2 - unexpected block Id
; 4 - key pressed
; ------------------------------------------------------
m_tape_read:
PUSH HL
PUSH DE
LD A, PIC_POLL_MODE ; pool mode
OUT (PIC_DD75RS), A
LD A, TMR0_SQWAVE
OUT (TMR_DD70CTR), A ; tmr0, load lsb+msb, sq wave
LD A, 0x0
; tmr0 load 0x0000
OUT (TMR_DD70C1), A
OUT (TMR_DD70C1), A
LD C, 3
.wait_3_changes:
CALL read_tape_bit_kbd
INC A
JP Z, .key_pressed
LD A, B
ADD A, 4
JP P, .wait_3_changes
DEC C
JP NZ, .wait_3_changes
.wait_4th_change:
CALL read_tape_bit_kbd
INC A
JP Z, .key_pressed
LD A, B
ADD A, 4
JP M, .wait_4th_change
LD C, 0x0
.wait_f5_marker:
CALL read_tape_bit_kbd
INC A
JP Z, .key_pressed
DEC A
RRA
LD A, C
RRA
LD C, A
CP 0xf5
JP NZ, .wait_f5_marker
LD E, 0x0 ; checksum = 0
; Read blk ID
CALL m_tape_read_byte
JP NC, .err_read_id
LD C, D
CALL m_tape_read_byte
JP NC, .err_read_id
LD B, D
PUSH BC
; Read block, 128 bytes
LD C, 128
.read_next_b:
CALL m_tape_read_byte
JP NC, .err_read_blk
LD (HL), D
INC HL
DEC C
JP NZ, .read_next_b
; Read checksum
CALL m_tape_read_byte
JP NC, .err_read_blk
LD A, E
OR A
JP Z, .checksum_ok
LD A, 0x1 ; bad checksum
.checksum_ok:
POP BC
.return:
POP DE
POP HL
RET
.err_read_blk:
POP BC
LD BC, 0x0
.err_read_id:
LD A, 0x2 ; read error
JP .return
.key_pressed:
CALL m_con_in
LD C, A ; store key code in C
LD B, 0x0
LD A, 0x4
JP .return
; ------------------------------------------------------
; Read byte from Tape
; Out: D - byte
; CF is set if ok, cleared if error
; ------------------------------------------------------
m_tape_read_byte:
PUSH BC
LD C, 8
.next_bit:
CALL m_read_tape_bit
; push bit from lo to hi in D
RRA
LD A, D
RRA
LD D, A
LD A, 4
ADD A, B
JP NC, .ret_err
DEC C
JP NZ, .next_bit
; calc checksum
LD A, D
ADD A, E
LD E, A
SCF
.ret_err:
POP BC
RET
; ------------------------------------------------------
; Read bit from tape
; Out: A - bit from tape
; B - time from last bit
; ------------------------------------------------------
m_read_tape_bit:
IN A, (KBD_DD78PB) ; Read Tape bit 5 (data)
AND TAPE_P
LD B, A
.wait_change:
IN A, (KBD_DD78PB)
AND TAPE_P
CP B
JP Z, .wait_change
LD A, TMR0_SQWAVE
OUT (TMR_DD70CTR), A
; [360...480...660] 0x220=544d
IN A, (TMR_DD70C1) ; get tmer#0 lsb
ADD A, 0x20
IN A, (TMR_DD70C1) ; get tmer#0 msb
LD B, A
ADC A, 0x2
; reset timer to 0
LD A, 0x0
OUT (TMR_DD70C1), A
OUT (TMR_DD70C1), A
; For 0 - 65535-360+544 -> overflow P/V=1
; For 1 - 65535-660+544 -> no overflow P/V=0
RET P
INC A
RET
; ------------------------------------------------------
; Read bit from tape with keyboard interruption
; Out: A - bit from tape
; B - time from last bit
; ------------------------------------------------------
read_tape_bit_kbd:
IN A, (KBD_DD78PB)
AND TAPE_P
LD B, A ; save tape bit state
; wait change with keyboard check
.wait_change:
IN A, (PIC_DD75RS)
AND KBD_IRQ
JP NZ, .key_pressed
IN A, (KBD_DD78PB)
AND TAPE_P
CP B
JP Z, .wait_change
; measure time
LD A, TMR0_SQWAVE
OUT (TMR_DD70CTR), A
; read lsb+msb
IN A, (TMR_DD70C1)
ADD A, 0x20
IN A, (TMR_DD70C1)
LD B, A
ADC A, 0x2
; reset timer#0
LD A, 0x0
OUT (TMR_DD70C1), A
OUT (TMR_DD70C1), A
; flag P/V is set for 0
RET P
INC A
RET
.key_pressed:
LD A, 0xff
RET
; ------------------------------------------------------
; Wait tape block
; Inp: A - periods to wait
; Out: A=4 - interrupded by keyboard, C=key
; ------------------------------------------------------
m_tape_wait:
OR A
RET Z
PUSH DE
LD B, A
.wait_t4:
LD C,B
IN A, (KBD_DD78PB)
AND TAPE_P ; Get TAPE4 (Wait det) and save
LD E, A ; store T4 state to E
.wait_next_2ms:
LD A,TMR0_SQWAVE
OUT (TMR_DD70CTR), A
; load 3072 = 2ms
XOR A
OUT (TMR_DD70C1), A
LD A, 0xc
OUT (TMR_DD70C1), A
.wait_tmr_key:
IN A, (PIC_DD75RS)
AND KBD_IRQ ; RST1 flag (keyboard)
JP NZ, .key_pressed
IN A, (PIC_DD75RS)
AND TIMER_IRQ ; RST4 flag (timer out)
JP Z, .wait_no_rst4
IN A, (KBD_DD78PB)
AND TAPE_P ; TAPE4 not changed?
CP E
JP NZ, .wait_t4 ; continue wait
JP .wait_tmr_key
.wait_no_rst4:
DEC C
JP NZ, .wait_next_2ms
XOR A
POP DE
RET
.key_pressed:
CALL m_con_in
LD C, A ; C = key pressed
LD A, 0x4 ; a=4 interrupted by key
POP DE
RET
; ------------------------------------------------------
; Check block marker from Tape
; Out: A=0 - not detected, 0xff - detected
; ------------------------------------------------------
m_tape_blk_detect:
IN A, (KBD_DD78PB)
AND TAPE_D ; TAPE5 - Pause detector
LD A, 0x0
RET Z
CPL
RET
; ======================================================
; FDC DRIVER
; ======================================================
fdc_unload_head:
LD A,0x0
OUT (FDC_DATA),A
LD A,0x3
OUT (FDC_CMD),A
NOP
NOP
fuh.wait_no_busy:
IN A,(FDC_CMD)
AND 0x5 ; TR0. BYSY
CP 0x4 ;
JP Z,fuh.tr0_ok
IN A,(FLOPPY)
RLCA ; MOT_ST -> CF
JP NC,fuh.wait_no_busy
LD A,0x20
RET
fuh.tr0_ok:
LD A,0x1
LD (M_VARS.ul_var1),A
XOR A
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
m_select_drive:
CALL delay_1.4mS
CP 0x1
JP Z, .sel_a
LD A, 0x2
JP .sel_b
.sel_a:
LD A, 0x5
.sel_b:
LD B, A
IN A, (FLOPPY)
AND 0x40
RRA
OR B
OUT (FLOPPY), A
LD B, A
LD A, D
CP 0x28
JP C, .l3
SUB 0x28
LD D, A
LD A, C
OR 0x8
LD C, A
LD A, B
AND 0x20
OR A
RET NZ
LD A, B
OR 0x20
OUT (FLOPPY), A
CALL delay_136uS
RET
.l3:
LD A, B
AND 0x20
OR A
RET Z
LD A, B
AND 0x7
OUT (FLOPPY), A
CALL delay_136uS
RET
; ---------------------------------------------------
; Delay for 136uS
; ---------------------------------------------------
delay_136uS:
LD B, 16 ; 7
; ---------------------------------------------------
; Delay for B*8uS
; ---------------------------------------------------
delay_b:
DEC B ; 4
JP NZ, delay_b ; 10
RET ; 10
; ---------------------------------------------------
; Delay for 1.4mS
; ---------------------------------------------------
delay_1.4mS:
LD B, 175 ; 7
JP delay_b ; 10
; ---------------------------------------------------
;
; ---------------------------------------------------
m_read_floppy:
CALL m_select_drive
CALL m_start_seek_track
JP C, fdc_ret
CALL m_fdc_read_c_bytes
JP C, fdc_ret
XOR A
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
m_write_floppy:
CALL m_select_drive
CALL m_start_seek_track
JP C, fdc_ret
CALL m_fdc_write_bytes
JP C, fdc_ret
XOR A
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
m_start_seek_track:
CALL m_start_floppy
RET C
CALL m_fdc_seek_trk
RET C
RET ; TODO: remove
; ---------------------------------------------------
;
; ---------------------------------------------------
m_start_floppy:
IN A, (FLOPPY)
RLCA
JP C, .wait_motor_st
IN A, (FDC_CMD)
AND 0x80
RET Z
.wait_motor_st:
PUSH BC
LD BC, 64000
CALL fdc_init
.wait_rdy1:
IN A, (FDC_CMD)
AND 0x80
JP Z, .long_delay
IN A, (FLOPPY)
RLCA
JP NC, .wait_rdy1
LD A, 0x20
JP .mot_st_exit
.long_delay:
DEC C
JP NZ, .long_delay
DEC B
JP NZ, .long_delay
XOR A
.mot_st_exit:
POP BC
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
fdc_init:
IN A, (FLOPPY)
AND 01001110b ; Get SSEL, DRSEL, MOT1, MOT0
RRA
OUT (FLOPPY), A
OR 0x08 ; Set INIT bit
OUT (FLOPPY), A
RET
; ---------------------------------------------------
; Seek track on floppy
; Inp: DE - track/sector
; ---------------------------------------------------
m_fdc_seek_trk:
LD A, (M_VARS.ul_var1)
AND 0x1
CALL Z, fdc_unload_head
LD A, D
OUT (FDC_DATA), A
LD A, 0x1f
OUT (FDC_CMD), A
NOP
NOP
IN A, (FDC_WAIT)
IN A, (FDC_CMD)
AND ASCII_EM
CP 0x0
JP NZ, .l1
JP .l2
.l1:
LD A, D
OUT (FDC_DATA), A
LD A, 0x2f
OUT (FDC_CMD), A
NOP
NOP
IN A, (FDC_WAIT)
IN A, (FDC_CMD)
AND ASCII_EM
CP 0x0
JP Z, .l2
SCF
LD A, 0x40
.l2:
PUSH AF
LD A, E
OUT (FDC_SECT), A
POP AF
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
m_fdc_write_bytes:
LD A, C
OUT (FDC_CMD), A
.w_next:
IN A, (FDC_WAIT)
RRCA
LD A, (HL)
OUT (FDC_DATA), A
INC HL
JP C, .w_next
CALL fdc_check_status ; TODO: replace call+ret to jp
RET
; ---------------------------------------------------
;
; ---------------------------------------------------
m_fdc_read_c_bytes:
LD A, C
OUT (FDC_CMD), A
JP .l2
.l1:
LD (HL), A
INC HL
.l2:
IN A, (FDC_WAIT)
RRCA
IN A, (FDC_DATA)
JP C, .l1
CALL fdc_check_status ; TODO: replace call+ret to jp
RET
; ---------------------------------------------------
; Check fdc status for errors
; Out: CF set if errors
; ---------------------------------------------------
fdc_check_status:
IN A,(FDC_CMD)
AND 11011111b
CP 0x0
JP Z,fdc_ret
IN A,(FDC_CMD)
CP 0x80
LD C,0x80
JP Z,fcs_error
CP 0x40
LD C,0x3
JP Z,fcs_error
CP 0x10
LD C,0x4
JP Z,fcs_error
CP 0x8
LD C,0x9
JP Z,fcs_error
LD C,0x10
fcs_error:
SCF
LD A,C
fdc_ret:
RET
DB "\r\n DRIVE IS NOT READY \r\n", 0, "I"
; ------------------------------------------------------
LAST EQU $
CODE_SIZE EQU LAST-0xe000
FILL_SIZE EQU ROM_CHIP_SIZE-CODE_SIZE
ASSERT m_start = 0xe036
ASSERT conf_uart = 0xe08c
ASSERT conf_pic = 0xe09f
ASSERT jump_bios = 0xe0d6
ASSERT m_out_strz = 0xe0e7
ASSERT m_cold_start = 0xe10c
ASSERT registers_tab = 0xe27e
ASSERT m_char_print = 0xe2e8
ASSERT m_con_out = 0xe307
ASSERT m_con_out_int = 0xe311
ASSERT get_esc_param = 0xe32b
ASSERT esc_params_tab = 0xe3ae
ASSERT esc_set_beep = 0xe3dd
ASSERT esc_print_screen = 0xe3fb
ASSERT m_print_hor_line = 0xe424
ASSERT m_get_7vpix = 0xe49e
ASSERT esc_set_palette = 0xe4e8
ASSERT m_get_glyph = 0xe50a
ASSERT m_print_no_esc = 0xe533
ASSERT calc_addr_40 = 0xe6b2
ASSERT mp_mode_64 = 0xe72e
ASSERT scroll_up = 0xe777
ASSERT mp_mode_80 = 0xe7c2
ASSERT m80_rt = 0xe85d
ASSERT calc_addr_80 = 0xe8a0
ASSERT m_clear_screen = 0xe900
ASSERT m_cursor_home = 0xe933
ASSERT m_draw_cursor = 0xe961
ASSERT m_handle_esc_code = 0xeb04
ASSERT handle_cc_common = 0xeb4c
ASSERT handle_cc_mono = 0xeb87
ASSERT handle_cc_80x25 = 0xebce
ASSERT m_beep = 0xebf5
ASSERT esc_set_cursor = 0xec2b
ASSERT esc_set_vmode = 0xec8b
ASSERT esc_set_color = 0xecbc
ASSERT m_print_at_xy = 0xecd0
ASSERT calc_px_addr = 0xed4b
ASSERT esc_draw_fill_rect = 0xed5e
ASSERT esc_draw_line = 0xedf7
ASSERT esc_draw_dot = 0xef3e
ASSERT esc_draw_circle = 0xef62
ASSERT dc_put_pixel = 0xf0a8
ASSERT get_key_with_check = 0xf5ce
ASSERT m_tape_write_ram = 0xf654
ASSERT m_tape_read_ram = 0xf6a4
ASSERT m_ramdisk_read = 0xf76a
ASSERT m_ramdisk_write = 0xf794
ASSERT m_tape_write = 0xf7be
ASSERT m_tape_wr_byte = 0xf835
ASSERT m_tape_read = 0xf88e
ASSERT m_read_tape_bit = 0xf92f
ASSERT m_tape_wait = 0xf97f
ASSERT m_select_drive = 0xf9e8
ASSERT m_read_floppy = 0xfa36
ASSERT m_write_floppy = 0xfa47
ASSERT m_start_floppy = 0xfa61
ASSERT fdc_init = 0xfa90
ASSERT m_fdc_seek_trk = 0xfa9c
ASSERT m_fdc_write_bytes = 0xfad8
ASSERT m_fdc_read_c_bytes = 0xfae9
ASSERT fdc_check_status = 0xfafd
;DISPLAY "m_handle_esc_code: ", /H, m_handle_esc_code
FILLER
DS FILL_SIZE, 0xFF
DISPLAY "Free size is: ", /D, FILL_SIZE, " bytes."
ENDMODULE
OUTEND
OUTPUT m_vars.bin
; put in separate waste file
INCLUDE "m_vars.inc"
OUTEND