Skip to content
Phosphoricwiki
Contents

Debugging and remote control

Phosphoric is not only a machine to play on: it is a bench for understanding a 6502 program. Breakpoints, going back in time, gdb attached to the Oric, and an API to drive everything from outside.

On this page

The built-in debugger

You enter it with F9 during emulation, with -D (--debug) at launch, or on a breakpoint (--break ADDR).

CommandEffect
s, n, cone instruction, one instruction without entering JSRs, continue
step-outrun until the current routine returns
undogo back: up to 16 snapshots of the processor and RAM
r, set reg valview and change the registers
d [addr] [n]disassemble, with symbols resolved in operands
m addr [n]view and change memory
a ADDR MNEMONIC [operand]assemble an instruction into memory
find B1 B2 …, find "text"search memory
b ADDR, b ADDR if EXPRbreakpoint (16 at most), possibly conditional
br LINEraster breakpoint: when the beam reaches a line (8 at most)
w ADDRwrite watchpoint (8 at most)
via, psg, disk, acia, tape, locithe state of the peripherals
stackthe stack

--symbols FILE loads a symbol table (.sym, .lab, EQU, VICE formats): the disassembler and the traces show them.

In text mode

Built with TUI=1 and started with --tui, the debugger shows in a terminal, in six panes: registers, stack, disassembly, memory, breakpoints and watchpoints, status.

gdb, lldb, VS Code

--gdb[=PORT] opens a GDB Remote Serial Protocol server (port 1234 by default). You attach gdb, lldb or a development environment to it:

./oric1-emu -r roms/basic11b.rom --gdb
gdb -ex 'target remote :1234'
(gdb) info registers          # A X Y SP PC P
(gdb) x/8xb 0xfffc            # the vectors
(gdb) break *0xc000
(gdb) stepi
(gdb) set {char}0x0400 = 0xa9

The machine starts stopped at the reset vector; gdb drives. gdb does not know the mos6502 architecture and may say so, but memory, breakpoints and stepping work; the server describes its registers through target.xml.

Traces and the profiler

OptionWhat it writes
--trace FILEone line per instruction: cycles, PC, bytes, disassembly, registers
--cycle-trace FILEone line per cycle: access type, address, data, registers, interrupt lines
--psg-trace FILEeach write to a PSG register, with its cycle
--serial-trace FILEbytes sent and received, and the serial port’s signals
--kbd-scan-trace FILEeach read of the VIA’s port B: to debug a program that scans the keyboard itself
--profile FILEhits and cycles per address, opcode histogram, 20 hot spots
--rom-info [FILE]an analysed ROM: vectors, subroutines, strings, code and data
--dump-ram-when ADDR:VAL:FILEthe 64 KB when a memory location takes a value

Driving from outside: --control

With --control, Phosphoric speaks a text protocol on its standard input and output (logs go to standard error). It was designed for the OricForge development environment. Three kinds of messages:

DirectionPrefixRole
client → emulatornoneone command per line
emulator → clientOK or ERRthe reply
emulator → clientEVTa spontaneous event: ready, stopped, halt

The commands: hello (capability negotiation), regs, set, read, bread (binary), write, peek (a peripheral), break, watch, raster, step, next, step-out, continue, pause (even while running), reset, nmi, load-tap, load-rom, load-sym, load-disk, eject-disk, disasm, keys, hunt (look for a value that changes), state-save, state-load, and more. All numbers are hexadecimal, lengths included.

A demonstration client in Python, with no dependency, is supplied (tests/integration/phos_smoke_client.py).

Driving over HTTP

Built with HTTPAPI=1, --http-api[=PORT] (8888 by default) exposes the same commands over HTTP and JSON, without duplicating the logic:

RequestEffect
GET /hello, /regs, /mem?addr=&len=, /peek/viaread
POST /keys with text=…type on the keyboard: a whole BASIC program, remotely
POST /reset, /nmi, /exec/step, /exec/continue, /exec/pauseact
POST /tape, /disk/A; DELETE /tape, /disk/Achange media
POST /break, /watch, /raster, /state/save, /tracedebug
curl -X POST --data-urlencode 'text=PRINT 2+2\n' http://127.0.0.1:8888/keys

Replies are JSON ({"ok":true,"reply":…}), with CORS. File operations are confined to --http-api-root FOLDER: absolute paths and .. are refused. Commands run on the emulator’s thread, at the frame boundary (decision 0002).

Automating with no display

All these pieces combine without a window:

# Load, wait, type, take a screenshot, record the sound, then exit
./oric1-emu --headless -r roms/basic11b.rom -t prog.tap -f \
    --type-keys '3000000:RUN\n' --screenshot-at 20000000:end.png \
    --audio-wav sound.wav --cycles 20100000
  • --record FILE and --replay FILE record and replay keyboard inputs, to the bit: enough to reproduce a defect or keep a regression test.
  • --screenshot-when ADDR:VAL:FILE takes a screenshot when the program reaches a state (exit code 2 if it never does).
  • --ula-ng-poke and --type-keys-when prepare the machine without guessing the right cycle.

That is exactly how the pictures in the gallery were made.

Sources in the repository : README.md, docs/gdb_remote.md, docs/control_protocol.md, docs/http-api.md, docs/movie_replay.md.