2020-11-23 08:47:23 +01:00
; Pat80 Memory Monitor
; @author Daniele Verducci
;
; Monitor commands (CMD $arg):
2020-11-25 08:53:41 +01:00
; H (HELP) Shows available commands
2020-12-18 08:50:24 +01:00
; D (DUMP) $pos Dumps bytes of memory starting at $pos
2020-11-25 08:53:41 +01:00
; S (SET) $pos $val Replaces byte at $pos with $val
2020-12-06 15:51:26 +01:00
; L (LOAD) $pos $val
2020-11-25 08:53:41 +01:00
; R (RUN) $pos Starts executing code from $pos
2020-12-15 17:34:50 +01:00
; A (ADB) Enters in Assembly Depoy Bridge mode: loads all the incoming bytes in application memory and starts executing.
2020-11-25 08:53:41 +01:00
; The commands are entered with a single letter and the program completes the command
2020-11-23 08:47:23 +01:00
2020-11-25 19:39:20 +01:00
include 'libs/strings.asm'
2020-11-23 08:47:23 +01:00
; CONSTANTS
2020-12-17 20:34:38 +01:00
MON_WELCOME: DB 10 , "PAT80 MEMORY MONITOR 0.2" , 10 , 0
2020-11-25 08:53:41 +01:00
MON_COMMAND_HELP: DB "HELP" , 0 ; null terminated strings
2020-11-25 19:39:20 +01:00
MON_COMMAND_DUMP: DB "DUMP" , 0
2020-11-25 08:53:41 +01:00
MON_COMMAND_SET: DB "SET" , 0
2020-12-26 12:39:18 +01:00
MON_COMMAND_ZERO: DB "ZERO" , 0
2020-11-25 08:53:41 +01:00
MON_COMMAND_LOAD: DB "LOAD" , 0
MON_COMMAND_RUN: DB "RUN" , 0
2020-12-15 17:34:50 +01:00
MON_COMMAND_ADB: DB "ADB" , 0
2021-01-02 10:53:30 +01:00
MON_COMMAND_QUIT: DB "QUIT" , 0
2020-11-25 20:50:39 +01:00
MON_ARG_HEX: DB " 0x" , 0
2021-01-02 10:53:30 +01:00
MON_HELP: DB 10 , "Available commands:\nHELP prints this message\nDUMP [ADDR] shows memory content\nSET [ADDR] sets memory content\nZERO [ADDR] [ADDR] sets all bytes to 0 in the specified range\nLOAD\nRUN [ADDR] executes code starting from ADDR\nADB starts Assembly Deploy Bridge\nQUIT exits" , 0
2020-12-15 17:34:50 +01:00
MON_MSG_ADB: DB 10 , "Waiting for data." , 0
2020-11-25 19:39:20 +01:00
MON_ERR_SYNTAX: DB " Syntax error" , 0
2020-12-16 08:49:28 +01:00
;MON_ADB_TIMEOUT: EQU 0xFF // Number of cycles after an ADB binary transfer is considered completed
2020-12-21 18:28:09 +01:00
MON_DUMP_BYTES_LINES: EQU 8
MON_DUMP_BYTES_PER_LINE: EQU 8
2020-11-23 08:47:23 +01:00
Monitor_main:
2020-11-25 08:53:41 +01:00
; Print welcome string
ld bc , MON_WELCOME
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-11-25 08:53:41 +01:00
monitor_main_loop:
2020-11-25 19:39:20 +01:00
; Newline
ld a , 10
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-11-25 08:53:41 +01:00
; Draw prompt char
ld a , 62 ; >
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-11-25 08:53:41 +01:00
; Read char from command line
2020-12-29 23:28:30 +01:00
call Sys_Readc ; blocking: returns when a character was read and placed in A reg
2020-11-25 19:39:20 +01:00
call Strings_charToUpper ; user may enter lowercase char: transform to upper
2020-12-29 23:28:30 +01:00
call Sys_Printc ; Print back the character to provide user feedback
2020-11-25 08:53:41 +01:00
; Switch case
2020-11-25 19:39:20 +01:00
ld hl , MON_COMMAND_HELP
cp ( hl ) ; check incoming char is equal to command's first char
2020-11-25 08:53:41 +01:00
jp z , monitor_help
2020-11-25 19:39:20 +01:00
ld hl , MON_COMMAND_DUMP
cp ( hl )
2020-11-25 08:53:41 +01:00
jp z , monitor_dump
2020-11-25 19:39:20 +01:00
ld hl , MON_COMMAND_SET
cp ( hl )
2020-11-25 08:53:41 +01:00
jp z , monitor_set
2020-12-26 12:39:18 +01:00
ld hl , MON_COMMAND_ZERO
cp ( hl )
jp z , monitor_zero
2020-11-25 19:39:20 +01:00
ld hl , MON_COMMAND_LOAD
cp ( hl )
2020-11-25 08:53:41 +01:00
jp z , monitor_load
2020-11-25 19:39:20 +01:00
ld hl , MON_COMMAND_RUN
cp ( hl )
2020-11-25 08:53:41 +01:00
jp z , monitor_run
2020-12-15 17:34:50 +01:00
ld hl , MON_COMMAND_ADB
2020-11-25 21:07:46 +01:00
cp ( hl )
2020-12-15 17:34:50 +01:00
jp z , monitor_adb
2021-01-02 10:53:30 +01:00
ld hl , MON_COMMAND_QUIT
cp ( hl )
jp z , monitor_quit
2020-12-06 15:51:26 +01:00
; Unrecognized command: print error and beep
2020-11-25 19:39:20 +01:00
ld bc , MON_ERR_SYNTAX
2020-12-29 23:28:30 +01:00
call Sys_Print
call Sys_Beep
2020-11-25 08:53:41 +01:00
jp monitor_main_loop
monitor_help:
ld bc , MON_COMMAND_HELP + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-11-25 08:53:41 +01:00
ld bc , MON_HELP
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-11-25 19:39:20 +01:00
jp monitor_main_loop
2020-11-25 08:53:41 +01:00
2021-01-02 10:53:30 +01:00
monitor_quit:
ld bc , MON_COMMAND_QUIT + 1 ; autocomplete command
call Sys_Print
; newline
ld a , 10
call Sys_Printc
2021-01-03 09:37:22 +01:00
; Restores registers and re-enable interrupts: when the BREAK key is pressed,
; a maskable interrupt is generated and the CPU jumps to 0x38 reset vector,
; where if finds a call to Memory monitor (see main.asm).
exx ; exchange registers
ex af , af '
; enable interrupts
ei
im 1 ; set interrupt mode 1 (on interrupt jumps to 0x38)
2021-01-02 10:53:30 +01:00
reti ; return from interrupt
2020-12-21 23:12:33 +01:00
; Asks the user for a memory position and shows the following 64 bytes of memory
; @uses a, b, c, d, e, h, l
monitor_dump:
2020-11-25 08:53:41 +01:00
ld bc , MON_COMMAND_DUMP + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-12-17 20:34:38 +01:00
; Now read the address from the user
2020-12-16 23:39:24 +01:00
call monitor_arg_2byte ; returns the read bytes in hl
2020-12-17 20:34:38 +01:00
ld a , 10 ; newline
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-17 20:34:38 +01:00
; now start displaying bytes from memory
ld e , MON_DUMP_BYTES_LINES ; the number of lines to display
monitor_dump_show_bytes_loop:
2020-12-21 23:12:33 +01:00
ld d , MON_DUMP_BYTES_PER_LINE * 2 ; the number of bytes per line to display (*2 as we display two times the same byte: once hex and once ascii)
2020-12-17 20:38:36 +01:00
; Print current address
ld a , h
call monitor_printHexByte
ld a , l
call monitor_printHexByte
2020-12-21 23:12:33 +01:00
; print four spaces
2020-12-17 20:38:36 +01:00
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
call Sys_Printc
call Sys_Printc
call Sys_Printc
2020-12-21 23:12:33 +01:00
monitor_dump_show_bytes_line_loop: ; counts down from 15 to 0
ld a , d
sub MON_DUMP_BYTES_PER_LINE + 1
jp m , monitor_dump_show_bytes_line_loop_ascii ; jp if
; if position is 8 to 15, print hex value at mem position
ld a , ( hl )
; print hex byte
call monitor_printHexByte
; print space
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-21 23:12:33 +01:00
; if position is 4, print a second space (to group nibbles)
ld a , d
cp MON_DUMP_BYTES_PER_LINE / 2 + MON_DUMP_BYTES_PER_LINE + 1
jp nz , no_second_space
; print second space
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-21 23:12:33 +01:00
no_second_space:
; move to next mem position
inc hl
; decrement "nth byte on the line" counter
dec d
jp monitor_dump_show_bytes_line_loop
; if position is 0 to 7, print ascii
monitor_dump_show_bytes_line_loop_ascii:
; is this the first ascii char printed in this line?
ld a , d
cp MON_DUMP_BYTES_PER_LINE
jp nz , no_mempos_decr ; no need to decrement, already done
; do this only once: printing hex values we advanced the counter by 8 positions. Bring it back.
ld bc , MON_DUMP_BYTES_PER_LINE
sbc hl , bc
; print 3 spaces to separate hex from ascii
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
call Sys_Printc
call Sys_Printc
2020-12-21 23:12:33 +01:00
no_mempos_decr:
; print ascii
ld a , ( hl )
call monitor_printAsciiByte
; print space
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-21 23:12:33 +01:00
; if position is 12 (8+4), print a second space (to group nibbles)
ld a , d
cp MON_DUMP_BYTES_PER_LINE / 2 + 1
jp nz , no_second_space2
; print second space
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-21 23:12:33 +01:00
no_second_space2:
; move to next mem position
inc hl
; decrement counter: if non zero continue loop
dec d
jp nz , monitor_dump_show_bytes_line_loop
2020-12-17 20:34:38 +01:00
; print newline
ld a , 10
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-17 20:34:38 +01:00
; decrement line counter
dec e
jp nz , monitor_dump_show_bytes_loop ; if line counter is not 0, print another line
; if line counter 0, finished
2020-11-25 19:39:20 +01:00
jp monitor_main_loop
2020-11-25 08:53:41 +01:00
2020-12-26 08:35:49 +01:00
; Asks user for a memory position and a byte and puts the byte in memory
; @uses a, b, c, h, l
2020-11-25 08:53:41 +01:00
monitor_set:
ld bc , MON_COMMAND_SET + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-12-18 08:50:24 +01:00
; Now read the memory address to be changed from the user
call monitor_arg_2byte ; returns the read bytes in hl
; Start looping memory addresses
monitor_set_byte_loop:
2020-12-26 08:35:49 +01:00
ld a , 10 ; newline
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-18 08:50:24 +01:00
; Print current address
ld a , h
call monitor_printHexByte
ld a , l
call monitor_printHexByte
; print two spaces
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
call Sys_Printc
2020-12-18 08:50:24 +01:00
; print previous memory content (hex)
ld a , ( hl )
call monitor_printHexByte
2020-12-26 08:35:49 +01:00
; print two spaces
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
call Sys_Printc
2020-12-18 08:50:24 +01:00
; print previous memory content (ascii)
ld a , ( hl )
call monitor_printAsciiByte
; print space
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-18 08:50:24 +01:00
; ask the user the new memory content
2020-12-26 08:35:49 +01:00
call monitor_arg_byte ; returns the read byte in a, exit code in b
; find if user pressed Q/ENTER
ld c , a ; save a
ld a , b ; exit code in a
cp 1 ; check if user pressed Q
jp z , monitor_main_loop ; user wants to exit
ld a , b
cp 2 ; check if user pressed ENTER
jp z , monitor_set_skipbyte ; user doesn't want to replace current byte: skip
; user didn't press Q/ENTER: he inserted a valid byte
; print two spaces
ld a , 32
2020-12-29 23:28:30 +01:00
call Sys_Printc
call Sys_Printc
2020-12-26 08:35:49 +01:00
ld a , c ; restore valid byte in a
call monitor_printAsciiByte ; print user-inserted byte in ascii
ld a , c ; restore valid byte in a
2020-12-18 08:50:24 +01:00
ld ( hl ), a ; write new byte to memory
2020-12-26 08:35:49 +01:00
monitor_set_skipbyte:
2020-12-18 08:50:24 +01:00
inc hl ; next memory position
2020-12-26 08:35:49 +01:00
jp monitor_set_byte_loop
2020-11-23 08:47:23 +01:00
2020-12-26 12:39:18 +01:00
; Asks user for a memory range and sets all bytes to zero in that range in memory
; @uses a, b, c, h, l
monitor_zero: ; TODO: bugged, doesn't exit cycle
ld bc , MON_COMMAND_ZERO + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-12-26 12:39:18 +01:00
; Now read the starting memory address
call monitor_arg_2byte ; returns the read bytes in hl
; starting addr in bc
ld b , h
ld c , l
call monitor_arg_2byte ; ending addr in hl
; Start looping memory addresses (from last to first)
monitor_zero_loop:
ld ( hl ), 0 ; set byte to 0 in memory
dec hl ; next byte
; check if we reached start addr (one byte at time)
ld a , b
cp h
jp nz , monitor_zero_loop ; first byte is different, continue loop
; first byte is equal, check second one
ld a , c
cp l
jp nz , monitor_zero_loop ; second byte is different, continue loop
; reached destination addr: zero the last byte and return
ld ( hl ), 0 ; set byte to 0 in memory
ret
2020-11-25 08:53:41 +01:00
monitor_load:
ld bc , MON_COMMAND_LOAD + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2021-01-02 10:53:30 +01:00
; TODO: When implemented, re-enable interrupts before run application
2020-11-25 19:39:20 +01:00
jp monitor_main_loop
2020-11-25 08:53:41 +01:00
monitor_run:
ld bc , MON_COMMAND_RUN + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2021-01-03 09:37:22 +01:00
; Now read the memory address to be executed from the user
2020-12-21 18:28:09 +01:00
call monitor_arg_2byte ; returns the read bytes in hl
ld a , 10 ; newline
2021-01-03 09:37:22 +01:00
call Sys_Printc
; enable interrupts
ei
im 1 ; set interrupt mode 1 (on interrupt jumps to 0x38)
; pop the last entry on the stack: this is needed (as the monitor
; runs in an interrupt) to counter-balance the missing reti statement
pop bc
; execute code
jp ( hl )
2020-11-25 21:07:46 +01:00
2020-12-15 17:34:50 +01:00
monitor_adb:
ld bc , MON_COMMAND_ADB + 1 ; autocomplete command
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-11-25 21:07:46 +01:00
; start copying incoming data to application space
2020-12-09 21:01:57 +01:00
call monitor_copyTermToAppMem
2021-01-02 10:53:30 +01:00
; call monitor_enable_int ; re-enable interrupts
2020-12-16 08:49:28 +01:00
;jp APP_SPACE ; Start executing code
2021-01-02 10:53:30 +01:00
2021-01-01 22:42:00 +01:00
; ld bc, APP_SPACE
; call Sys_Print
2020-12-16 08:49:28 +01:00
jp monitor_main_loop
2020-11-25 08:53:41 +01:00
2020-12-16 23:39:24 +01:00
; Prints "0x" and read 1 hex byte (2 hex digits, e.g. 0x8C)
2020-12-26 08:35:49 +01:00
; Can be cancelled with Q/ENTER
; @return a the read byte, b the exit code (0=valid byte in a, 1=Q, 2=ENTER)
2020-12-16 23:39:24 +01:00
; @uses a, b, c
2020-11-25 20:50:39 +01:00
monitor_arg_byte:
; Print 0x... prompt
ld bc , MON_ARG_HEX
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-12-16 23:39:24 +01:00
; Read 2 digits
call monitor_arg_byte_impl
2020-11-25 20:50:39 +01:00
ret
2020-12-16 23:39:24 +01:00
; Prints "0x" and reads 2 hex bytes (4 hex digits e.g. 0x3F09)
2020-12-26 08:35:49 +01:00
; Ignores Q/ENTER keys
2020-12-16 23:39:24 +01:00
; @return hl the two read bytes
; @uses a, b, c, h, l
2020-11-25 20:50:39 +01:00
monitor_arg_2byte:
; Print 0x... prompt
ld bc , MON_ARG_HEX
2020-12-29 23:28:30 +01:00
call Sys_Print
2020-12-16 23:39:24 +01:00
; Read 2 digits
call monitor_arg_byte_impl
ld h , a ; move result to h
; Read 2 digits
call monitor_arg_byte_impl
ld l , a ; move result to l
ret
; Read 2 hex digits
2020-12-26 08:35:49 +01:00
; @return a the read byte, b the exit code
; (0 if no control key was, pressed, 1 for Q, 2 for RETURN)
2020-12-16 23:39:24 +01:00
; @uses a, b, c
monitor_arg_byte_impl:
2020-12-26 08:35:49 +01:00
; Receive first hex digit. Value in a, exit code in b
2020-11-25 20:50:39 +01:00
call monitor_readHexDigit
2020-12-26 08:35:49 +01:00
; check exit code to find if user pressed esc or return
ld c , a ; save a
ld a , b ; load exit code in a
cp 0
jp nz , monitor_arg_byte_impl_exitcode ; user pressed Q/RETURN key
; user didn't press Q/RETURN: returned nibble is valid
ld a , c ; restore a and discard c
2020-12-18 08:50:24 +01:00
; First hex digit is the most signif nibble, so rotate left by 4 bits
2020-12-26 08:35:49 +01:00
rlca
rlca
rlca
rlca
2020-12-18 08:50:24 +01:00
; the lower nibble must now be discarded
and % 11110000
2020-12-16 23:39:24 +01:00
ld c , a ; save shifted nibble in c
; Read second hex digit
2020-11-25 20:50:39 +01:00
call monitor_readHexDigit
2020-12-16 23:39:24 +01:00
; Join the two nibbles in a single byte: second digit is already in a,
; so we OR with the previously shifted c and obtain the complete byte in a.
or c
2020-11-25 20:50:39 +01:00
ret
2020-12-26 08:35:49 +01:00
monitor_arg_byte_impl_exitcode:
; user pressed Q/RETURN key. Exit code is now in a.
ld b , a ; move exit code in b
ld a , 0 ; clear a
ret
2020-12-09 21:01:57 +01:00
; Reads an hex digit (0 to 9, A to F)
2020-12-26 08:35:49 +01:00
; @return a the read nibble (or 0 if Q/RETURN was pressed), b the exit code
; (0 if no control key was, pressed, 1 for Q, 2 for RETURN)
2020-12-16 23:39:24 +01:00
; @uses a, b
2020-11-25 20:50:39 +01:00
monitor_readHexDigit:
2020-12-29 23:28:30 +01:00
call Sys_Readc
2020-12-26 08:35:49 +01:00
; check if user pressed Q
; if user pressed Q, return exit code 1 in b and 0 in a
cp 81
jp z , monitor_readHexDigit_esc
; check if user pressed RETURN
; if user pressed RETURN, return exit code 2 in b and 0 in a
cp 10
jp z , monitor_readHexDigit_return
2020-11-25 20:50:39 +01:00
; check if is a valid hex digit (0-9 -> ascii codes 48 to 57; A-F -> ascii codes 65 to 70)
; first check if is between 0 and F(ascii codes 48 to 70)
ld b , a
sub a , 48
jp m , monitor_readHexDigit ; if negative (s), ascii code is under 48: ignore char
ld a , b
sub a , 71 ; 71 because we want to include 70 and the result must be negative
jp p , monitor_readHexDigit ; if not negative (ns), ascii code is over 70: ignore it
; check if is a valid int (<=57)
ld a , b
sub a , 58
jp p , monitor_readHexDigit_char ; if not negative (ns), maybe is a char
; otherwise is a number! First print for visive feedback
ld a , b
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-11-25 20:50:39 +01:00
; then convert to its value subtracting 48
sub a , 48
2020-12-26 08:35:49 +01:00
ld b , 0 ; set b to exit code 0 to represent "valid value in a"
2020-11-25 20:50:39 +01:00
ret
monitor_readHexDigit_char:
; check if is A, B, C, D, E, F (ascii codes 65 to 70). We already checked it is less than 70.
ld a , b
sub a , 65
jp m , monitor_readHexDigit ; if negative (s), ascii code is under 65: ignore char
; otherwise is a valid char (A-F). Print for visive feedback
ld a , b
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-11-25 20:50:39 +01:00
; Its numeric value is 10 (A) to 15 (F). To obtain this, subtract 55.
sub a , 55
2020-12-26 08:35:49 +01:00
ld b , 0 ; set b to exit code 0 to represent "valid value in a"
2020-11-25 20:50:39 +01:00
ret
2020-11-25 08:53:41 +01:00
2020-12-26 08:35:49 +01:00
monitor_readHexDigit_esc:
ld a , 0
ld b , 1
ret
monitor_readHexDigit_return:
ld a , 0
ld b , 2
ret
2020-12-17 13:52:28 +01:00
; Prints a byte in hex format: splits it in two nibbles and prints the two hex digits
2020-12-26 08:35:49 +01:00
; NOTE: The byte in a will be modified!
2020-12-17 13:52:28 +01:00
; @param a the byte to print
; @uses a, b, c
monitor_printHexByte:
ld c , a
2020-12-17 20:34:38 +01:00
; rotate out the least significant nibble to obtain a byte with the most significant nibble
2020-12-17 13:52:28 +01:00
; in the least significant nibble position
2020-12-29 23:28:30 +01:00
rrca
rrca
rrca
rrca
2020-12-17 20:34:38 +01:00
; the upper nibble must now be discarded
and % 00001111
2020-12-17 13:52:28 +01:00
call monitor_printHexDigit
ld a , c
and % 00001111 ; bitwise and: set to 0 the most significant nibble and preserve the least
call monitor_printHexDigit
ret
; Prints an hex digit
; @param a provides the byte containing, in the LSBs, the nibble to print
; @uses a, b
monitor_printHexDigit:
; check the input is valid (0 to 15)
ld b , a
2020-12-17 20:34:38 +01:00
sub 16 ; subtract 16 instead of 15 cause 0 is positive
2020-12-17 13:52:28 +01:00
; if positive, the input is invalid. Do not print anything.
ret p
; now check if the digit is a letter (10 to 15 -> A to F)
ld a , b ; restore a
sub 10
; if a is positive, the digit is a letter
jp p , monitor_printHexDigit_letter
ld a , b ; restore a
; add 48 (the ASCII number for 0) to obtain the corresponding number
add 48
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-17 13:52:28 +01:00
ret
monitor_printHexDigit_letter:
ld a , b ; restore a
2020-12-17 20:34:38 +01:00
; to obtain the corresponding letter we should subtract 10 (so we count from A)
; and add 65 (the ASCII number for A). So -10+65=+55 we add only 55.
add 55
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-17 13:52:28 +01:00
ret
2020-12-17 20:34:38 +01:00
; Prints an ASCII character. Similar to system Print function, but
; ignores control characters and replaces any non-printable character with a dot.
2020-12-26 08:35:49 +01:00
; NOTE: the a register is modified
2020-12-17 20:34:38 +01:00
; @param a the byte to print
; @uses a, b
monitor_printAsciiByte:
ld b , a ; save a (it will be modified)
; if < 32 is a control char, non printable
sub 32
jp m , monitor_printAsciiByte_nonprintable
ld a , b ; restore a
; if >= 127 is an extended char, may not be printable
sub 127
jp p , monitor_printAsciiByte_nonprintable
; otherwise is a printable ascii char
ld a , b ; restore a
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-17 20:34:38 +01:00
ret
monitor_printAsciiByte_nonprintable:
ld a , 46 ; print dot
2020-12-29 23:28:30 +01:00
call Sys_Printc
2020-12-17 20:34:38 +01:00
ret
2020-12-17 13:52:28 +01:00
2020-12-30 21:21:38 +01:00
; Copy data from parallel terminal to application memory. This is tought to be used with the ADB function of the Pat80 Python Terminal.
; Uses TERM_DATA_AVAIL_REG to check if a byte is available before reading it.
; The first two received bytes (heading bytes) defines the stream length (MSB first), the rest of the bytes are copied to memory.
; The copy is completed when the number of bytes defined in the heading bytes are received.
; @uses a, b, c, d, h, l
2020-12-09 21:01:57 +01:00
monitor_copyTermToAppMem:
2020-12-30 21:21:38 +01:00
; d contains the current status.
; 2 = waiting for first heading byte
; 1 = waiting for second heading byte
; 0 = heading bytes received, now receiving binary stream
ld d , 2
2020-12-09 21:01:57 +01:00
ld hl , APP_SPACE ; we will write in APP_SPACE
monitor_copyTermToAppMem_loop:
2020-12-30 21:21:38 +01:00
ld a , d
cp 2 ; check if we are receiving first header byte
jp z , monitor_copyTermToAppMem_loop_rec_head_byte_1
ld a , d
cp 1 ; check if we are receiving second header byte
jp z , monitor_copyTermToAppMem_loop_rec_head_byte_2
; we are receiving binary stream: read byte and save to memory
2021-01-01 22:42:00 +01:00
call Term_readb ; reads a byte from terminal
2020-12-30 21:21:38 +01:00
ld ( hl ), a ; copy byte to memory
inc hl ; move to next memory position
2021-01-01 22:42:00 +01:00
dec bc ; decrement remaining bytes counter
; check if we reached the number of bytes to be transferred
ld a , b
cp 0
jp nz , monitor_copyTermToAppMem_loop ; continue loop
ld a , c
cp 0
jp nz , monitor_copyTermToAppMem_loop ; continue loop
; all bytes received, return
ret
2020-12-09 21:01:57 +01:00
2020-12-30 21:21:38 +01:00
monitor_copyTermToAppMem_loop_rec_head_byte_1:
; we are receiving first header byte: read byte and save to b
2021-01-01 22:42:00 +01:00
call Term_readb ; reads a byte from terminal
2020-12-30 21:21:38 +01:00
ld b , a
dec d
jp monitor_copyTermToAppMem_loop ; continue loop
monitor_copyTermToAppMem_loop_rec_head_byte_2:
; we are receiving second header byte: read byte and save to c
2021-01-01 22:42:00 +01:00
call Term_readb ; reads a byte from terminal
2020-12-30 21:21:38 +01:00
ld c , a
dec d
jp monitor_copyTermToAppMem_loop ; continue loop
2021-01-02 10:53:30 +01:00
2020-11-25 08:53:41 +01:00