; 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 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 - Call the pointer given in as a subroutine." fcb $0D,$0A fcc "HELP [CMD] - Display help, command optional." fcb $0D,$0A fcc "PEEK [] - Read memory at to ." fcb $0D,$0A fcc "POKE - Overwrite memory with starting at ." 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