-
Notifications
You must be signed in to change notification settings - Fork 3
EN Debug
Menu path: Debug · Boards: all · Requires: SD card (only for "Save dump to file" and the on-SD log)
Two different things live under the word "debug" in pico-spec, and it helps to keep them apart:
-
The Debug menu (OSD, runtime) — a built-in Z80 debugger you reach from the menu (or hotkeys) while the emulator is running: a single-step source/memory/register view, breakpoints (PC, port and memory), Jump to / Poke / NMI, a memory dump to screen or SD file, and a runtime toggle for the on-SD log. This is the user-facing part and is documented below.
-
Developer logging (build-time / source-level) —
Debug::logto the console UART,Debug::log2SDtodebug.logon SD, and a set of per-subsystem*_TRACEverbose logs that are CMake compile options (off in shipped builds). See Developer logging.
The Debug menu is for inspecting guest (ZX-Spectrum) code at runtime. The trace options are for developers debugging the emulator itself and are not in any menu.
Debug
├── Debug dialog (Alt+F5) open the full-screen Z80 debugger
├── BreakPoint (Alt+F7) add a breakpoint (pick type → address)
├── BP List list/edit breakpoints, jump the debugger to one
├── Jump to set PC to an address (no execution)
├── Input Poke (Alt+F9) write a byte to memory (address/value, optional bank)
├── Trigger NMI (Alt+F10) raise a Z80 NMI
└── Debug Log ▸ Write debug.log [Yes/No] — runtime on-SD log toggle
(Default hotkeys shown — all of these are reconfigurable in Options → Host keys.)
BP List and Jump to no longer have dedicated hotkeys — both actions are still available from the Debug menu. The freed Alt+F8 now defaults to toggle on-screen LED indicators (a new, reconfigurable hotkey).
| Item | Hotkey | What it does |
|---|---|---|
| Debug dialog | Alt+F5 | Opens the full-screen debugger (osdDebug). Disassembly + register panel + memory panel, single-step, breakpoints, search, screen-preview. Keys below |
| BreakPoint | Alt+F7 | Pick a type (PC address / Port read / Port write / Mem write / Mem read) then enter an address. Up to 20 breakpoints, saved to NVS |
| BP List | — | List active breakpoints (type + address), delete with Del; Enter opens the debugger at that address |
| Jump to | — | Set the Z80 PC to a typed address. Changes where execution resumes; does not step |
| Input Poke | Alt+F9 | Write one byte: enter Address + Value (and optionally a RAM bank 0–7). Useful for cheats/patches |
| Trigger NMI | Alt+F10 | Raise a non-maskable interrupt on the Z80 (Z80::triggerNMI). With DivMMC active this is the esxDOS automap NMI; ZX-Byte shows its NMI menu |
| Debug Log | — | Submenu Write debug.log [Yes/No] — turns the on-SD developer log on/off at runtime (see below). Persisted to NVS (debug_log) |
Several of these actions are also bound to hotkeys, so you can open the debugger, add a breakpoint, poke or NMI without going through the menu. BP List and Jump to are menu-only (their old Alt+F7 / Alt+F8 hotkeys were removed).
| Type | Code | Fires when… |
|---|---|---|
| PC address | PC |
the program counter reaches the address |
| Port read | PR |
the guest reads from the I/O port |
| Port write | PW |
the guest writes to the I/O port |
| Mem write | MW |
the guest writes to the memory address |
| Mem read | MR |
the guest reads from the memory address |
When a breakpoint hits, the current frame ends and the debugger view opens. The
running-machine stats line also shows BP(s):N while breakpoints are set.
The debugger (Debug dialog) has three sections you cycle with Tab: Code (disassembly around PC), Memory (a hex/ASCII dump panel) and Regs. Press F1 inside it for the built-in help. Keys:
| Key | Action |
|---|---|
| Space | Step one CPU instruction |
| Alt+Space | Step over a CALL (sets a temporary breakpoint at the return address) |
| Enter | Go to an address (view; in a panel, inline hex edit) |
| Tab | Switch section: Code / Memory / Regs |
| F5 | Toggle a PC breakpoint at the cursor line |
| F7 | Add a breakpoint (choose type) |
| Alt+F7 | Breakpoint list |
| F8 | Set PC to the address at the cursor |
| F2 | Show the guest screen (memory dump preview overlay) |
| Alt+F2 |
Save dump to file → dump.log on SD (range picker first) |
| Alt+F1 | Search memory for a hex byte sequence |
| F3 | Search next |
| Alt+T | Toggle the memory panel between HEX and ASCII |
| Alt+F9 | Show the guest screen full-screen |
| F11 / F12 | Load / Save snapshot |
| + / − / 0 | Shift the screen preview up / down / default |
| PageUp/Down, arrows | Scroll code / move the memory cursor |
| Esc | Exit the debugger |
Alt+F2 in the debugger asks for an address range, then writes a full state dump to
/.config/pico-spec/dump.log (created fresh each time, CREATE_ALWAYS). The dump
contains, in order:
| Section | Contents |
|---|---|
| Header | Dump range #xxxx – #xxxx
|
| Machine |
Arch + RomSet
|
| ROM/paging state |
romInUse, romLatch, bankLatch, videoLatch, pagingLock, page0ram, newSRAM, divmmc
|
| TR-DOS | on/off + TR-DOS BIOS version |
| Registers |
AF BC DE HL (+ alternates AF' BC' DE' HL'), IX IY SP PC, I R IM IFF1 IFF2 Halted
|
| Flags |
S Z H P N C decoded from F |
| Stack | top 8 words (SP+00 … SP+0E) |
| CPU |
T-states + statesInFrame
|
| TR-DOS / WD1793 | TR-DOS state, FDD write-protect A–D, and the FDC: cmd status track sector data drive side dsr led retry state stepState control, plus per-disk tracks / sides / wp / filename
|
| Memory dump | hex + ASCII over the chosen range |
This is the efficient way to capture a complete runtime snapshot for offline analysis, versus single-stepping by hand.
This section is build-time / source-level — none of it is in a menu except the
runtime debug.log toggle above.
Debug::log(fmt, …) prints to the console UART (or printf where there's no debug
UART). It is always compiled in and always fires — no flag. It is best-effort and
lossy under flood: it only writes while the UART TX FIFO has room and drops the rest
rather than blocking (a logging stall in a hot path — e.g. the ZiFi net pump or a tape
loader — would otherwise freeze the main loop or break loader timing).
⚠️ Never log inside a tight loader / hot loop. Even one write perIN A,(0xFE)adds thousands of T-states and breaks turbo tape loaders.
Debug::log2SD(fmt, …) appends timestamped lines to /.config/pico-spec/debug.log
on the SD card. It is gated by a runtime flag, Debug::log_enabled, controlled by
the Debug → Debug Log → Write debug.log [Yes/No] menu toggle (persisted to NVS as
debug_log). When the flag is off the call collapses to a single branch and writes
nothing. The log is capped at 200 KB and wraps (rewritten from the start) when full;
each session starts with a --- BOOT (POWER-ON | WATCHDOG) --- header.
Note: this is a runtime toggle, not the old
DEBUG=1compile define. Turn it on from the menu, reproduce the issue, then readdebug.logoff the SD card.
Verbose per-access traces live in the source but are compiled out unless you build
with the matching CMake option. They are defined in one place (CMakeLists.txt) as
option(... OFF) → -DXXX_TRACE=1/0; sources just use #if XXX_TRACE … #endif. When
off they are true no-ops (no code, no RAM). Enable with e.g.
cmake -B build -DFDD_PORT_TRACE=ON.
| Option | Subsystem traced |
|---|---|
IDE_PORT_TRACE |
PROFI IDE/HDD port access (Ports.cpp, IDE.cpp) |
FDD_PORT_TRACE |
WD1793 (ВГ93) FDD command/port trace |
RTC_PORT_TRACE |
MC146818 (Mr Gluk) RTC ..F7 port access |
PROFI_PORT_TRACE |
0x7FFD / 0xDFFD paging-port writes |
SND_PORT_TRACE |
per-port I/O histogram (sound-DAC port hunting) |
PERF_TRACE |
per-60-frame CPU / HDMI / FPS performance log |
GS_PERF_TRACE |
General Sound per-second perf counters |
GS_DEBUG_TRACE |
General Sound port-IO trace ring + auto-dumps (~50 KB SRAM) |
ZIFI_TRACE |
ZiFi (ESP-01S NIC) port / UART traffic |
ZIFI_NET_VERBOSE |
per-packet ZiFi net-client trace (floods logs) |
⚠️ These flood the console UART and can break timing-sensitive paths (WiFi scan, FTP/transfers, tape loaders). Keep them OFF unless actively debugging that one subsystem, and never ship a build with them on.
Separate per-board CMake switches (MURM1_DBG_UART, PICO_PC_DBG_UART,
PICO_DV_DBG_UART, ZERO_DBG_UART, ZERO2_DBG_UART, all OFF by default) route the
console UART out to a header for a debug probe / serial monitor. Enabling one takes
GPIO pins from other peripherals (e.g. moves the keyboard and disables NESPAD on
MURM1) — see Boards & pinout.
| Path | Purpose |
|---|---|
/.config/pico-spec/debug.log |
Debug::log2SD output (≤ 200 KB, wraps). On when Debug Log is Yes |
/.config/pico-spec/dump.log |
One state+memory dump per Alt+F2 in the debugger (overwritten each time) |
| Action | What it checks | Expected result |
|---|---|---|
| Set a PC breakpoint, run guest code past it | Breakpoint engine | Frame ends, debugger opens at the address; stats show BP(s):1
|
| In the debugger, Alt+F2 with SD present | Dump-to-file |
dump.log created with registers/stack/WD1793/memory; "Dump saved" notice |
| Debug Log → Yes, reproduce, read SD |
log2SD runtime gate |
debug.log grows with timestamped lines + a --- BOOT … --- header |
| Input Poke an address, resume | Poke | The byte changes in memory (and in the debugger Memory panel) |
See Test images.
- Host key reconfiguration: Options
- Board GPIO maps (Debug Probe UART pins): Boards & pinout
- Developer notes: CLAUDE.md
Меню (RU)
Сквозные темы
Для разработчиков