| name | pgm-sim-server |
| description | Control the MiSTer PGM simulator through its persistent stdio JSON server. Use when you need structured simulator automation, including loading games or MRAs, running until conditions, reading CPU state, reading or writing memory, saving states, tracing, taking screenshots, starting/stopping binary audio capture, or interacting with exported TestROM GUI state. |
PGM Simulator Server
Use this skill when working with the simulator in sim/ through its machine-readable control interface.
Primary reference:
Workflow
- Start a persistent server process:
cd /Users/akawaka/Source/Arcade-IGSPGM_MiSTer/sim
./sim --server
- Send exactly one JSON request per line on
stdin.
- Read exactly one JSON response per request from
stdout.
- Treat
stderr as logs only.
Rules
- Always call
sim.initialize before other control methods.
- Then call either
sim.load_game or sim.load_mra.
- For normal game startup, call
sim.reset after sim.load_game.
- Prefer
sim.run_until over many tiny sim.run_cycles calls when synchronizing to a CPU or signal condition.
- Use
cpu.get_state, memory.read, and signal.read for observations.
- Use
signal.list to discover which VPI signals are available in the current build.
- For internal HDL signals, use VPI-resolved names like
sim_top.vblank or pgm_inst.cpu_word_addr.
- Use
state.save / state.load for checkpoints.
- Call
sim.shutdown before ending the session when practical.
Recommended request sequence
{"id":1,"method":"sim.initialize","params":{"headless":true}}
{"id":2,"method":"sim.load_game","params":{"name":"pgm"}}
{"id":3,"method":"sim.reset","params":{"cycles":100}}
{"id":4,"method":"sim.run_until","params":{"condition":{"type":"signal_equals","signal":"vblank","value":1},"timeout_cycles":1000000}}
{"id":5,"method":"cpu.get_state","params":{}}
Important methods
sim.initialize
sim.shutdown
sim.status
sim.load_game
sim.load_mra
sim.reset
sim.run_cycles
sim.run_frames
sim.run_until
cpu.get_state
memory.read
memory.write
memory.list_regions
signal.read
signal.list
state.list
state.save
state.load
trace.start
trace.stop
audio_capture.start
audio_capture.stop
video.screenshot
gui.get_state
gui.set_override
gui.press_button
ics2115.get_state
input.set_dipswitch
Read the full method reference in docs/sim-server.md before using less common operations or composing complex conditions.
Condition examples
Wait for vblank:
{"type":"signal_equals","signal":"vblank","value":1}
Wait for an internal HDL signal using VPI name lookup:
{"type":"signal_not_equals","signal":"pgm_inst.cpu_word_addr","value":0}
Wait for a specific PC:
{"type":"cpu_pc_equals","value":4096}
Wait for a PC range while not in reset:
{
"type":"and",
"children":[
{"type":"cpu_pc_in_range","start":4096,"end":8192},
{"type":"not","children":[{"type":"signal_equals","signal":"reset","value":1}]}
]
}
Error handling
If a request fails:
- inspect
error.code
- inspect
error.message
- if state may be ambiguous, call
sim.status
- if initialization or load failed, restart from
sim.initialize
Notes
- The protocol is synchronous: one request, one response.
- Responses are JSON lines on
stdout.
- Logs may still appear on
stderr.
- Keep a single long-lived simulator process per investigation when possible.
- Use
audio_capture.start / audio_capture.stop for simulator audio packet capture; do not rely on old CLI or environment-based capture control.
- Decode simulator packet captures with
python3 utils/capture_stream.py out.wav --input capture.bin.
- Use
ics2115.get_state when debugging sound-chip behavior; it returns global IRQ/timer/host/ROM/audio state plus all 32 decoded voice records.
- For test ROMs that export
gui_data at WORK_RAM[0x0a00], use gui.get_state to inspect the mirrored GUI and gui.set_override / gui.press_button to interact with it.
- The TestROM GUI snapshot is only safe when both magic words match,
count > 0, and lock == 0; the simulator checks this at vblank boundaries.
- Signal lookup first checks built-in aliases, then tries VPI hierarchical lookup.
- Default VPI builds may expose only a subset of internal signals; use
signal.list to inspect availability.