picoZ80 User Manual

picoZ80 User Manual

The picoZ80 is a drop-in replacement for a Z80 CPU in any DIP-40 socketed computer. It plugs directly into the Z80 socket of your vintage computer and — without any modifications to the host board — provides expanded memory, virtual peripherals, floppy and QuickDisk emulation, filing systems, and a browser-based management interface over WiFi.
This manual covers the physical board, initial setup, connecting to a host machine, and using the web interface. For architecture details, configuration reference, and development information see the picoZ80 Technical Guide.

Board Overview

The picoZ80 PCB is designed to fit within the footprint of a standard 40-pin DIP package. All 40 DIP pins emerge from the underside of the board, exactly matching the pin-out of a real Z80, so it drops straight into any Z80 socket without bending or adapting.
The top surface of the board carries all active components. The board is narrower than most Z80 computers' internal clearances, and the height above the socket is within the envelope of a standard IC with a DIP-40 socket fitted underneath.

Connectors and Indicators

The picoZ80 board exposes the following connectors and indicators:
Item Description
6-pin Debug Header Located on the board edge. Provides SWD (Serial Wire Debug) access to the RP2350, BOOTSEL and Reset lines for initial flashing, and Reset for the ESP32. See Debug Header Pinout below.
USB Port (Mini-B) USB connectivity for firmware flashing via USB mass-storage (initial flash) and for USB-UART bridging to the ESP32. On board revisions v2.3a and later a second dedicated USB port for the ESP32 may also be present.
SD Card Slot Full-size SD card slot managed by the ESP32. Holds config.json, ROM images, disk images, and filing system trees.

Debug Header Pinout

The 6-pin header is the primary hardware interface for initial programming and source-level debugging. The pins are numbered from Pin 1 at the end closest to the board edge marker.
Pin Signal Function
1 SWCLK Serial Wire Debug clock (ARM SWD)
2 SWDIO Serial Wire Debug data (ARM SWD)
3 Reset RP2350 Active-low reset for the RP2350. Pull low to reset the RP2350.
4 Reset ESP32 Active-low reset for the ESP32. Pull low to hold ESP32 in reset.
5 GND Ground reference
6 BOOTSEL RP2350 boot mode select. Hold low during power-on/reset to enter USB mass-storage mode.

NB. Pins 1, 2, and 5 are used for SWD debugging (SWCLK, SWDIO, GND). Pins 3 and 6 are used only for initial flashing. Pin 4 is used when you need to prevent the ESP32 from starting during RP2350 boot (e.g. during initial ESP32 firmware programming).


Getting Started

Follow these steps in order the first time you set up a picoZ80 board:
  1. Flash the RP2350 bootloader via USB mass-storage mode (BOOTSEL).
  2. Flash the ESP32 firmware via esptool.
  3. Prepare an SD card with config.json and any required ROM/disk images.
  4. Install the picoZ80 in the Z80 socket of your host computer.
  5. Power on, connect to the picoZ80 web interface, and configure as required.

Step 1 — Flash the RP2350 Bootloader

The RP2350 does not have physical BOOTSEL or Reset buttons. Both signals are available on the 6-pin debug header. To enter the USB mass-storage bootloader:
  1. Do not insert the picoZ80 into a host computer yet — connect it to a PC by USB cable only.
  2. Using a jumper or probe, hold Pin 6 (BOOTSEL) low.
  3. Apply power to the USB port — the RP2350 starts booting.
  4. Release BOOTSEL promptly after the board enumerates as a USB mass-storage device. (If you hold BOOTSEL too long after reset the RP2350 cannot access the Flash chip.)
  5. The PC will mount a drive labelled RPI-RP2 (or similar).
  6. Copy Bootloader_<version>.uf2 to the mounted drive. The RP2350 self-flashes and reboots automatically.
After flashing the bootloader, all subsequent RP2350 firmware updates can be performed wirelessly via the web OTA page — you do not need to touch the debug header again for normal firmware updates.

Step 2 — Flash the ESP32 Firmware

The ESP32 firmware is flashed using esptool. On board revisions v2.3a and later, the ESP32 has its own USB port and appears independently on the host PC. On earlier revisions (v2.0 – v2.2), the ESP32 is accessed through the RP2350 acting as a USB-UART bridge.
Set up the Python environment (once only):
python3 -m venv ./venv/
source ./venv/bin/activate
cd $HOME/esptool
Then flash all four ESP32 firmware components. Adjust PORT to the device node assigned by your OS:
PORT=/dev/ttyUSB0       # Linux — adjust as required
# PORT=/dev/tty.usbmodem141403  # macOS

BINPATH=/path/to/esp32/build

python3 ./esptool.py \
  -p ${PORT} -b 115200 \
  --before default_reset --after hard_reset \
  --chip esp32s3 \
  write_flash \
  --flash_mode dio --flash_size 4MB --flash_freq 80m \
  0x0     ${BINPATH}/bootloader.bin \
  0x8000  ${BINPATH}/partition-table.bin \
  0x9000  ${BINPATH}/ota_data_initial.bin \
  0x10000 ${BINPATH}/sd_card.bin

NB. All subsequent ESP32 firmware updates can be performed via the OTA web page (ota-esp32.htm) once the initial flash is complete.

Step 3 — Prepare the SD Card

The SD card is the primary storage medium for the picoZ80. It holds the configuration file, ROM images, disk images, and filing system directories.
Format requirements:
  • FAT32 file system.
  • Any capacity supported by FAT32 (typically up to 32GB is recommended for reliable formatting).
Minimum required files:
  • config.json in the SD card root — the main configuration file. See Basic Configuration for a minimal example.
  • webfs/ directory — the ESP32 web interface assets. Copy the contents of the webfs/ directory from the project repository to the SD card root.
Optional but recommended directories:
Directory Contents
MZF/ MZF format program files for loading via the filing system
ROM/ ROM images referenced by config.json
DSK/ Floppy disk images (DSK format) for WD1773 emulation
QD/ QuickDisk images for QuickDisk emulation
TZFS/ TranZPUter Filing System trees
RFS/ ROM Filing System program trees
The SD card can be managed entirely through the web File Manager once the picoZ80 is running — you can upload ROM images, edit `config.json`, and create directories from the browser without physically removing the card.

Step 4 — Install in the Host Computer

Safety first: Always power off and unplug the host computer before installing or removing the picoZ80. The board operates at 3.3V internally; the DIP-40 pins connect to the 5V host bus through appropriate interface circuitry, but the board must never be inserted or removed while powered.
Installation procedure:
  1. Power off the host computer and discharge any static.
  2. Remove the existing Z80 CPU chip from its DIP-40 socket. A chip extractor tool is recommended to avoid bending pins.
  3. Insert the SD card into the picoZ80 SD card slot.
  4. Align the picoZ80 with the Z80 socket, ensuring that Pin 1 of the picoZ80 (marked with a dot or notch) aligns with Pin 1 of the socket (also marked, and typically adjacent to the notch on the IC outline silkscreen).
  5. Press the picoZ80 gently and evenly into the socket. Ensure all 40 pins are seated. Do not force — if resistance is felt, remove and check pin alignment.
  6. Power on the host computer.
On first power-on after a fresh firmware install, the ESP32 will start in Access Point mode, broadcasting a WiFi network named picoZ80. Connect to this network to access the web interface and complete initial WiFi configuration.

NB. The picoZ80 draws power from the 5V supply on the Z80 socket VCC pin. The on-board buck converter delivers 3.3V to all board components. Ensure your host computer's 5V supply can deliver at least 500mA — the picoZ80 can draw up to 400mA under peak load (RP2350 at 300MHz with WiFi active).


WiFi Setup

WiFi connectivity requires the antenna matching network to be populated on the PCB and the ESP32 firmware to be built with WiFi enabled. See the Regulatory Notice below. If using NCM-only firmware, skip this section and use the USB NCM connection instead.
The picoZ80 ESP32 co-processor provides WiFi connectivity. On first boot (or when no WiFi credentials have been saved) the ESP32 starts in Access Point (AP) mode so that you can connect to it from any device with a browser and configure your home network settings.

Connecting in Access Point Mode

  1. On your phone, tablet, or laptop, open the WiFi settings and look for a network named picoZ80 (or as configured in the esp32.wifi.ssid field of your config.json when in AP mode).
  2. Connect to the picoZ80 network. The default AP password is pZ80pZ80 (check your firmware release notes if this has changed).
  3. Open a browser and navigate to http://192.168.4.1 — this is the default AP mode IP address. The picoZ80 web interface will appear.
  4. Navigate to the WiFi Manager page to enter your home network SSID and password.
  5. Click Save & Connect. The ESP32 will reboot and connect to your home network as a client.

Client (Station) Mode

Once configured for client mode, the ESP32 joins your home WiFi network and is reachable at the IP address shown on the Dashboard page. If you set a fixed IP in `config.json` (recommended for ease of access), navigate directly to:
http://192.168.1.192
Substitute the IP address you configured. If you are using DHCP, find the assigned address from your router's DHCP client list.
The web interface runs entirely in your browser. No additional software is required. The picoZ80 web server runs on port 80.

USB NCM Connection (No WiFi Required)
If the board is built with the NCM firmware (sdkconfig.mode_ncm_only or sdkconfig.mode_wifi_and_ncm), a virtual Ethernet adapter appears on the host computer when the ESP32 USB port is connected. The picoZ80's built-in DHCP server automatically assigns the host an IP address — no manual network configuration is needed.
  1. Connect a USB cable from the host computer to the ESP32 USB port on the picoZ80.
  2. Wait a few seconds for the host operating system to detect the new network adapter.
  3. Open a web browser and navigate to http://192.168.7.1.
  4. The picoZ80 Dashboard page should appear.
This mode provides full access to all web interface features: configuration editing, firmware updates, file management, and persona selection. No WiFi antenna or radio components are required.

Web Interface

The picoZ80 web interface is an eight-page Bootstrap 4 application served by the ESP32. All pages — including the new GUI Configuration editor — are accessible from the navigation bar at the top of each page. The web assets are stored in the webfs/ directory on the SD card and can be updated independently of the firmware.

Dashboard (index.htm)

The Dashboard is the home page of the web interface. It displays real-time system information and provides a quick overview of the picoZ80 state.
Information shown on the Dashboard includes:
  • Firmware Version — the currently running RP2350 firmware version and build date.
  • ESP32 Version — the ESP32 co-processor firmware version.
  • Active Partition — which of the two firmware slots (1 or 2) is currently active.
  • Active Persona — the machine personality currently loaded (e.g. MZ-700, MZ-80A).
  • RP2350 Clock — current CPU frequency in MHz.
  • PSRAM Clock — current PSRAM SPI clock frequency.
  • WiFi Status / Network Status — in WiFi modes: mode (AP or client), SSID, and assigned IP address. In NCM Only mode: this panel is titled Network Configuration and shows the USB NCM network status (IP address, netmask) — there are no WiFi-related fields.
  • WiFi RSSI (WiFi modes only) — live received signal strength indicator (dBm) that auto-updates every three seconds. Colour-coded: green (≥ −50 dBm, excellent), blue (≥ −70 dBm, good), orange (≥ −80 dBm, fair), or red (< −80 dBm, poor). Not shown in NCM Only mode.
  • WiFi TX Power (WiFi modes only) — current transmit power in dBm, also live-updated. Not shown in NCM Only mode.
  • SD Card — whether an SD card is present and the filesystem mount status.
  • Uptime — time since last reboot.
The Dashboard also provides buttons to reboot the RP2350 and to trigger a configuration reload from the SD card without a full reboot.

Config Editor (config.htm)

The Config Editor page provides an in-browser editor for the config.json file stored on the SD card. The editor features syntax highlighting and basic JSON validation.
To edit the configuration:
  1. Navigate to the Config Editor page.
  2. The current config.json is loaded into the editor automatically.
  3. Make your changes. The editor will highlight syntax errors in red.
  4. Click Save to write the updated file back to the SD card.
  5. Click Apply (or reboot) to apply the new configuration. The RP2350 reads the config at boot, minifies it, and stores it in Flash — subsequent boots use the Flash copy if no SD card is present.
Changes to the memory map, ROM images, and I/O map take effect on the next RP2350 reset. Changes to WiFi settings in the esp32.wifi block take effect on the next ESP32 reboot.

NB. The Config Editor operates directly on the SD card file. It is good practice to keep a backup copy of a working config.json on your PC before making significant changes.

GUI Configuration (configgui.htm)

The GUI Configuration page provides a graphical alternative to the raw JSON Config Editor. All configuration settings are presented as labelled input fields, dropdown menus, and editable tables, organised into four tabs:
  • RP2350 Global — global core voltage, CPU frequency, and PSRAM frequency settings that apply to both partitions.
  • Partition 1 / Partition 2 — per-partition memory map (address, size, type, wait states, bank, ROM file), I/O port map (address, size, type, handler), and driver configuration. Each section has add/remove buttons for rows.
  • ESP32 — WiFi SSID, password, IP address, netmask, mode (AP/Client), DHCP, and TX power settings.
Click Save Configuration to write changes to config.json (previous version is backed up) and automatically reload the RP2350 configuration. Click Reload to re-read the current config.json from the SD card, discarding any unsaved changes. For advanced editing beyond what the GUI exposes, use the Config Editor to modify the raw JSON directly.

File Manager (filemanager.htm)

The File Manager provides a browser-based view of the SD card contents. You can navigate directories, upload new files (ROM images, disk images, MZF program files), download existing files to your PC, create new directories, and delete files and directories.
Common tasks in the File Manager:
  • Upload a ROM image — navigate to the ROM/ directory and use the Upload button to transfer the ROM file from your PC.
  • Upload a disk image — navigate to DSK/ (floppy) or QD/ (QuickDisk) and upload the image file. Once loaded, the current disk image filename is displayed in the Actions menu next to each floppy and QD slot for quick reference.
  • Upload MZF programs — navigate to MZF/ or the relevant filing system directory and upload your MZF files.
  • Backup config.json — click the download icon next to config.json to save a copy to your PC.
File operations are performed directly on the SD card via the ESP32. Large file uploads may take a few seconds depending on file size and WiFi signal quality.

Persona Selection (personality.htm)

The Persona Selection page allows you to choose which machine personality (persona) the picoZ80 presents to the host computer. Different personas load different memory maps, ROM images, and virtual driver bindings from the configuration.
Currently supported Sharp MZ personas:
  • MZ-700 — full MZ-700 persona with bank switching, virtual video, keyboard I/O, WD1773 floppy emulation, QuickDisk emulation, and ROM Filing System. Includes CP/M v2.23 (48K), SA-1510 BASIC, and Microsoft BASIC v4.7, all with SD card read/write access.
  • MZ-80A — MZ-80A persona (in development).
  • MZ-80B — MZ-80B persona (in development).
  • MZ-800 — MZ-800 persona (in development).
Switching persona changes the active memory map and loaded ROM images without rebooting the host. The picoZ80 reinitialises its memory banking to the new persona's configuration and the host sees the new memory layout on the next Z80 bus transaction.

Firmware Updates (OTA)

Firmware for both the RP2350 and the ESP32 can be updated over-the-air (OTA) from the web interface without any physical access to the debug header.

RP2350 OTA Update (ota-rp2350.htm)
  1. Build the RP2350 firmware using the build scripts — the output binary will be in fw/bin/ with a version-stamped filename (e.g. BaseZ80_v3.009.bin).
  2. Navigate to http://<device-ip>/ota-rp2350.htm.
  3. Select which partition slot to update (Slot 1 or Slot 2). The currently active slot is shown on the Dashboard — it is good practice to update the inactive slot so that the existing firmware remains available if the update fails. Two optional checkboxes are available: Clear App Config wipes the ROM images and configuration data for the target slot, and Clear Flash Header resets the partition table to factory defaults — use these when upgrading to a firmware version with an incompatible configuration schema.
  4. Click Choose File, select the .bin file, then click Upload.
  5. Wait for the upload and verification to complete. The page will confirm success and show the new partition as available.
  6. To activate the new firmware, navigate to the partition selection section of the same page, choose the newly updated slot, and click Set Active & Reboot. The RP2350 reboots into the new firmware.
Application partitions use pure binary format (not UF2) because they reside at non-standard flash addresses. The bootloader verifies the image checksum before activating the new partition — if verification fails, the existing active slot remains in use.

ESP32 OTA Update (ota-esp32.htm)
  1. Build the ESP32 firmware — the output binary is esp32/build/tzpuPico_esp32.bin.
  2. Navigate to http://<device-ip>/ota-esp32.htm.
  3. Click Choose File, select the .bin file, then click Upload.
  4. The ESP32 reboots automatically into the new firmware after a successful upload.
The OTA page also accepts a FilePack archive to update the web interface assets stored in the webfs/ directory on the SD card. This allows the web UI to be updated independently of the ESP32 firmware binary.

WiFi Manager (wifimanager.htm)

Note: The WiFi Manager page is only available when the ESP32 firmware is built with WiFi enabled (sdkconfig.mode_wifi_only or sdkconfig.mode_wifi_and_ncm). In NCM Only mode this page is not present — network connectivity is provided automatically via USB NCM with no user configuration required.
The WiFi Manager page configures the ESP32 wireless network settings. Changes made here are persisted in the ESP32 NVS (non-volatile storage) and take effect on the next reboot.
Available settings:
  • WiFi ModeAccess Point (the picoZ80 creates its own network) or Client (the picoZ80 joins an existing network).
  • SSID — the network name to create (AP mode) or join (client mode).
  • Password — the WiFi passphrase.
  • IP Address / Netmask / Gateway — fixed IP settings for client mode (recommended for consistent access).
  • DHCP — enable to obtain an address from your router automatically; disable to use the fixed IP settings above.
  • TX Power — WiFi transmit power in 0.25 dBm units (range 8–84, i.e. 2–21 dBm). Set to 0 to use the region-specific default. The picoZ80 PCB is designed for minimal RF radiation, so when the board is installed inside a metal computer case the signal to the router may be weak. Increasing TX Power can improve connectivity at the expense of slightly higher power consumption; decreasing it can reduce interference in environments with many WiFi devices. The current RSSI and effective TX Power are shown on the Dashboard and on this page, updated live every three seconds.
After saving, click Reboot ESP32 to apply the new settings. The ESP32 will restart and connect using the new configuration. If client mode connection fails (wrong SSID or password), the ESP32 will fall back to Access Point mode after a timeout, allowing you to reconnect and correct the settings.

Basic Configuration

All picoZ80 behaviour is controlled by config.json on the SD card. The following is a minimal working configuration for a Sharp MZ-700. Refer to the Technical Guide — Configuration Reference for a full description of all options.
{
  "esp32": {
    "core": {
      "device": "Z80",
      "mode":   0
    },
    "wifi": {
      "override":  1,
      "wifimode":  "client",
      "ssid":      "YourNetwork",
      "password":  "YourPassword",
      "ip":        "192.168.1.192",
      "netmask":   "255.255.255.0",
      "gateway":   "192.168.1.1",
      "dhcp":      0,
      "webfs":     "webfs",
      "persist":   0
    }
  },
  "rp2350": {
    "core": {
      "cpufreq":   300000000,
      "psramfreq": 133000000,
      "voltage":   1.10
    },
    "z80": [
      {
        "memory": [
          {
            "enable":   1,
            "addr":     "0x0000",
            "size":     "0x1000",
            "type":     "ROM",
            "bank":     0,
            "tcycwait": 0,
            "tcycsync": 0,
            "task":     "",
            "file":     "/ROM/mz700.rom",
            "fileofs":  0
          },
          {
            "enable":   1,
            "addr":     "0x1000",
            "size":     "0xCFFF",
            "type":     "RAM",
            "bank":     0,
            "tcycwait": 0,
            "tcycsync": 0,
            "task":     "",
            "file":     "",
            "fileofs":  0
          },
          {
            "enable":   1,
            "addr":     "0xD000",
            "size":     "0x3000",
            "type":     "PHYSICAL_VRAM",
            "bank":     0,
            "tcycwait": 2,
            "tcycsync": 1,
            "task":     "",
            "file":     "",
            "fileofs":  0
          }
        ],
        "io":      [],
        "drivers": []
      }
    ]
  }
}
This example maps:
  • 0x0000 – 0x0FFF — 4KB ROM loaded from /ROM/mz700.rom on the SD card into PSRAM bank 0.
  • 0x1000 – 0xCFFF — 48KB RAM in PSRAM bank 0 (read/write, zero wait states).
  • 0xD000 – 0xFFFF — 12KB passed through to the physical host hardware (VRAM and I/O registers), with 2 wait states and T1 synchronisation enabled.

ICE (Debug Shell)

The picoZ80 includes a built-in interactive debug shell (ICE — In-Circuit Emulator) for real-time inspection and control of the Z80 CPU emulation.
The ICE debug shell is included in the DBGSH firmware variant. If using the standard firmware, the debug shell is not available. Flash the DBGSH variant to enable ICE functionality.
Connecting: The debug shell is available on the second USB serial port. When the picoZ80 is connected via USB, two serial ports appear on the host computer — the first is the standard debug log output, the second is the debug shell. Open it with any terminal emulator at 115200 baud, 8N1. The prompt dbg> appears when connected.
Key capabilities:
  • Register inspectionregs displays all Z80 registers, flags, and cycle count.
  • Memory dumpdm p 0000 100 dumps 256 bytes from address 0x0000 via the physical bus; dm v 0000 100 reads virtual PSRAM directly.
  • Breakpointsbp E800 sets a breakpoint at 0xE800. Up to 8 breakpoints. bl lists them, bc * clears all.
  • Single-stephold pauses the CPU, then step executes one instruction showing before/after register state.
  • Execution tracetrace on records every executed instruction. trace dump 20 shows the last 20 with disassembly.
  • Disassemblydis v E800 20 disassembles 32 instructions from 0xE800.
  • I/O accessin D8 reads port 0xD8; out D8 03 writes 0x03 to port 0xD8.
  • System infostatus shows CPU frequency, PSRAM clock, emulation speed, and uptime. drivers lists active drivers.
Type help at the prompt for a quick summary.

Command Reference
The complete ICE command set is listed below. All address and data values are entered in hexadecimal without a 0x prefix.
Command Parameters Description
help Display a summary of all available commands.
regs Dump the complete Z80 register set: main registers (AF, BC, DE, HL), alternate registers (AF’, BC’, DE’, HL’), index registers (IX, IY), stack and program counter (SP, PC), interrupt state (I, R, IM, IFF1, IFF2), decoded flags (S, Z, H, P/V, N, C), HALT line state, MEMPTR, and the cumulative T-cycle count.
dm <p|f|v|r> <addr> [len] Dump memory in hex and ASCII. Four modes: p (physical) reads via the Z80 bus triggering real hardware; f (fetch) reads using M1 fetch cycles; v (virtual) reads PSRAM directly with no bus activity; r (RP2350) reads the microcontroller’s own address space (Flash, SRAM, peripherals). addr is the start address, len is the number of bytes (default 256).
cmp [f] <phys> <virt> <len> Compare physical bus memory with virtual PSRAM. Optional f uses fetch (M1) cycles instead of read cycles. Reports mismatches with addresses and values.
dis [p|v] [addr] [count] Disassemble Z80 machine code. p reads opcodes from the physical bus, v from virtual PSRAM (default). addr defaults to the current PC. count is the number of instructions (default 16). The current PC is marked with >.
asm [addr] Enter the interactive Z80 assembler at addr (default: current PC). Type Z80 mnemonics one per line; assembled bytes are written to virtual PSRAM and the address advances. Supports db and dw/defw directives. Enter an empty line or . to exit.
memmap [block] Display the SRAM memory-block pointer table. Each entry shows the block number, Z80 address range, memory type (PHYSICAL, RAM, ROM, FUNC), bank number, and PSRAM offset. If block is given, show only that 512-byte block.
memptr [addr] Display the PSRAM memPtr/memioPtr tables for the given address, showing the handler function pointer and attributes.
iomap [port] Display the I/O port handler table. Each entry shows the port address, handler function, and direction (read/write/both). If port is given, show only that port.
status System status overview: RP2350 CPU frequency, PSRAM SPI clock, host Z80 clock, emulation speed ratio, free SRAM, and uptime.
ver Display firmware version, build date, flash partition layout (address, size, checksum, active flag), author, and licence.
drivers List all active machine persona drivers and their sub-interfaces, showing initialisation status.
hold Pause Z80 CPU emulation. Core 1 finishes the current instruction and stops fetching. The shell waits for the hold to be acknowledged before returning. Required before using out or other commands that modify running state.
release Resume Z80 CPU emulation from the point it was held. Breakpoints remain active.
go Continue execution (same as release). If a breakpoint is subsequently hit, the CPU will hold again automatically.
cont Alias for go. Continue execution from the current hold point. Breakpoints remain active.
step [n] Single-step one instruction (or n instructions). For each step the shell displays the register state before execution, the disassembled instruction with hex bytes, and the register state after execution. The CPU must be held first. If a breakpoint is hit during multi-step, execution stops early.
bp <addr> Set a breakpoint at the given Z80 address. Up to 8 breakpoints can be active simultaneously. When the PC matches a breakpoint address during opcode fetch, the CPU is automatically held and the hit is reported. Duplicate addresses are rejected.
bc <n|*> Clear breakpoint slot n (0–7) or all breakpoints (*).
bl List all active breakpoints showing slot number and address.
wm [p|v] <addr> <byte> [byte]... Write one or more bytes to memory. p = physical Z80 bus, v = virtual PSRAM, omit for auto (follows memory map). Multiple bytes can be specified separated by spaces. Auto-holds CPU for physical/mapped writes.
fill [p|v] <addr> <len> [w|d] <val> Fill a memory region with a constant value. p = physical, v = virtual, omit for auto. Default 8-bit; w = 16-bit, d = 32-bit (little-endian). Auto-holds CPU when needed.
copy <pv|fp|vp> <src> <len> <dst> Copy memory between physical and virtual. pv = physical read to virtual, fp = physical fetch to virtual, vp = virtual to physical write. Auto-holds CPU.
memtest <addr> <len> [pattern] Test physical memory with three passes: write+read, write+fetch, interleaved. Default pattern: ascending bytes. Reports errors per pass.
in <port> Read a Z80 I/O port. Drives a real IORQ+RD bus cycle and displays the byte read.
out <port> <byte> Write a byte to a Z80 I/O port. The CPU must be held first. Drives a real IORQ+WR bus cycle.
trace <on|off|dump [n]|clear|rt|byte ...> Control the execution trace. on enables recording of every executed instruction into a 512-entry ring buffer (PC, opcode, flags). off disables recording. dump displays the last n entries (default: all) with disassembly and decoded flags. clear resets the buffer. rt enables real-time trace output to the debug console as instructions execute. byte enables byte-level tracing of memory/IO transactions.
verify <on|off> Toggle full opcode fetch verification. When on, every fetch is verified against readPhysicalMem (50% speed reduction). When off (default), only checks 0x00/0xFF opcodes.
fwait <0-4> Force extra wait states on M1 (opcode fetch) cycles. <n> is 0–4 additional T-states (0 = off, default). Useful for debugging code that behaves differently with wait states — some peripherals or memory devices require specific timing margins. Without a parameter, displays the current setting.
iowait <0-8> Force extra wait states on I/O read and write cycles. <n> is 0–8 additional T-states (0 = off, default). Stretches I/O cycles for diagnosing peripherals with slow response times. Without a parameter, displays the current setting.
corrupt [clear] Display detected fetch corruptions (PC, fetched opcode, verified opcode). clear resets the log.
fdctrace <on|off|dump> Enable, disable, or dump FDC I/O trace. on/off controls recording of WD1773 FDC register accesses into a 64-entry ring buffer. dump displays the last 64 operations, showing the register name (Status/Command, Track, Sector, Data, DriveSel, SideSel, DDEN), read or write direction, byte value, and FDC status.
qdtrace <on|off|dump> Enable, disable, or dump Quick Disk I/O trace. on/off controls recording of QD SIO register accesses into a 64-entry ring buffer. dump displays the last 64 operations, showing port, direction, byte value, and tape position (byte offset).
piodbg [clear] Display RP2350 PIO hardware diagnostics for all three PIO blocks (PIO 0, PIO 1, PIO 2). Shows FDEBUG sticky error flags (stall, RX underflow, TX overflow), FSTAT status, FIFO fill levels, per-state-machine program counters, GPIO output-enable mask, and GPIO pin levels. clear resets the FDEBUG sticky flags. Useful for diagnosing PIO state machine hangs or bus contention.
load <p|v> <file> <addr> [len] [ofs] Load a file from the ESP32 SD card into Z80 memory. p = write to physical bus, v = write to virtual PSRAM bank 0. file is relative to /sdcard/ on the ESP32. addr is the Z80 start address. If len is omitted the entire file is loaded (up to 64KB); if specified, loads that many bytes (max 1MB). Optional ofs is the file offset to start reading from. Auto-holds CPU for physical writes. Uses PSRAM bank 63 as scratch buffer.
save <p|pf|v> <file> <addr> <len> Save Z80 memory to a file on the ESP32 SD card. p = read via physical bus, pf = read via physical fetch (M1 cycles), v = read from virtual PSRAM bank 0. file is relative to /sdcard/. addr is the Z80 start address, len is bytes to save (max 64KB). Auto-holds CPU for physical reads. Performs periodic DRAM refresh during physical reads.
dir [path] List files on the ESP32 SD card. Optional path is relative to /sdcard/. Shows filenames and sizes.
echo [on|off] Toggle or set character echo. When on (default), typed characters are echoed back to the terminal.
reset Force an immediate Z80 CPU reset. The emulation restarts from the reset vector (typically 0x0000).
set <reg|flags|memmap|memptr|iomap> <idx> <val> Modify a Z80 register, flags, memory map, PSRAM memPtr, or I/O port map entry at runtime. reg sets a Z80 register, flags sets the flags register, memmap/memptr/iomap modify the memory or I/O configuration. idx is the register name or table index (decimal or hex), val is the new value. This allows hot-patching registers and memory/IO configuration without reloading config.json.
hist [n] Display command history buffer. Shows the last n commands (default: all entries, up to 16). History is preserved across power cycles via ESP32 NVS storage.
savehst Force-save the current command history to ESP32 NVS storage immediately. History is normally saved automatically on graceful shutdown; this command forces an immediate save.
Typical debugging workflow:
  1. Connect a terminal to the second USB serial port (115200, 8N1).
  2. hold — pause the CPU.
  3. regs — inspect current register state.
  4. dis v — disassemble code at the current PC.
  5. bp E800 — set a breakpoint.
  6. go — resume. The CPU will stop when it reaches 0xE800.
  7. step 5 — single-step 5 instructions from the breakpoint.
  8. dm v D000 80 — inspect VRAM contents.
  9. trace on / go / trace dump 50 — trace and review execution history.

Troubleshooting

Host computer does not boot

  • Check orientation — ensure Pin 1 of the picoZ80 aligns with Pin 1 of the socket. Inserting the board backwards will damage both the picoZ80 and the host computer.
  • Check seating — remove the picoZ80 and reinsert, ensuring all 40 pins are fully seated and none are bent under the board.
  • Check the SD card — if config.json is missing or malformed the firmware will attempt to use the previously cached Flash configuration. If no valid config exists the RP2350 will not initialise the memory map and the host will see an open bus.
  • Confirm firmware is flashed — try connecting the picoZ80 via USB (without inserting in the host) and verify the board enumerates on the PC.
  • Check host power supply — the picoZ80 can draw up to 400mA from the 5V rail. Some vintage computers have marginal power supplies; check the 5V rail voltage under load with a multimeter.

Cannot connect to the web interface

  • Check WiFi mode — on first boot or after a factory reset the ESP32 starts in AP mode. Connect to the picoZ80 WiFi network first, then navigate to http://192.168.4.1.
  • Check configured IP address — if client mode is configured with a fixed IP, verify the IP matches your network subnet.
  • Check the SD card is present — the web assets in webfs/ on the SD card are required. Without the SD card the web server cannot serve any pages.
  • Check the webfs directory — confirm the webfs/ directory exists on the SD card and contains the HTML/CSS/JS files from the project repository.
  • Factory reset WiFi — if credentials are lost, re-flash the ESP32 firmware to clear NVS settings and start fresh.

SD card not recognised

  • Ensure the SD card is formatted as FAT32. NTFS, exFAT, and FAT16 are not supported.
  • Try a different SD card — some high-capacity or high-speed cards can have compatibility issues with the ESP32 SPI SD interface.
  • Cards up to 32GB are well supported. Very large cards (>32GB) may require special formatting.
  • Re-seat the SD card — remove and reinsert to ensure good contact.

ROM images not loading

  • Verify the file path in config.json exactly matches the file location on the SD card (paths are case-sensitive).
  • Confirm the ROM image file is present on the SD card — use the File Manager to browse to the expected location.
  • Check the fileofs value — an incorrect offset will load garbage data into the ROM bank.
  • Verify the size field in the memory map entry is not larger than the ROM image file. Oversized mappings will pad with undefined data.

Board resets or reboots unexpectedly

  • The picoZ80 has a hardware watchdog timer that automatically resets the RP2350 if the firmware hangs during boot or normal operation. If the board reboots repeatedly, the watchdog is triggering because a boot stage is not completing in time.
  • Check the SD card — a missing or corrupt config.json can cause the boot sequence to stall during configuration parsing.
  • Check WiFi settings — if the ESP32 cannot establish a connection, the SPI handshake between the RP2350 and ESP32 may time out, triggering the watchdog.
  • Use SWD debugging — connect a debug probe and inspect the watchdog scratch registers (watchdog_hw->scratch[5] through scratch[7]). The boot progress code in scratch[6] indicates which stage the firmware reached before the watchdog fired, and scratch[0–3] hold a history of the last four reset attempts.
  • Check the persistent log — the firmware writes boot-critical messages to the last 4KB of PSRAM using plogf(). These messages survive the watchdog reset and are dumped to the debug console on the next successful boot, revealing what happened before the reset.

OTA update fails

  • Ensure you are uploading a .bin file (not a .uf2) for RP2350 OTA updates.
  • Ensure you are uploading to the inactive slot to preserve the working firmware.
  • If the OTA update fails or results in a non-booting partition, the bootloader will keep the previous active slot running — repeat the upload process.
  • For ESP32 OTA failures, re-flash via esptool using the debug header USB connection.

Reference Sites

Resource Link
picoZ80 project page /picoz80/
picoZ80 Technical Guide /picoz80-technicalguide/
pico6502 project page /pico6502/
RP2350 Datasheet datasheets.raspberrypi.com
Pico SDK Documentation raspberrypi.github.io/pico-sdk-doxygen
ESP32-S3 Technical Reference docs.espressif.com
X (Twitter) project preview engineerswork1

FCC / RED Regulatory Notice

The picoZ80 board has not been submitted for FCC (USA) or RED (EU) intentional radiator certification. As shipped, the board must have the WiFi antenna matching components unpopulated and the ESP32 firmware built with the NCM Only configuration. In this state no radio frequency energy is emitted and the board does not fall under intentional radiator regulations.
End users who wish to use WiFi may populate the antenna matching network, build the WiFi firmware variant, and operate under the hobbyist/experimental exemption applicable in their jurisdiction. Any party wishing to sell the board commercially with WiFi enabled must first obtain FCC and/or RED certification for the complete assembly.