294 lines
8.6 KiB
Typst
294 lines
8.6 KiB
Typst
#set document(
|
|
title: "BUZBEE Manual",
|
|
author: "Gale Faraday",
|
|
description: "CHIBI PC-09 machine language monitor BUZBEE technical and user manual",
|
|
)
|
|
|
|
#import "style.typ": conf
|
|
#show: conf.with(
|
|
title: [BUZBEE User Manual and Technical Reference],
|
|
subtitle: [A CHIBI PC-09 Machine Language Monitor],
|
|
author: [Gale Faraday],
|
|
)
|
|
|
|
= Introduction <intro>
|
|
|
|
BUZBEE is a "machine language monitor" styled after Steve Wozniak's WOZMON for
|
|
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
|
|
MIT license.
|
|
|
|
#pagebreak()
|
|
|
|
= BUZBEE Functions <bbfunc>
|
|
|
|
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" 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()
|
|
|
|
== Internal Functions (IFs) <if-top>
|
|
|
|
Internal Functions are the textual commands that BUZBEE interprets from the
|
|
command line to execute the user's wish. Internal Functions are canonically
|
|
listed in alphabetical order. Below in @if-table is a list of available IFs.
|
|
|
|
#figure(
|
|
table(
|
|
columns: (auto, auto, 1fr),
|
|
inset: 10pt,
|
|
align: center,
|
|
fill: (_, y) =>
|
|
if calc.odd(y) { luma(250) }
|
|
else { white },
|
|
table.header(
|
|
[*Name* (pg. no.)], [*Command Token*], [*Description*]
|
|
),
|
|
[`CALL` (#ref(<if-call>, form: "page"))],
|
|
[`$00`],
|
|
[Call a resident routine in the MPU's address space.],
|
|
[`HELP` (#ref(<if-help>, form: "page"))],
|
|
[`$01`],
|
|
[Display a summary of known commands.],
|
|
[`PEEK` (#ref(<if-peek>, form: "page"))],
|
|
[`$02`],
|
|
[Dumps memory from the MPU's address space to the terminal.],
|
|
[`POKE` (#ref(<if-poke>, form: "page"))],
|
|
[`$03`],
|
|
[Overwrites memory in the MPU's address space.],
|
|
[`SREC` (#ref(<if-srec>, form: "page"))],
|
|
[`$04`],
|
|
[Switches into Motorola S-Record receive mode.],
|
|
),
|
|
caption: [Table of IFs],
|
|
) <if-table>
|
|
|
|
In the following pages these IFs are described in specific.
|
|
|
|
IFs are tokenized from their textual form into a binary "bytecode" form. This
|
|
bytecode is described in @internals.
|
|
|
|
First the text command name (eg. `CALL`) is hashed in some way into a token.
|
|
Then conditional processing on the remainder of the line occurs. Values given in
|
|
hex are encoded as their corresponding bytes directly. The token buffer
|
|
mechanics are described more in @internals. Subcommands are also hashed into
|
|
tokens.
|
|
|
|
#pagebreak()
|
|
|
|
// Function for creating IF page headers
|
|
#let _ifpagehead(
|
|
desc: none,
|
|
syntax: none,
|
|
params: (),
|
|
) = {
|
|
smallcaps[#desc]
|
|
parbreak()
|
|
[Syntax: #syntax]
|
|
parbreak()
|
|
[Parameters: ]
|
|
if params.len() > 0 {
|
|
for (param, desc) in params [
|
|
- #raw("<" + upper(param) + ">"): #desc
|
|
]
|
|
} else {
|
|
text(style: "italic")[N/A]
|
|
}
|
|
}
|
|
|
|
=== IF: `CALL` <if-call>
|
|
|
|
#_ifpagehead(
|
|
desc: "Calls a resident routine in the MPU's address space.",
|
|
syntax: [`CALL <PTR>`],
|
|
params: (
|
|
ptr: "An absolute pointer to a position in the 6309 MPU's memory map.",
|
|
),
|
|
)
|
|
|
|
Call takes an absolute pointer into the MPU's address space to call as if it
|
|
were a subroutine using `JSR`.
|
|
|
|
// TODO: For when CHIBI PC-09 Prototype #2 comes out or whenever we get banking
|
|
// add it here "Special care must be taken to properly bank in the correct
|
|
// memory banks before executing this command." yadda yadda
|
|
|
|
#pagebreak()
|
|
|
|
=== IF: `HELP` <if-help>
|
|
|
|
#_ifpagehead(
|
|
desc: "Displays a summary of available IFs.",
|
|
syntax: [`HELP`],
|
|
params: ()
|
|
)
|
|
|
|
`HELP` does what it says on the tin. It should be noted that between Git tags of
|
|
the firmware the message displayed by this may be incomplete or innaccurate.
|
|
Internally all this does is print a string with the UART using the `POUTZSTR`
|
|
BIOS routine.
|
|
|
|
#pagebreak()
|
|
|
|
=== IF: `PEEK` <if-peek>
|
|
|
|
#_ifpagehead(
|
|
desc: "Dumps memory from the MPU's address space to the terminal.",
|
|
syntax: [`PEEK <BASE> [<HIGH>]`],
|
|
params: (
|
|
base: [
|
|
The address (two bytes) of the byte to dump or the base (lower bound)
|
|
address of the byte to start dumping from if `<HIGH>` is specified.
|
|
],
|
|
high: [
|
|
An optional operand given as the upper bound of the range to dump. Forms
|
|
a range together with `<BASE>`. (two bytes)
|
|
],
|
|
)
|
|
)
|
|
|
|
Peeking memory causes the MPU to read the requested bytes and dump them to the
|
|
screen.
|
|
|
|
#pagebreak()
|
|
|
|
=== IF: `POKE` <if-poke>
|
|
|
|
#_ifpagehead(
|
|
desc: "Writes values to the MPU's address space.",
|
|
syntax: [`POKE <ADDR> <BYTES>`],
|
|
params: (
|
|
addr: "The base (low) address (two bytes) to start writing bytes from.",
|
|
bytes: "The bytes to write into memory separated by whitespace.",
|
|
)
|
|
)
|
|
|
|
Poking memory causes the MPU to overwrite the bytes at `<ADDR>` with the bytes
|
|
given in `<BYTES>`.
|
|
|
|
#pagebreak()
|
|
|
|
=== IF: `SREC` <if-srec>
|
|
|
|
#_ifpagehead(
|
|
desc: "Switches into Motorola S-Record receive mode.",
|
|
syntax: [`SREC`],
|
|
params: (),
|
|
)
|
|
|
|
Motorola S-Record mode is currently a stub.
|
|
|
|
#pagebreak()
|
|
|
|
== External Functions (EFs) <ef-top>
|
|
|
|
External functions are any native user code that can be called with `CALL` (see
|
|
@if-call). This mechanism is usable to run any code or routine in memory as
|
|
though interactively using the MPU's `JSR` instruction.
|
|
|
|
=== EFs in ROM <ef-rom>
|
|
|
|
Some common EFs to call include the using call to reset the CHIBI PC-09 with
|
|
`CALL 8000`.
|
|
|
|
// TODO: Talk about memory test and BIOS interface
|
|
|
|
#pagebreak()
|
|
|
|
= BUZBEE Reserved Memory Regions <res-mem>
|
|
|
|
BUZBEE uses memory in the 0200-02FF page. A table of the layout of this memory
|
|
is provided. The memory is laid out in a packed structure starting at 0200.
|
|
|
|
#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()
|
|
|
|
= Building CHIBI PC-09 Firmware from Source <building>
|
|
|
|
Building the CHIBI PC-09 firmware from source requires LWTOOLS
|
|
#link("http://lwtools.ca"), a functioning C compiler (`cc`), and a POSIX Shell
|
|
implementation (`sh`). The firmware was developed using LWTOOLS version 4.24 on
|
|
Linux, though later versions may work as well. A GNU Make "makefile" is provided for
|
|
building on Linux. GNU binutils' `objcopy` is also used to build the compiled
|
|
Motorola S-Record into a raw binary. Development is tracked using Git.
|
|
|
|
Using the makefile is simple. It provides facilities for easy building, and
|
|
development.
|
|
|
|
To build an S-Record of the ROM run:
|
|
```sh
|
|
make generate && make boot.s19
|
|
```
|
|
|
|
To build a ROM image with `objcopy` run:
|
|
```sh
|
|
make generate && make
|
|
```
|
|
|
|
In order to rebuild, first the generated files and existing objects must be
|
|
cleaned. To do this a `make clean` pseudo-target is defined.
|
|
|
|
Building the documentation can also be accomplished using `make docs`, provided
|
|
`typst` is installed.
|
|
|
|
#pagebreak()
|
|
|
|
= BUZBEE Internals and Modding <internals>
|
|
|
|
BUZBEE's interpreter works by "compiling" textual user commands into bytecode
|
|
for more simply passing parameters to IFs (see @if-top). The way that works is
|
|
the implementation dependent, but each hash is one byte (1B) in size, and
|
|
corresponds to an IF token, which is the index of the hash.
|
|
|
|
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.
|