Files
chibi-firmware/src/buzbee.s

396 lines
11 KiB
ArmAsm

; CHIBI PC-09 Machine Language Monitor -- BUZBEE
; Copyright (c) 2025 Gale Faraday
; Licensed under MIT
INCLUDE "bbhash.inc"
INCLUDE "buzbee.inc"
INCLUDE "hardware.inc"
INCLUDE "serial.inc"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Variables
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BBIN_DEPTH EQU $80 ; Input buffer depth
BBTOKENS_DEPTH EQU $40 ; Token buffer depth
SECTION BBVARS,bss
tagbbvar STRUCT
input rmb BBIN_DEPTH ; Input buffer
cchinput rmd 1 ; Input buffer char count
tokens rmb BBTOKENS_DEPTH ; Token buffer
cbtokens rmd 1 ; Token buffer byte count
scratch rmd 1 ; Scratch word
ENDSTRUCT
ORG $0200
BBVAR tagbbvar
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Main Loop
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SECTION BUZBEE
EXPORT BUZBEE
BUZBEE
lbsr NEWLINE ; Setup the new input line and handle display.
bsr INPLOOP ; Fill input buffer.
cmpy #$0000 ; No data?
beq BUZBEE ; Try again...
; TODO: Parse the input buffer into tokens
lbsr RUNIF
bra BUZBEE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Input Buffering and Handling Routines
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Fills input buffer with characters from the serial console. Sets Y to the
; offset in the input buffer of the last char read.
INPLOOP
jsr PINCHAR ; Try to read a char
cmpd #$0000 ; If no char keep waitin'
beq INPLOOP
bitb #UARTF_LSR_DR ; Is there a char in A?
beq NOCHAR@
cmpa #$1B ; ESC?
beq HESC@ ; Handle ESC
cmpa #$08 ; BS?
beq HBACKSPC@ ; Backup a char
cmpa #$0D ; CR?
beq HCR@ ; Then terminate and parse input buffer
cmpy #BBIN_DEPTH ; Are we at the end of the input buffer?
beq FULLBUF@ ; Handle the buffer being full
ECHO@
jsr POUTCHAR ; Echo char back, this includes BS chars
sta BBVAR.input,y ; Add it to the input buffer
leay 1,y
; Fall through
NOCHAR@
; Check for error condition, work based on The Serial Port release 19
bitb #(UARTF_LSR_FIFO|UARTF_LSR_BI|UARTF_LSR_FE|UARTF_LSR_PE|UARTF_LSR_OE)
beq INPLOOP
bitb #UARTF_LSR_OE ; Check for overrun error
beq NOOVER@
PZSTR EM_OVERRUN
NOOVER@
bitb #UARTF_LSR_PE ; Check for parity error
beq NOPARITY@
PZSTR EM_PARITY
NOPARITY@
bitb #UARTF_LSR_FE ; Check for framing error
beq NOFRAM@
PZSTR EM_FRAMING
NOFRAM@
bitb #UARTF_LSR_FIFO ; Check for FIFO error
beq INPLOOP ; Loop over
PZSTR EM_FIFO
bra INPLOOP ; Loop over
HCR@
sty BBVAR.cchinput ; Store buffer length
rts
HESC@
lda #'^ ; Print a char that signifies that ESC was pressed
jsr POUTCHAR
ldy #$0000 ; On return we cmpy #$0000 and if eq then newline.
rts
HBACKSPC@
clrb ; Clear last char
leay -1,y
stb BBVAR.input
bra ECHO@ ; Echo the char in A
FULLBUF@
lda #$07 ; ASCII BEL
jsr POUTCHAR
lbra INPLOOP
; Handle new lines; prints a new prompt and then clears the input buffer
NEWLINE
PZSTR PROMPTLINE ; Print prompt line
CLRIN ; Label to just clear input buffer without newline
clra ; Init A and X
ldx #$0000
NEXT@
sta BBVAR.input,x ; Clear input buffer
leax 1,x
cmpx #BBIN_DEPTH
blo NEXT@
ldy #$0000 ; Reset buffer fill pointer
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Hex Conversion and Printing Routines
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Prints a byte in A
; @param A: byte to print
PBYTE
pshs b
tfr a,b ; Transfer lower nybble into B
andd #$F00F ; Mask and adjsut
asra
asra
asra
asra
anda #$0F
ora #'0 ; Add '0' to offset to digits
cmpa #$3A ; Hex? ':' '9'+1
blo SKIPA@
adca #6 ; Hex offset
SKIPA@
jsr POUTCHAR ; Print char in A
andb #$0F
orb #'0 ; Add '0' to offset to digits
cmpb #$3A ; Hex? ':' '9'+1
blo SKIPB@
adcb #6 ; Hex offset
SKIPB@
tfr b,a ; Print char in B
jsr POUTCHAR
puls b ; Restore B
rts
; Converts a hexadecimal sequence into a byte value
; @param D: hex representation of a byte with A: MSD B: LSD
; @return A: returned byte value
; NOTE: Conversion logic credit to Wozniak. This code unrolled for speed.
HEX2BYT
eora #$B0 ; Map digits to 0-9
cmpa #9+1 ; Is it a decimal?
blo AISDEC@ ; Yes? skip hex adjust
adca #$88 ; Map 'A'-'F' to $FA-$FF
cmpa #$FA ; Hex char?
blo BADHEX@ ; No? Print error
AISDEC@
asla ; Shift MSD into upper nybble of A
asla
asla
asla
; Do B part
eorb #$B0 ; Map digits to 0-9
cmpa #9+1 ; Is it a decimal?
blo BISDEC@ ; Yes? skip hex adjust
adcb #$88 ; Map 'A'-'F' to $FA-$FF
andb #$0F ; Mask high nybble
cmpb #$0A ; Hex char?
blo BADHEX@ ; No? Print error
BISDEC@
stb BBVAR.scratch ; Store low nybble in scratch buffer
ora BBVAR.scratch ; Combine the nybbles
rts
BADHEX@
PZSTR EM_BADHEX ; Print an error message
clrd ; Prevent RUNIF from executing
std BBVAR.cbtokens
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Tokenizing Routines
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Makes a hash of four chars in BBIN starting at offset X
; @param Y: offset in BBIN to read the four chars from
; @return A: resulting hash
; @return Y: offset after hash processing
MKCMDSUM
pshs b
ldb #4 ; Loop over four chars
clra ; Initialize accumulator
NEXTC@
suba BBVAR.input,y ; Subtract current char from accumulator
leax 1,y ; Next char
decb ; Reduce count
cmpb #0 ; Are we at the end?
bne NEXTC@ ; No? loop
puls b
rts
; Skips "whitespace" to the next semantic char
; @param Y: current index in text buffer
; @return Y: resulting index in text buffer
SKIPTONEXTC
lda BBVAR.input,y ; Get our char?
cmpa #$20 ; SPACE or control char?
bhi EXIT@ ; Yes? End
leay 1,y ; Iterate next char
bra SKIPTONEXTC
EXIT@
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE IF Handling Functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Executes a command based on the initial token
; @corrupts B
; @return X: command data table index
RUNIF
clrd ; Do we have any tokens?
cmpd BBVAR.cbtokens
beq NOTOK@
ldx #0 ; Counting up from zero
lda BBVAR.tokens ; Load token
NEXTHASH@
cmpa BBCHT,x ; Is this hash our hash?
beq CALCPTR@ ; Yes? skip to next step to put ptr in x
leax 1,x ; Begin considering next hash
cmpx BBCHTC ; Is this the last byte?
blo NEXTHASH@ ; No? try next hash, Yes? fall through
PZSTR EM_BADHASH ; Print an error message
lbra IFHELP ; Proceed to call "HELP"
CALCPTR@
tfr x,d ; Swap into d to do a cheap multiply
asld ; Cheaply << to get *2, pointer size
tfr d,x ; Restore x from d and jump to function at index
jmp [IFPTRTBL,x]
NOTOK@
rts
; IF pointer table
IFPTRTBL
fdb IFCALL
fdb IFHELP
fdb IFPEEK
fdb IFPOKE
fdb IFSREC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Internal Command Functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call a pointer
IFCALL
ldd BBVAR.cbtokens ; Only jump if three tokens given
cmpd #3
lbne INVALIDARG
jsr [BBVAR.tokens+1] ; Make our jump (doesn't implicitly return)
rts
; Print out a help message
IFHELP
PZSTR HELP_MSG
rts
; Peek memory
IFPEEK
ldd BBVAR.cbtokens ; One 16-bit token given, single peek
cmpd #3
lblo INVALIDARG ; Not enough args given
bhi SELTYPE@ ; Select forward or backward peek
SINGLE@
lda [BBVAR.tokens+1] ; Get byte
lbsr PBYTE ; Print peek byte
rts
SELTYPE@
ldd BBVAR.cbtokens ; Have enough tokens?
cmpd #5
lbne INVALIDARG ; No? bounce out
ldd BBVAR.tokens+1 ; Are we forwards (BASE < HIGH)?
cmpd BBVAR.tokens+3
beq SINGLE@ ; Gracefully handle BASE == HIGH
bhi INVALIDARG ; Malformed if BASE > HIGH
ldx BBVAR.tokens+1 ; Get BASE
NEXT@
lda ,x+ ; Get the next byte
lbsr PBYTE ; Print our byte
cmpx BBVAR.tokens+3 ; Are we at <HIGH> yet?
bne NEXT@ ; No? loop
rts
; Poke bytes into memory
; NOTE: Blocks could also use 6309 TFM instruction
IFPOKE
ldx BBVAR.cbtokens ; Make sure we have enough tokens
cmpx #4
lblo INVALIDARG
leax -3,x ; Get count of bytes to write into X
ldy #0 ; Setup Y for indexing
NEXTB@
lda BBVAR.tokens+3,y ; Get source byte to copy
sta [BBVAR.tokens+1,y] ; Copy byte
leay +1,y ; Increment memory indexer
leax -1,x ; Decement byte count
cmpx #0 ; Are we at our last byte?
bhi NEXTB@ ; No? loop
rts
; Placeholder function labels to make assembler happy before git commit
IFSREC
rts
; Invalid argument IF tail
INVALIDARG
PZSTR EM_BADARG
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Strings and Fixed Data
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
HELP_MSG
fcc "-- BUZBEE HELP --"
fcb $0D,$0A
fcc "Available Commands:"
fcb $0D,$0A
fcc "CALL <PTR> - Call the pointer given in <PTR> as a subroutine."
fcb $0D,$0A
fcc "HELP [CMD] - Display help, command optional."
fcb $0D,$0A
fcc "PEEK <BASE> [<HIGH>] - Read memory at <BASE> to <HIGH>."
fcb $0D,$0A
fcc "POKE <ADDR> <BYTES> - Overwrite memory with <BYTES> starting at <BASE>."
fcb $0D,$0A
fcc "SREC - Enter Motorola S-Record entry mode."
fcb $0D,$0A
fcb $00
PROMPTLINE
fcb $0D,$0A,$25,$00 ; CR LF '%' NUL
EM_OVERRUN
fcc "!!! UART Overrun Error !!!"
fcb $0D,$0A,$00
EM_PARITY
fcc "!!! UART Parity Error !!!"
fcb $0D,$0A,$00
EM_FRAMING
fcc "!!! UART Framing Error !!!"
fcb $0D,$0A,$00
EM_FIFO
fcc "!!! UART FIFO Error !!!"
fcb $0D,$0A,$00
EM_BADHASH
fcc "!!! Bad Command Hash !!!"
fcb $0D,$0A,$00
EM_BADARG
fcc "!!! Malformed Arguments !!!"
fcb $0D,$0A,$00
EM_TOKFAIL
fcc "!!! Tokenization Failure !!!"
fcb $0D,$0A,$00
EM_BADHEX
fcc "!!! Malformed Hex Value !!!"
fcb $0D,$0A,$00
EM_FULLTOKBUF
fcc "!!! Token Buffer Overrun !!!"
fcb $0D,$0A,$00