- C 69%
- NSIS 18.9%
- Assembly 5.4%
- DIGITAL Command Language 4.8%
- Python 0.8%
- Other 1%
Use non-blocking I/O on the serial port to prevent the console from becoming unresponsive when the Pico isn't reading CDC data. Use tcflush + os.close instead of ser.close to avoid tcdrain hang on exit. Switch to TCSANOW for immediate terminal restore. Remove non-functional reset-pico command. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| bios | ||
| cpm | ||
| doc | ||
| firmware | ||
| lib | ||
| rom-code | ||
| test-apps | ||
| tools | ||
| volksforth | ||
| .gitignore | ||
| CLAUDE.md | ||
| empty-disk.nsi | ||
| exhibit-image.cfg | ||
| exhibit-text.cfg | ||
| exhibit.cfg.example | ||
| HARDWARE.md | ||
| HEX-LOADING.md | ||
| Makefile | ||
| nsdiagboot-failure.md | ||
| parity-test.bas | ||
| PLAN.md | ||
| README.md | ||
| REWIRE.md | ||
| ROM-FONT.md | ||
| TEST-CPM.md | ||
| TEST-PLAN.md | ||
| vdconfig.nsi | ||
VantaDrive
A Raspberry Pi Pico-based floppy disk emulator for the NorthStar Advantage computer. VantaDrive replaces physical floppy drives by serving disk images from Pico flash storage over the NorthStar PIO board's parallel interface.
It also provides a rapid development workflow: edit Z80 code on a host machine, push the binary to the Pico over USB, press the NMI button on the Advantage, and the program is running in seconds.
How It Works
VantaDrive connects a Raspberry Pi Pico W to the NorthStar Advantage via a PIO (Parallel I/O) board installed in slot 2. The PIO board provides two independent 8-bit data buses with hardware handshaking — one for each direction. The Pico dedicates one CPU core entirely to the PIO handshake, ensuring it can keep up with the Z80 at all times.
A custom two-stage boot ROM ("VantaBIOS") replaces the Advantage's original disk I/O. Stage 1 lives in a 2K EPROM and loads stage 2 from the Pico into RAM. Stage 2 then either runs a development binary or boots an operating system from a disk image.
Host (Mac/Linux) Pico W NorthStar Advantage
| | |
+-- USB serial ----------> | |
| deploy binaries, | <--- PIO board (slot 2) --> |
| manage disk images | P1: Pico -> Z80 (8-bit) |
| | P2: Z80 -> Pico (8-bit) |
| | |
| +-- Flash: disk images +-- VantaBIOS stage 1 (EPROM)
| +-- RAM: dev-mode binary +-- VantaBIOS stage 2 (loaded from Pico)
Two-Stage Boot Process
Stage 1 — EPROM Boot Loader
Stage 1 is a small (~500 byte) program burned into a 2K EPROM that replaces the Advantage's original boot ROM. On power-up or reset, the Z80 begins executing at address 0x0000 where stage 1 resides.
Stage 1 performs these steps:
-
Initialise hardware — set up the stack, install the NMI handler, and perform the mandatory I/O reset cycle (the Advantage's I/O subsystem is in an indeterminate state at power-on and must be explicitly reset before any I/O board will respond).
-
Initialise the display — map the display RAM pages and clear the 640x240 monochrome bitmap screen. All status messages are rendered directly to the bitmap display using a built-in 6x7 pixel font.
-
Detect the PIO board — read the board identification port (0x74) and check for the expected ID byte (0xDB). If no PIO board is found, stage 1 halts with an error message.
-
Contact the Pico — send a
GET_STATUScommand to the Pico and wait for a response. Stage 1 retries up to 10 times with 500ms delays, since the Pico may still be starting up when the Advantage is powered on. -
Load stage 2 — send a
LOAD_PROGRAMcommand. The Pico responds with a 2-byte length followed by the stage 2 binary. Stage 1 receives the data into RAM at address 0xF000. -
Jump to stage 2 — transfer control to 0xF000.
Stage 2 — RAM-Resident BIOS
Stage 2 is not stored in EPROM — it is loaded from the Pico every time the Advantage boots. This means stage 2 can be updated by simply deploying a new binary to the Pico, without touching the EPROM.
Stage 2 occupies 0xF000–0xFBFF (up to 3KB) and provides:
-
Mode detection — sends
GET_STATUSto the Pico. The response flags indicate what content is available:- Dev mode (flag 0x01): a development binary has been deployed to the Pico via USB. Stage 2 loads it into RAM at 0xC000 and jumps to it.
- Disk mode (flag 0x02): disk images are available on the Pico. Stage 2 presents a boot menu for image selection and boots the OS.
-
Dev mode — loads a program from the Pico into 0xC000–0xEFFF (up to 12KB) and executes it. The dev binary persists on the Pico across resets, so pressing the NMI button will re-run the same program. To deploy a different binary, use
deploy.pyon the host and press the NMI button on the Advantage. -
Disk mode (planned) — image selection menu, NorthStar OS bootstrap, and a CP/M-compatible BIOS shim at 0xFC00 that translates OS disk I/O calls into VantaDrive protocol commands.
Memory Map When Stage 2 Is Running
| Address Range | Contents |
|---|---|
| 0x0000–0x07FF | Boot EPROM (stage 1, still mapped) |
| 0x4000–0x7FFF | Display RAM page 8 (columns 0–63) |
| 0x8000–0xBFFF | Display RAM page 9 (columns 64–79) |
| 0xC000–0xEFFF | User program / OS load area |
| 0xF000–0xFBFF | Stage 2 code |
| 0xFC00–0xFFCF | BIOS shim jump table (planned) |
| 0xFFD0–0xFFEF | Display state variables |
| 0xFFF0–0xFFFF | Stack |
Communication Protocol
Physical Layer
The Pico and the Advantage communicate through the PIO board's two DB-15 connectors, each carrying an independent 8-bit data bus with hardware handshake signals:
-
P1 (lower connector) — Input port, Pico to Z80. The Pico drives 8 data lines (GP0–GP7) and pulses /in_strobe (GP16) to latch data. The PIO board sets /in_flag when data is ready. The Z80 polls for /in_flag, reads the byte, and resets the flag. The Pico watches /in_flag (GP17) to confirm the Z80 has read each byte before sending the next.
-
P2 (upper connector) — Output port, Z80 to Pico. The Z80 writes to port 0x40 to latch the data, then accesses port 0x45 to assert /out_flag (the write alone does not signal the Pico). The Pico reads the byte from GP8–GP15 and asserts /out_ack (GP19). The PIO board clears /out_flag, and the Z80 sees the acknowledgement in the status register.
All signals are active low. The Pico's 3.3V outputs meet TTL input thresholds, and its GPIO inputs are 5V-tolerant, so no level shifting is needed.
Byte Transfer Timing
Each byte transfer takes approximately 17 microseconds, giving a throughput of about 57 KB/s. A 256-byte disk sector transfers in roughly 4.5 milliseconds.
The Pico runs its PIO handler on a dedicated CPU core (Core 1) to ensure deterministic response times. Core 0 handles USB serial communication, storage management, and the status LED.
Command Protocol
All communication is initiated by the Z80. Each transaction begins with a 4-byte command block sent from the Z80 to the Pico:
| Byte | Contents |
|---|---|
| 0 | Opcode |
| 1 | Parameter 1 |
| 2 | Parameter 2 |
| 3 | Parameter 3 |
The Pico responds with a status byte (0x00 = success, 0x80+ = error), optionally followed by a data phase whose format depends on the command.
Commands
GET_STATUS (0x03)
Reports what content is available on the Pico.
- Parameters: none (all zero)
- Response: status byte, then a flags byte:
- Bit 0 (
VD_STATUS_DEV_MODE): a dev-mode binary is loaded - Bit 1 (
VD_STATUS_DISK_MODE): disk images are available
- Bit 0 (
Used by both stage 1 (to verify the Pico is alive) and stage 2 (to decide which mode to enter).
LOAD_PROGRAM (0x04)
Transfers a binary from the Pico to the Z80.
- Parameters: none (all zero)
- Response: status byte, then 2-byte length (little-endian), then the program data
Stage 1 uses this to load stage 2 (into 0xF000). Stage 2 uses it to load a dev-mode binary (into 0xC000). The dev binary persists on the Pico and can be served again on subsequent resets.
READ_SECTOR (0x01)
Reads a 256-byte sector from a disk image.
- Parameters: track (0–69), sector (0–9), drive number
- Response: status byte, then 256 bytes of sector data
Tracks 0–34 are side 0, tracks 35–69 are side 1 (matching the NorthStar .nsi disk image format: 35 tracks x 2 sides x 10 sectors x 256 bytes = 179,200 bytes per image).
WRITE_SECTOR (0x02)
Writes a 256-byte sector to a disk image.
- Parameters: track (0–69), sector (0–9), drive number
- Response: status byte (ready to receive), then the Z80 sends 256 bytes of data, then the Pico sends a final status byte confirming the write
SET_IMAGE (0x05)
Selects which disk image to mount on a given drive.
- Parameters: image index, 0, 0
- Response: status byte
LIST_IMAGES (0x06)
Lists available disk images on the Pico.
- Parameters: none (all zero)
- Response: status byte, image count, then image name data
Error Codes
| Code | Name | Meaning |
|---|---|---|
| 0x00 | OK | Success |
| 0x81 | BAD_OPCODE | Unknown command |
| 0x82 | BAD_SECTOR | Sector number out of range |
| 0x83 | BAD_TRACK | Track number out of range |
| 0x84 | NO_IMAGE | No disk image mounted / no binary available |
| 0x85 | WRITE_FAIL | Write to storage failed |
| 0x86 | CRC | CRC error |
USB Deploy Protocol
Development binaries and disk images are loaded onto the Pico over USB
serial from the host machine using tools/deploy.py. The deploy protocol
uses a simple framed packet:
[0x56 'V'] [command] [length_lo] [length_hi] [data...] [crc_lo] [crc_hi]
The CRC is CRC-16/CCITT. The Pico responds with ACK (0x06) or NAK (0x15).
Deploy commands:
0x01— deploy a dev-mode binary (max 16KB)0x02— upload a disk image0x03— list images0x04— delete an image
Usage:
python3 tools/deploy.py program.bin # deploy dev binary
make deploy BIN=path/to/program.bin # same, via Makefile
Building
Z80 Code
Requires the pasmo Z80 assembler and memsim2 EPROM emulator tool.
make # build all Z80 code (ROMs, BIOS, test apps)
make bios # build VantaBIOS stage 1 + stage 2
make bios-upload # upload stage 1 to EPROM emulator
make deploy BIN=app.bin # deploy binary to Pico via USB
Pico Firmware
Requires the Raspberry Pi Pico SDK (PICO_SDK_PATH environment variable).
cd firmware
mkdir -p build && cd build
cmake .. && make
Flash the resulting vantadrive.uf2 by holding BOOTSEL on the Pico,
connecting USB, and copying the file to the RPI-RP2 drive that appears.
LED Status
The Pico W onboard LED indicates the current state:
| Pattern | Meaning |
|---|---|
| Slow blink (1s period) | Waiting for NorthStar power |
| Brief flash every 2s | Connected, idle |
| Solid on | Data transfer in progress |
Hardware
See HARDWARE.md for complete wiring tables (Pico GPIO to DB-15 pin mapping) and TEST-PLAN.md for the step-by-step bring-up procedure.