Host Tools¶
ROM building and host-side control of the Pico live in the separate
Romulan repository, checked out as a sibling
of this repo (for example ~/Downloads/romulan). Romulan assembles ROM images from
annotated hex and speaks the v1 Hardware API over the framed serial link.
Set it up once:
cd ~/Downloads/romulan
uv sync
Workflow¶
Build and upload a ROM, then capture the bus:
uv run romulan program.txt --build --upload # assemble + upload via Hardware API
uv run romulan hardware upload bin/rom.bin --port /dev/ttyACM0
uv run romulan hardware capture --max-cycles 500 --port /dev/ttyACM0
Note
rom_image[] is lost on Pico power-cycle — re-upload after each reboot.
HTTP REST API¶
Romulan also exposes an HTTP REST server, so any client (curl, browser, CI) can drive the device without speaking the framed serial protocol directly:
PICO_PORT=/dev/ttyACM0 uvicorn api_server:app --host 127.0.0.1 --port 8080
curl http://127.0.0.1:8080/v1/status
curl -X POST http://127.0.0.1:8080/v1/reset -H 'Content-Type: application/json' -d '{"assert":true}'
curl -X POST http://127.0.0.1:8080/v1/rom --data-binary @bin/rom.bin
OpenAPI docs are served at http://127.0.0.1:8080/docs.
Python client¶
from romulan.hardware_api import HardwareAPI
with HardwareAPI("/dev/ttyACM0") as api:
print(api.status())
api.reset(assert_reset=True) # hold CPU in reset
api.upload_rom(open("bin/rom.bin", "rb").read()) # chunked, base64-encoded upload
api.reset(assert_reset=False) # release → run
capture = api.read_until_stp(max_cycles=500) # disables monitor; ~12 s/frame
print(capture.reason, len(capture.cycles))
read_until_stp() captures one JSON event per PHI2 rising edge until the CPU fetches STP
(0xDB) or max_cycles is reached. At the default 0.2 Hz clock, frames arrive about every
5 s (the host waits up to 12 s per frame).
Demo program¶
Romulan’s sample program ends in STP so automated capture stops deterministically:
$8000: CLC
LDA #$05
STA $4000 ; visible via read / monitor
ADC #$0F ; A = 20
STA $4000
STP ; stops read_until_stp capture (opcode $DB)
$FFFC: $8000 ; reset vector