Compare commits
30 Commits
18a5615b53
...
f68fa4c0a6
Author | SHA1 | Date | |
---|---|---|---|
f68fa4c0a6
|
|||
d92b8f6ba4
|
|||
96a5804467
|
|||
9ab92eb8a5
|
|||
a6a93e656a
|
|||
b5cfd501c5
|
|||
8f615e1bd8
|
|||
31cf42167f
|
|||
a616d47e76
|
|||
1cd6720bf6
|
|||
88fcc86e72
|
|||
6cbb038b42
|
|||
aed8ca28f9
|
|||
3441aea9c1
|
|||
893753561c
|
|||
eda7b3ac1f
|
|||
eafc0ce98e
|
|||
d7d8532021
|
|||
6544321450
|
|||
98ed74f10d
|
|||
15872f93b9
|
|||
8c12c2106f
|
|||
35a2f12cce
|
|||
dce0719796
|
|||
abeecf4e93
|
|||
180fc932c9
|
|||
f0104c74c2
|
|||
2988fb9059
|
|||
2b23634bb8
|
|||
853efd9bac
|
@@ -12,7 +12,7 @@ insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
[*.{md,typ}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 80
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,6 +6,9 @@
|
||||
*.s19
|
||||
build/
|
||||
map.txt
|
||||
bbmkhash
|
||||
*.pdf
|
||||
|
||||
# Build system generated files
|
||||
src/version.s
|
||||
src/bbhash.s
|
||||
|
67
bbmkhash.c
Normal file
67
bbmkhash.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* Generates BUZBEE command hash data table asm file */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Length of commands in printable-char count (excluding NUL terminator). */
|
||||
const int s_cchCmd = 4;
|
||||
|
||||
/* Add your commands here to be hashed. Imprtant that they all be CCH_CMD
|
||||
* chars long EXCLUDING the NUL terminator. Order is important here. */
|
||||
const char *s_ppszCmds[] = {
|
||||
"CALL",
|
||||
"HELP",
|
||||
"PEEK",
|
||||
"POKE",
|
||||
"SREC",
|
||||
/* "BOOT", */
|
||||
};
|
||||
|
||||
int mkHash(const char pszCmd[]);
|
||||
|
||||
int main(void) {
|
||||
/* Emit file header */
|
||||
puts("; CHIBI PC-09 -- BUZBEE -- Command Hash Table\n\
|
||||
; Copyright (c) 2025 Gale Faraday\n\
|
||||
; Licensed under MIT\n\
|
||||
\n\
|
||||
; This file generated by bbmkcmds.c\n\
|
||||
\n\
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\
|
||||
;;\n\
|
||||
;; BUZBEE Command Hash Table\n\
|
||||
;;\n\
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\
|
||||
\n\
|
||||
SECTION BBHASHES\n\
|
||||
\n\
|
||||
EXPORT BBCHTC\n\
|
||||
EXPORT BBCHT\n");
|
||||
|
||||
/* Command count.
|
||||
* NOTE: This is a u16 because it gets emitted into the output assembly. */
|
||||
uint16_t cCmds = sizeof(s_ppszCmds) / sizeof(char *);
|
||||
|
||||
/* Emit command count */
|
||||
printf("BBCHTC\n fdb $%.4X\n", cCmds);
|
||||
|
||||
/* Emit table data */
|
||||
puts("\nBBCHT");
|
||||
for (int iCmd = 0; iCmd < cCmds; iCmd++) {
|
||||
uint8_t uHash = mkHash(s_ppszCmds[iCmd]);
|
||||
printf(" fcb $%.2X\n", uHash);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkHash(const char pszCmd[]) {
|
||||
uint8_t nhash = 0;
|
||||
|
||||
/* NOTE: Very important that condition is the length of the string MINUS the
|
||||
* NUL terminator, in this case iChar < 4 */
|
||||
for (int iChar = 0; iChar < s_cchCmd; iChar++)
|
||||
nhash = nhash - pszCmd[iChar];
|
||||
|
||||
return nhash;
|
||||
}
|
293
docs/buzbee.typ
Normal file
293
docs/buzbee.typ
Normal file
@@ -0,0 +1,293 @@
|
||||
#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.
|
62
docs/style.typ
Normal file
62
docs/style.typ
Normal file
@@ -0,0 +1,62 @@
|
||||
// Style conf function for CHIBI PC-09 projects
|
||||
#let conf(
|
||||
title: none,
|
||||
subtitle: none,
|
||||
author: none,
|
||||
doc,
|
||||
) = {
|
||||
|
||||
// Global page format
|
||||
set page(
|
||||
paper: "us-letter",
|
||||
header: align(right, text(10pt, weight: "light")[#title]),
|
||||
numbering: "1",
|
||||
)
|
||||
|
||||
// Font settings
|
||||
set text(
|
||||
font: "New Computer Modern",
|
||||
size: 12pt,
|
||||
)
|
||||
|
||||
// Default paragraph settings
|
||||
set par(
|
||||
justify: true,
|
||||
first-line-indent: 1cm,
|
||||
)
|
||||
|
||||
// Heading numbering
|
||||
set heading(numbering: "1.1")
|
||||
|
||||
// Show table captions above tables
|
||||
show figure.where(kind: table): set figure.caption(position: top)
|
||||
|
||||
// Title page and TOC
|
||||
page(header: none, footer: none)[
|
||||
// Emit title and subtitle page
|
||||
#block(height: 60%)[
|
||||
#align(center + horizon,
|
||||
block(text(22pt)[#title]) +
|
||||
block(above: 2em)[#smallcaps[#subtitle]] +
|
||||
block[Written by #author],
|
||||
)
|
||||
]
|
||||
// Emit TOC
|
||||
#pagebreak()
|
||||
#outline()
|
||||
#pagebreak()
|
||||
]
|
||||
|
||||
// Heading formatting for doc, must come after title page and TOC
|
||||
show heading: it => [
|
||||
CHAPTER
|
||||
#counter(heading).display()
|
||||
#it.body
|
||||
]
|
||||
|
||||
// Emit doc
|
||||
counter(page).update(1) // Reset counter for first real page
|
||||
set align(left)
|
||||
doc
|
||||
}
|
||||
|
@@ -28,6 +28,6 @@ sed -e "s/<TAG>/$TAG/g" -e "s/<DATE>/$DATE/g" <<EOF > "$OUTFILE"
|
||||
|
||||
VERMSG
|
||||
fcc "CHIBI PC-09 BOOT ROM <TAG>"
|
||||
fcb \$0A
|
||||
fcb \$0D,\$0A
|
||||
fcn "BUILT <DATE>"
|
||||
EOF
|
||||
|
@@ -2,5 +2,8 @@ section RESET load 8000
|
||||
section SERIAL
|
||||
section MEMTEST
|
||||
|
||||
section BUZBEE
|
||||
section BBHASHES
|
||||
|
||||
section VECTORS high 100000
|
||||
section VERSION high
|
||||
|
16
makefile
16
makefile
@@ -1,6 +1,6 @@
|
||||
# Makefile for CHIBI PC-09 Firmware
|
||||
|
||||
.PHONY: generate all clean
|
||||
.PHONY: generate all clean docs
|
||||
.IGNORE: clean
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
@@ -13,7 +13,7 @@ TARGREC := $(TARGET).s19
|
||||
TARGROM := $(TARGET).bin
|
||||
SRCDIR := src/
|
||||
BUILDDIR := build/
|
||||
GENS := $(SRCDIR)version.s
|
||||
GENS := $(SRCDIR)version.s $(SRCDIR)bbhash.s
|
||||
SRCS := $(wildcard $(SRCDIR)*.s)
|
||||
OBJS := $(patsubst $(SRCDIR)%.s,$(BUILDDIR)%.o,$(SRCS))
|
||||
INCS := $(wildcard $(SRCDIR)*.inc)
|
||||
@@ -33,6 +33,9 @@ LDFLAGS := -f srec -m map.txt -s linkscript
|
||||
# Rules and Phony Targets
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
docs: docs/*.typ
|
||||
typst compile docs/buzbee.typ
|
||||
|
||||
all: $(TARGROM)
|
||||
|
||||
# Fix srec into flashable bin file
|
||||
@@ -48,11 +51,18 @@ $(OBJS): $(BUILDDIR)%.o : $(SRCDIR)%.s
|
||||
-@mkdir -p $(BUILDDIR)
|
||||
$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
# Pseudo target for generation step
|
||||
generate: $(GENS)
|
||||
|
||||
$(GENS):
|
||||
# Run generation scripts
|
||||
$(GENS): bbmkhash
|
||||
./bbmkhash > src/bbhash.s
|
||||
./genver.sh
|
||||
|
||||
# Build bbmkcmds, used to generate src/cmds.s
|
||||
bbmkhash: bbmkhash.c
|
||||
cc -o $@ $<
|
||||
|
||||
clean:
|
||||
@echo 'Cleaning up intermediary files...'
|
||||
@rm -rv $(TARGROM) $(TARGREC) map.txt $(BUILDDIR)
|
||||
|
8
src/bbhash.inc
Normal file
8
src/bbhash.inc
Normal file
@@ -0,0 +1,8 @@
|
||||
; CHIBI PC-09 Machine Language Monitor -- BUZBEE Command Hash Table Symbols
|
||||
; Copyright (c) 2025 Gale Faraday
|
||||
; Licensed under MIT
|
||||
|
||||
; vim: ft=asm
|
||||
|
||||
BBCHTC IMPORT
|
||||
BBCHT IMPORT
|
7
src/buzbee.inc
Normal file
7
src/buzbee.inc
Normal file
@@ -0,0 +1,7 @@
|
||||
; CHIBI PC-09 Machine Language Monitor -- BUZBEE Header
|
||||
; Copyright (c) 2025 Gale Faraday
|
||||
; Licensed under MIT
|
||||
|
||||
; vim: ft=asm
|
||||
|
||||
BUZBEE IMPORT
|
442
src/buzbee.s
Normal file
442
src/buzbee.s
Normal file
@@ -0,0 +1,442 @@
|
||||
; 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 #0 ; No data?
|
||||
beq BUZBEE ; Try again...
|
||||
lbsr TOKENIZE ; Try to tokenize the input buffer
|
||||
lbsr RUNIF ; Execute token buffer, handling any errors
|
||||
bra BUZBEE ; Repeat
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 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 #0 ; 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 #0 ; On return we cmpy #0 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 #0
|
||||
NEXT@
|
||||
sta BBVAR.input,x ; Clear input buffer
|
||||
leax 1,x
|
||||
cmpx #BBIN_DEPTH
|
||||
blo NEXT@
|
||||
ldy #0 ; 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
|
||||
;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Attempts to parse the input buffer into tokens depending on the command
|
||||
TOKENIZE
|
||||
ldd BBVAR.cchinput ; Do we have input to work with?
|
||||
cmpd #4 ; Do we have even enough space for a string command
|
||||
blo TOKFAIL@ ; No? GTFO
|
||||
ldy #0 ; Initialize Y; used to track current position in BBVAR.input
|
||||
ldx #0 ; Initialize X; used to track position in BBVAR.tokens
|
||||
bsr SKIPTONEXTC ; Get the next non-whitespace char
|
||||
bsr MKCMDSUM ; Hash the first four non-whitespace chars
|
||||
bsr HASH2TOKEN ; Try to turn that hash into a proper token
|
||||
bcs TOKFAIL@
|
||||
bra STTOK@ ; Store token
|
||||
NEXTHEX@ ; Next hex token
|
||||
bsr SKIPTONEXTC ; Skip to next whitespace
|
||||
ldd BBVAR.input,y ; Get hex value (two digits)
|
||||
bsr HEX2BYT ; Convert hex value to byte value
|
||||
STTOK@
|
||||
sta BBVAR.tokens,x ; Store curent token
|
||||
leax 1,x ; Advance to next token
|
||||
cmpx #BBTOKENS_DEPTH ; Is this next token in bounds?
|
||||
beq FULLBUF@ ; No? handle a full buffer
|
||||
bra NEXTHEX@ ; Try to turn the next character into a hex value
|
||||
FULLBUF@
|
||||
PZSTR EM_FULLTOKBUF ; Print an error message
|
||||
clrd ; Say we wrote no tokens
|
||||
std BBVAR.cbtokens
|
||||
rts
|
||||
TOKFAIL@
|
||||
PZSTR EM_TOKFAIL ; Print tokenization fail
|
||||
clrd ; Say we wrote no tokens
|
||||
std BBVAR.cbtokens
|
||||
rts
|
||||
|
||||
; Converts a runtime command hash into a portable token. Command tokens are
|
||||
; indexes into BBCHT, which is generated at compile-time
|
||||
; @param A: runtime hash
|
||||
; @return A: output token
|
||||
; @return CC.C: set if error state, cleared otherwise
|
||||
HASH2TOKEN
|
||||
pshs x ; Preserve & init X; other routines in this group use it
|
||||
ldx #0
|
||||
NEXTHASH@
|
||||
cmpa BBCHT,x ; Is this hash our hash?
|
||||
beq THISHASH@ ; Yes? turn it into a token
|
||||
leax 1,x ; Begin considering next hash
|
||||
cmpx BBCHTC ; Is the next hash even in the table?
|
||||
blo NEXTHASH@ ; Yes? try this next hash, No? fall through
|
||||
PZSTR EM_BADHASH CALL; Print an error message to the user
|
||||
puls x
|
||||
orcc #1 ; Set CC.C to indicate error
|
||||
rts
|
||||
THISHASH@
|
||||
puls x
|
||||
andcc #$FE ; Clear CC.C to indicate success
|
||||
rts
|
||||
|
||||
; 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
|
||||
tfr a,b ; Get the index in D
|
||||
asld ; Cheaply << to get *2, pointer size
|
||||
tfr d,x ; Move to X so we can use indexed mode with the offset
|
||||
jmp [IFPTRTBL,x] ; Select IF
|
||||
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
|
@@ -18,7 +18,7 @@
|
||||
; RAM testing routine. Ported to 6809 from 6800, based on source for ROBIT-2 for
|
||||
; MIKBUG.
|
||||
RAMTEST
|
||||
ldx #SRAM_BASE
|
||||
ldx #STACK_TOP+1 ; bottom of testable SRAM, $0200
|
||||
AGAIN@ ; Store 1 in memory
|
||||
lda #1 ; Set [X] to 1
|
||||
sta 0,x
|
||||
|
29
src/reset.s
29
src/reset.s
@@ -2,9 +2,10 @@
|
||||
; Copyright (c) 2024-2025 Amber Zeller, Gale Faraday
|
||||
; Licensed under MIT
|
||||
|
||||
INCLUDE "buzbee.inc"
|
||||
INCLUDE "hardware.inc"
|
||||
INCLUDE "serial.inc"
|
||||
INCLUDE "memtest.inc"
|
||||
INCLUDE "serial.inc"
|
||||
INCLUDE "version.inc"
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -22,8 +23,8 @@ RESET
|
||||
|
||||
CLRSTACK
|
||||
; Initialize the system stack
|
||||
lda #$00 ; Initialize A & X to zero out the stack
|
||||
ldx #$0000
|
||||
clra ; Init A & X to zero out the stack
|
||||
ldx #0
|
||||
NEXT@
|
||||
sta STACK_BOTTOM,x ; Write a zero and progress to the next byte
|
||||
leax 1,x
|
||||
@@ -35,13 +36,19 @@ BOOTSCR
|
||||
lda #13 ; 9600 baud
|
||||
ldb #%11 ; 8N1
|
||||
jsr INITUART ; Initialize serial console
|
||||
ldx #VERMSG ; Print version information
|
||||
jsr POUTZSTR
|
||||
PZSTR VERMSG ; Print version information
|
||||
|
||||
; Progress to POST
|
||||
POST
|
||||
jsr RAMTEST
|
||||
; Hand off control to the BUZBEE monitor and print notification of leaving the
|
||||
; firmware
|
||||
ENTERMON
|
||||
PZSTR TXTRUN
|
||||
jmp BUZBEE
|
||||
|
||||
HALT
|
||||
sync ; Halt and wait for interrupts
|
||||
bra HALT
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Text/Resources for Reset Handler
|
||||
;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
TXTRUN
|
||||
fcn "<3RUN<3"
|
||||
|
Reference in New Issue
Block a user