Compare commits

...

2 Commits

2 changed files with 164 additions and 69 deletions

View File

@@ -18,6 +18,10 @@ the CHIBI PC-09 hobby computer platform. It is the stock bootloader and
interface for the PC-09. This manual goes over the usage of BUZBEE, and some of
the technical internals of how it works and how to hack on it.
BUZBEE was created primarily to debug prototype versions of the CHIBI PC-09.
BUZBEE will grow alongside the CHIBI PC-09 project. It also functions as a
reference implementation of an OS using the CHIBI PC-09 BIOS.
The CHIBI PC-09 name and platform is copyright 2024-2025 Amber Zeller. The CHIBI
PC-09 BIOS is copyright 2024-2025 Gale Faraday and Amber Zeller. BUZBEE is
copyright 2025 Gale Faraday. All CHIBI PC-09 components are licensed under the
@@ -29,10 +33,11 @@ MIT license.
BUZBEE is at its core a chain loader or bootloader. This means that most of the
functionality of the CHIBI starts with using BUZBEE. BUZBEE functions are broken
into two categories: _Internal Functions_ or "IFs," and _External Functions_ or
"EFs." IFs are native routines mapped to textual commands entered at the BUZBEE
prompt. EFs are native routines called through IFs. EFs can either be any user
supplied code, or one of a set of routines in the BIOS/BUZBEE ROM or "firmware".
into two categories: _Internal Functions_ or "IFs" defined in @if-top, and
_External Functions_ or "EFs" in @ef-top. IFs are native routines mapped to
textual commands entered at the BUZBEE prompt. EFs are native routines called
through IFs. EFs can either be any user supplied code, or one of a set of
routines in the BIOS/BUZBEE ROM or "firmware".
#pagebreak()
@@ -47,6 +52,9 @@ listed in alphabetical order. Below in @if-table is a list of available IFs.
columns: (1fr, auto),
inset: 10pt,
align: center,
fill: (_, y) =>
if calc.odd(y) { luma(250) }
else { white },
table.header(
[*Name* (pg. no.)], [*Description*]
),
@@ -149,6 +157,9 @@ BIOS routine.
)
)
Peeking memory causes the MPU to read the requested bytes and dump them to the
screen.
#lorem(120)
#pagebreak()
@@ -198,9 +209,34 @@ Some common EFs to call include the using call to reset the CHIBI PC-09 with
= BUZBEE Reserved Memory Regions <res-mem>
BUZBEE uses memory in the 0200-02FF page. A table of the layout of this memory
is provided.
is provided. The memory is laid out in a packed structure starting at 0200.
// TODO: Provide a table of the BUZBEE memory layout.
#table(
columns: (auto, 1fr, auto),
inset: 10pt,
align: center,
fill: (_, y) =>
if calc.odd(y) { luma(250) }
else { white },
table.header(
[*Internal Name*], [*Size (Bytes)*], [*Description*]
),
[`input`],
[128],
[Text input buffer],
[`cchinput`],
[2],
[Text input buffer character count],
[`tokens`],
[64],
[BUZBEE token buffer],
[`cbtokens`],
[2],
[Count of bytes in `tokens`],
[`scratch`],
[2],
[Internal scratch word used for some operations],
)
#pagebreak()
@@ -236,4 +272,17 @@ Building the documentation can also be accomplished using `make docs`, provided
= BUZBEE Internals and Modding <internals>
#lorem(120)
BUZBEE's interpreter works by "compiling" textual user commands into bytecode
for more simply passing parameters to IFs (see @if-top).
BUZBEE's source, and the surrounding BIOS source is well commented, but a
general summary of the control flow is provided here.
+ BUZBEE sets up the prompt and input buffer with `NEWLINE`
+ BUZBEE enters an input processing loop that works with the CHIBI PC-09's
serial driver.
+ If no input is provided, restart.
+ BUZBEE makes a tokenizing pass over the input buffer.
+ BUZBEE attempts to execute the tokens, which may involve leaving the BUZBEE
loop, or in the event the IF returns, loops around and re-enters the BUZBEE
loop.

View File

@@ -13,15 +13,17 @@
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BBIN_DEPTH EQU $7F
BBTOKENS_DEPTH EQU $3F
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 rmb 2
cbtokens rmd 1 ; Token buffer byte count
scratch rmd 1 ; Scratch word
ENDSTRUCT
ORG $0200
@@ -38,10 +40,10 @@ BBVAR tagbbvar
EXPORT BUZBEE
BUZBEE
bsr NEWLINE ; Setup the new input line and handle display.
bsr INPLOOP ; Fill input buffer.
cmpy #$0000 ; No data?
beq BUZBEE ; Try again...
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
@@ -52,20 +54,6 @@ BUZBEE
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
; Fills input buffer with characters from the serial console. Sets Y to the
; offset in the input buffer of the last char read.
INPLOOP
@@ -79,13 +67,14 @@ INPLOOP
cmpa #$08 ; BS?
beq HBACKSPC@ ; Backup a char
cmpa #$0D ; CR?
beq EXIT@ ; Then parse input buffer
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)
@@ -103,10 +92,11 @@ NOPARITY@
PZSTR EM_FRAMING
NOFRAM@
bitb #UARTF_LSR_FIFO ; Check for FIFO error
beq INPLOOP
beq INPLOOP ; Loop over
PZSTR EM_FIFO
bra INPLOOP
EXIT@
bra INPLOOP ; Loop over
HCR@
sty BBVAR.cchinput ; Store buffer length
rts
HESC@
lda #'^ ; Print a char that signifies that ESC was pressed
@@ -121,7 +111,21 @@ HBACKSPC@
FULLBUF@
lda #$07 ; ASCII BEL
jsr POUTCHAR
bra INPLOOP
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -130,7 +134,7 @@ FULLBUF@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Prints a byte in A
; @param a: byte to print
; @param A: byte to print
PBYTE
pshs b
tfr a,b ; Transfer lower nybble into B
@@ -148,24 +152,58 @@ PBYTE
rts
; Converts a nybble into a valid hex digit
; @param a: nybble to convert to a char
; @return a: resulting char
; @param A: nybble to convert to a char
; @return A: resulting char
NYB2HEX
anda #$0F
ora #'0 ; Add "0"
cmpa #$3A ; ":" "9"+1
bcc SKIP@
blo SKIP@
adca #6 ; Add offset to "A" in ascii
SKIP@
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.
; Makes a hash of four chars in BBIN starting at offset X
; @param X: offset in BBIN to read the four chars from
; @return A: resulting hash
MKCMDSUM
@@ -180,6 +218,18 @@ NEXTC@
bne NEXTC@ ; No? loop
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
@@ -190,6 +240,9 @@ NEXTC@
; @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@
@@ -198,13 +251,15 @@ NEXTHASH@
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_BADCMD ; Print an error message
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 [BBCMDPTRTBL,x]
NOTOK@
rts
; IF pointer table
BBCMDPTRTBL
@@ -238,40 +293,25 @@ IFPEEK
ldd BBVAR.cbtokens ; One 16-bit token given, single peek
cmpd #3
lblo INVALIDARG ; Not enough args given
bhi SELFORBAC@ ; Select forward or backward peek
bhi SELTYPE@ ; Select forward or backward peek
SINGLE@
lda [BBVAR.tokens+1] ; Get byte
lbsr PBYTE ; Print peek byte
rts
SELFORBAC@
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
blo PEEKFWD
bhi PEEKBACK
; Peek forward
PEEKFWD
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
; Peek backwards
PEEKBACK
bhi INVALIDARG ; Malformed if BASE > HIGH
ldx BBVAR.tokens+1 ; Get BASE
PREV@
lda 0,x ; Get current byte
leax -1,x ; Prep for next byte
NEXT@
lda ,x+ ; Get the next byte
lbsr PBYTE ; Print our byte
cmpx BBVAR.tokens+3 ; Are we at <HIGH> yet?
bne PREV@ ; No? loop
bne NEXT@ ; No? loop
rts
; Poke bytes into memory
@@ -297,12 +337,12 @@ IFSREC
; Invalid argument IF tail
INVALIDARG
PZSTR EM_MISSINGARG
PZSTR EM_BADARG
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; BUZBEE Strings and Tables
;; BUZBEE Strings and Fixed Data
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -327,20 +367,26 @@ PROMPTLINE
fcb $0D,$0A,$25,$00 ; CR LF '%' NUL
EM_OVERRUN
fcc "!!! Overrun Error !!!"
fcc "!!! UART Overrun Error !!!"
fcb $0D,$0A,$00
EM_PARITY
fcc "!!! Parity Error !!!"
fcc "!!! UART Parity Error !!!"
fcb $0D,$0A,$00
EM_FRAMING
fcc "!!! Framing Error !!!"
fcc "!!! UART Framing Error !!!"
fcb $0D,$0A,$00
EM_FIFO
fcc "!!! FIFO Error !!!"
fcc "!!! UART FIFO Error !!!"
fcb $0D,$0A,$00
EM_BADCMD
EM_BADHASH
fcc "!!! Bad Command Hash !!!"
fcb $0D,$0A,$00
EM_MISSINGARG
fcc "!!! Missing Arguments !!!"
EM_BADARG
fcc "!!! Malformed Arguments !!!"
fcb $0D,$0A,$00
EM_TOKFAIL
fcc "!!! Tokenization Failure !!!"
fcb $0D,$0A,$00
EM_BADHEX
fcc "!!! Maleformed Hex Value !!!"
fcb $0D,$0A,$00