Banking
This commit is contained in:
@@ -4,10 +4,12 @@ This project provides a resident BIOS, an interactive monitor, and ROM-resident
|
||||
applications for a Z80 system with a UART/CTC card at I/O base `20`.
|
||||
|
||||
At reset, a small ROM bootstrap copies only the BIOS and monitor into the top
|
||||
16 KiB of RAM at `C000`. The BIOS initializes interrupt mode 2 and the UART,
|
||||
then starts the monitor. Applications remain in ROM and execute in place while
|
||||
calling the stable BIOS jump table in high RAM. Tiny BASIC is the first such
|
||||
application, linked at ROM address `1000`.
|
||||
16 KiB at `C000`. Before copying, it writes `06` to banking port `00`: ROM
|
||||
remains enabled, banking is enabled, and `C000-FFFF` maps to the upper physical
|
||||
16 KiB. The BIOS then initializes interrupt mode 2 and the UART and starts the
|
||||
monitor. Applications remain in ROM and execute in place while calling the
|
||||
stable BIOS jump table in high RAM. Tiny BASIC is the first such application,
|
||||
linked at ROM address `1000`.
|
||||
|
||||
Connect a terminal at **2400 baud, 8 data bits, no parity, 1 stop bit**.
|
||||
Commands are case-insensitive and all numeric arguments are hexadecimal; an
|
||||
@@ -17,6 +19,7 @@ optional `0x` prefix is accepted.
|
||||
| --- | --- |
|
||||
| `D 8000` | Dump 40 bytes starting at address 8000 |
|
||||
| `D 8000 20` | Dump 20 bytes starting at address 8000 |
|
||||
| `C 8000 BFFF` | Compute the 16-bit additive checksum of an inclusive range |
|
||||
| `W 8000 3E 41 D3 25 C9` | Write bytes starting at address 8000 |
|
||||
| `I 20` | Read I/O port 20 |
|
||||
| `O 20 57` | Write 57 to I/O port 20 |
|
||||
@@ -29,12 +32,41 @@ optional `0x` prefix is accepted.
|
||||
`RET` returns to the monitor. Code that changes the stack pointer, interrupt
|
||||
mode, or UART/CTC setup must restore it before returning.
|
||||
|
||||
`C` adds every byte from the start through the end address, inclusive, and
|
||||
prints the low 16 bits of the sum as four hexadecimal digits. The end address
|
||||
must be greater than or equal to the start address.
|
||||
|
||||
Build the ROM and programmer-format images with:
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
## Uploading Intel HEX files
|
||||
|
||||
`program_ihex.py` can write an Intel HEX file to memory through the running
|
||||
monitor. It sends data in small blocks with `W`, checks every block with `C`,
|
||||
and retries a failed write or checksum before giving up. It requires Python 3
|
||||
and [pySerial](https://pyserial.readthedocs.io/).
|
||||
|
||||
```sh
|
||||
python3 -m pip install pyserial
|
||||
python3 program_ihex.py /dev/ttyUSB0 program.hex
|
||||
```
|
||||
|
||||
The default connection is 2400 baud, the default block size is 16 bytes, and
|
||||
three retries are allowed after the initial attempt. For example:
|
||||
|
||||
```sh
|
||||
python3 program_ihex.py /dev/ttyUSB0 program.hex --retries 5 --block-size 24
|
||||
```
|
||||
|
||||
Use a Windows port such as `COM3` in place of `/dev/ttyUSB0`. Run
|
||||
`python3 program_ihex.py --help` for all options. The monitor must be sitting at
|
||||
its `>` prompt before starting the upload. Only data records present in the HEX
|
||||
file are written; gaps are left unchanged. The HEX addresses must refer to
|
||||
writable memory and must not overwrite the running monitor at `C000-FFFF`.
|
||||
|
||||
The outputs are:
|
||||
|
||||
- `build/metal/monitor.bin`: complete 32 KiB ROM image
|
||||
@@ -44,8 +76,8 @@ The outputs are:
|
||||
The current compact image is 6,157 bytes. Its ROM layout is:
|
||||
|
||||
- `0000-007F`: reset/copy bootstrap
|
||||
- `0080-0F9D`: packed BIOS+monitor image copied to RAM at `C000-CF1D`
|
||||
- `0F9E-0FFF`: unused space reserved for the resident image to grow
|
||||
- `0080-0FEA`: packed BIOS+monitor image copied to RAM at `C000-CF6A`
|
||||
- `0FEB-0FFF`: unused space reserved for the resident image to grow
|
||||
- `1000-180C`: Tiny BASIC, executed directly from ROM
|
||||
- `180D-7FFF`: unused space available for additional ROM content
|
||||
|
||||
@@ -58,13 +90,20 @@ The resulting RAM layout is:
|
||||
- `8000-AFFF`: Tiny BASIC workspace and BASIC program text
|
||||
- `B000-B077`: Tiny BASIC variables and input buffer
|
||||
- `B078-BFFF`: Tiny BASIC stack space
|
||||
- `C000-CF1D`: resident BIOS, vectors, services, and monitor
|
||||
- `CF1E-EFFF`: free space for resident-image growth
|
||||
- `C000-CF6A`: resident BIOS, vectors, services, and monitor
|
||||
- `CF6B-EFFF`: free space for resident-image growth
|
||||
- `F000-FFFF`: BIOS globals, UART buffers, and monitor stack
|
||||
|
||||
The BIOS and monitor continue to work if low ROM is disabled. ROM-resident
|
||||
applications naturally require ROM to remain mapped while they execute.
|
||||
|
||||
The banking latch bits used by the bootstrap are bit 0 `ROM_DISABLE`, bit 1
|
||||
`BANK_SELECT`, and bit 2 `BANK_ENABLE`. Its initial value `06` leaves ROM on and
|
||||
selects the lower physical 48 KiB plus the upper physical 16 KiB. Writing `07`
|
||||
later disables ROM without changing that split mapping. Writing `05` selects
|
||||
the complete upper physical 64 KiB; the monitor remains available because its
|
||||
`C000-FFFF` image was placed in that upper bank during boot.
|
||||
|
||||
## BIOS interface
|
||||
|
||||
Assembly applications include `include/bios.inc` and call these fixed entries:
|
||||
@@ -78,10 +117,25 @@ Assembly applications include `include/bios.inc` and call these fixed entries:
|
||||
| `C05C` | `BIOS_IO_IN` | Read port `A`, returning the value in `A` |
|
||||
| `C05F` | `BIOS_DELAY_MS` | Delay approximately `HL` milliseconds |
|
||||
| `C062` | `BIOS_MONITOR` | Warm-start the monitor; does not return |
|
||||
| `C065` | `BIOS_BANK` | `A=0`: split lower 48K/upper 16K; otherwise select upper 64K |
|
||||
| `C068` | `BIOS_ROM_DISABLE` | Disable ROM while retaining the selected RAM mapping |
|
||||
|
||||
The service wrappers preserve working registers except for documented return
|
||||
values. The monitor uses the corresponding C API declared in `bios.h`.
|
||||
|
||||
The banking latch at port `00` is write-only, so the BIOS keeps a persistent
|
||||
shadow byte initialized to `06` by the copied resident image. `BIOS_BANK`
|
||||
always leaves banking enabled and changes only the bank selection while
|
||||
retaining the shadowed ROM-disable bit and auxiliary-output bits.
|
||||
`BIOS_ROM_DISABLE` sets the ROM-disable bit and is idempotent. Code should not
|
||||
write port `00` through `BIOS_IO_OUT` or the monitor's `O` command after using
|
||||
these services, because such writes bypass the BIOS shadow state.
|
||||
|
||||
The equivalent C API is `bios_bank(uint8_t bank)` and
|
||||
`bios_rom_disable(void)`. A ROM-resident caller cannot return normally after
|
||||
selecting the complete upper 64 KiB or disabling ROM, because its return
|
||||
address is no longer mapped; it must arrange its continuation in RAM.
|
||||
|
||||
Project organization:
|
||||
|
||||
- `boot.asm`: ROM bootstrap, high vectors, BIOS jump table, and assembly glue
|
||||
|
||||
Reference in New Issue
Block a user