pico6502 Technical Guide

Note: The pico6502 project is in early development. The hardware, PIO bus interface, memory model, and build system are fully implemented and functional. Machine persona drivers are at an early stage. This guide describes the technical architecture as it exists today.

Overview

The pico6502 technical architecture is identical to the picoZ80 in all respects except the CPU bus interface. The same RP2350B dual-core processor, PSRAM memory model, Flash layout, ESP32 co-processor, and driver framework are shared between the two products. This guide focuses on the differences specific to the 6502 and refers to the picoZ80 Technical Guide for topics that are fully shared.

Hardware Architecture

Block Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                            pico6502 Board (v2.2)                        │
│                                                                         │
│  ┌───────────────┐   PIO 0: A0–A15, D0–D7      ┌───────────────────┐   │
│  │               │◄──────────────────────────►│  DIP-40 Interface │   │
│  │   RP2350B     │   PIO 1: cycle/ctrl/irq     │   (6502 socket)   │   │
│  │  (300 MHz)    │◄──────────────────────────►│  A0–A15, D0–D7   │   │
│  │               │   PIO 2: PHI1/PHI2 clock ──►│  PHI0/RNW/SYNC   │   │
│  │  Core 0       │                             │  IRQ/NMI/RDY/SO  │   │
│  │  (USB/IO/ESP) │                             └───────────────────┘   │
│  │               │◄──QSPI──►[ 8MB PSRAM ]                             │
│  │  Core 1       │◄──SPI───►[ 16MB Flash ]                             │
│  │  (6502 loop)  │                                                     │
│  │               │◄──FSPI──►┌───────────┐                              │
│  │               │◄──UART──►│   ESP32   │◄──SPI──►[ SD Card ]         │
│  └───────────────┘          │  (WiFi)   │──────────[ Web Server ]     │
│                             └───────────┘                              │
│  [ USB Hub ]──USB──►[ RP2350 USB Bridge ]                             │
└─────────────────────────────────────────────────────────────────────────┘

Key Components

Component Part Specification
Main processor RP2350B Dual Cortex-M33, up to 300 MHz, 512KB SRAM, 48 GPIO
PSRAM SPI PSRAM 8MB, QSPI interface, up to 133 MHz
Flash SPI NOR Flash 16MB, XIP (execute-in-place)
Co-processor ESP32-S3 WiFi, SD card, web server, 460.8kbaud UART to RP2350
SD card FAT32 ROM images, disk images, config.json, web files
Bus interface Resistor network Series resistors for 5V ↔ 3.3V level translation
Power supply TLV62590BV Synchronous buck, 5V (VCC pin) → 3.3V, all board power
USB On-board hub RP2350 USB mass-storage bridge for firmware flashing

GPIO Assignment

The GPIO assignments below are indicative of the typical layout for the pico6502 v2.2 board. The KiCad schematic (kicad/PICO6502/PICO6502_Schematic.pdf) is the authoritative source.
GPIO Signal Direction Notes
0–15 A0–A15 Output 6502 address bus — driven by PIO 0 m6502_addr
16–23 D0–D7 Bidir 6502 data bus — driven/sampled by PIO 0 m6502_data
24 PHI0 Input External clock input to PIO 2
25 PHI1 Output Phase 1 clock output — generated by PIO 2
26 PHI2 Output Phase 2 clock output — generated by PIO 2
27 RNW Input Read/Not-Write — sampled by PIO 1
28 SYNC Output Opcode fetch indicator — driven by PIO 1
29 IRQ Input Maskable interrupt (active low) — monitored by PIO 1
30 NMI Input Non-maskable interrupt (active low) — monitored by PIO 1
31 RDY Input Ready signal — sampled by PIO 1
32 SO Input Set Overflow — monitored by PIO 1
33 RESET Bidir System reset (active low)
34–39 Flash SPI NOR Flash (XIP)
40–45 PSRAM QSPI PSRAM
46–47 ESP32 FSPI SCLK, CS to ESP32
48–49 ESP32 UART TX/RX 460.8kbaud to ESP32

Firmware Architecture

Flash Memory Layout

Identical to the picoZ80 layout:
Partition Address Range Size Contents
Bootloader 0x10000000–0x1001FFFF 128KB USB bridge, firmware update, partition selector
App Slot 1 0x10020000–0x1051FFFF 5MB Main 6502 firmware (partition 1)
App Slot 2 0x10520000–0x10A1FFFF 5MB Main 6502 firmware (partition 2)
App Config 1 0x10A20000–0x10C9FFFF 2.5MB ROM images + minified config JSON (slot 1)
App Config 2 0x10CA0000–0x10F1FFFF 2.5MB ROM images + minified config JSON (slot 2)
General Config 0x10F20000–0x10FFEFFF 892KB Core settings, scratch space
Partition Table 0x10FFF000–0x11000000 4KB Active slot, checksums, metadata

Dual-Core Design

Core Responsibilities
Core 0 USB mass-storage bridge; firmware partition management; file I/O relay to ESP32; ESP32 UART command dispatch; inter-core queue service
Core 1 6502 bus emulation hot loop — services PIO FIFOs for every bus cycle, resolves addresses against the memory map, dispatches to PSRAM / PHYSICAL / FUNC handlers, calls driver poll callbacks

PIO Bus Interface

The 6502 bus interface is implemented in M6502.pio across all three RP2350 PIO blocks. The key difference from the Z80 interface is the 6502's two-phase non-overlapping clock scheme: PHI0 is an external clock input; PIO 2 generates PHI1 and PHI2 from it. This ensures correct 6502 bus timing independent of Core 1 scheduling.

PIO Programs

PIO Block Program State Machines Function
PIO 0 m6502_addr SM 0 Outputs 16-bit address A0–A15; signals IRQ 0 (cycle start)
PIO 0 m6502_data SM 1 Drives or samples D0–D7; signals IRQ 1 (data phase); tri-state control via RNW
PIO 1 m6502_cycle SM 0 Top-level bus cycle sequencer; IRQ 7 = execution loop exit
PIO 1 m6502_fetch SM 1 Opcode-fetch cycle (SYNC asserted, PHI2 high, RNW=1)
PIO 1 m6502_read SM 1 Memory read cycle
PIO 1 m6502_write SM 2 Memory write cycle
PIO 1 m6502_irq SM 2 Monitors IRQ pin; signals PIO IRQ 5 on assertion
PIO 1 m6502_nmi SM 3 Monitors NMI pin; signals PIO IRQ 4 on assertion
PIO 1 m6502_so SM 3 Monitors SO (Set Overflow) pin; signals PIO IRQ 6
PIO 2 m6502_clock_6502 SM 0 Generates PHI1 / PHI2 two-phase clocks from external PHI0 input

IRQ Signal Conventions

PIO IRQ Flag Signal Triggered By Consumed By
IRQ 0 Cycle start m6502_addr — address valid on PHI1 Core 1 dispatch loop
IRQ 1 Data phase m6502_data — data bus active Core 1 dispatch loop
IRQ 4 NMI m6502_nmi — NMI pin low Core 1 NMI handler
IRQ 5 IRQ m6502_irq — IRQ pin low Core 1 IRQ handler
IRQ 6 SO m6502_so — SO pin high Core 1 SO handler
IRQ 7 Loop exit Software request m6502_cycle — exits execution loop

PHI1 / PHI2 Clock Generation

The 6502 requires two non-overlapping clock phases. PIO 2 runs the m6502_clock_6502 program which accepts an external PHI0 input on a dedicated GPIO and generates PHI1 and PHI2 with the correct non-overlap timing. Dedicating an entire PIO block to clock generation means the 6502 bus timing is never affected by Core 1 activity or FIFO stalls.

Wait States and RDY

The 6502 RDY signal can be used to insert wait states — holding RDY low during a read cycle pauses the processor until RDY goes high. The pico6502 can assert RDY programmatically from Core 1 to insert wait states when accessing slower virtual devices (e.g. floppy disk emulation). The tcycwait parameter in the memory map JSON entry specifies the number of wait states to insert for a given memory region.

PIO Architecture — How 6502 Bus Cycles Are Recreated

The RP2350's Programmable I/O (PIO) subsystem recreates cycle-accurate 6502 bus timing using 10 state machines across all three PIO blocks. The architecture differs from the picoZ80 PIO in two fundamental ways: the 6502 uses a two-phase non-overlapping clock scheme (PHI1/PHI2) rather than a single clock, and it uses a single R/W̄ (Read/Not-Write) signal instead of separate /RD and /WR.

Two-Phase Clock Generation
The 6502 requires two non-overlapping clocks — PHI1 and PHI2. An external PHI0 signal provides the reference; PIO 2 generates PHI1 and PHI2 from it. The m6502_clock_6502 state machine (PIO 2 SM 0) implements this:
PHI0 (input):  ──┐        ┌──┐        ┌──
                 │        │  │        │
                 └────────┘  └────────┘

PHI1 (output):    ┌──────┐              ┌──────┐
                  │      │              │      │
               ───┘      └──────────────┘      └───

PHI2 (output): ───┐              ┌──────┐              ┌──
                  │              │      │              │
                  └──────────────┘      └──────────────┘
                  ↑              ↑      ↑
                  │              │      │
            PHI0 falls     PHI0 rises  PHI0 falls
            → brief gap    → brief gap → brief gap
            → PHI1 rises   → PHI1 falls
                           → PHI2 rises
The SM uses jmp pin to detect PHI0 edges and set pins to drive both PHI1 and PHI2 with the correct non-overlap gaps. The [1] delay annotation on the first set pins instruction creates the non-overlap period — both clocks are low for a brief interval during transitions. Dedicating an entire PIO block to clock generation ensures the 6502 bus timing is never affected by FIFO stalls or Core 1 latency.

The out exec, 32 Mechanism
Like the picoZ80, the pico6502 uses dynamic instruction injection via out exec — but with a key difference: the 6502 cycle SM uses out exec, 32 (32-bit instructions) rather than the Z80's out exec, 16. This provides the full 32-bit PIO instruction encoding including side-set bits, delay values, and extended operands.
The m6502_cycle SM (PIO 1 SM 0) orchestrates all bus cycles:
// m6502_cycle SM program (PIO 1 SM 0):
//
// start_cycle:
//     wait 0 gpio CLK2      ; Sync to PHI2 falling edge (start of new cycle)
//     irq set 0             ; Signal "ready for new cycle"
//     wait 0 irq 0          ; Wait for C code to load address and clear IRQ 0
// cycle_exec:
//     out exec, 32           ; Pull 32-bit instruction from FIFO, execute it
//     jmp cycle_exec         ; Repeat
// cycle_end:
//     irq set 7              ; Flag end of execution loop
// cycle_exec2:
//     out exec, 32           ; Continue executing injected instructions
//     jmp cycle_exec2        ; Loop until JMP start_cycle
The C code pre-computes 32-bit instruction sequences for each cycle type (fetch, read, write) and pushes them into the FIFO. The cycle SM pulls and executes each instruction in turn, controlling the SYNC and R/W̄ signals while coordinating with the address and data SMs via IRQ flags.

6502 Bus Cycle Types
The 6502 has three bus cycle types, all controlled by the state of R/W̄ and SYNC:
Opcode Fetch (m6502_fetch):
PHI1:      ┌──────┐              ┌──
           │      │              │
        ───┘      └──────────────┘
PHI2:   ───┐              ┌──────┐
           │              │      │
           └──────────────┘      └───
A0–A15: ══╤═══ PC address ══════════╗   (valid on PHI1 rising)
R/W̄:    ──┤── high (read) ─────────╢
SYNC:   ──┤── high (fetch) ────────╢   (SYNC high = opcode fetch)
D0–D7:  ══════════════════╤════════╗   (sampled at PHI2 falling)
                       opcode


Memory Read (m6502_read):
           Same timing as fetch, but SYNC = low.


Memory Write (m6502_write):
PHI1:      ┌──────┐              ┌──
           │      │              │
        ───┘      └──────────────┘
PHI2:   ───┐              ┌──────┐
           │              │      │
           └──────────────┘      └───
A0–A15: ══╤═══ address ═════════════╗   (valid on PHI1 rising)
R/W̄:    ──┤── low (write) ─────────╢   (R/W̄ low = write)
SYNC:   ──┤── low ─────────────────╢
D0–D7:  ══════════════╤═══ data ═══╗   (driven during PHI2 high)
Key differences from the Z80 PIO implementation:
  • Single R/W̄ signal — replaces the Z80's separate /RD and /WR signals. The m6502_fetch and m6502_read SMs set R/W̄ high; m6502_write sets it low.
  • SYNC signal — the 6502 asserts SYNC during opcode fetches to distinguish them from ordinary reads. The m6502_fetch SM sets SYNC high; m6502_read and m6502_write leave it low.
  • PHI2-based data sampling — the data bus is sampled at the PHI2 falling edge (end of the cycle), not at a specific T-state clock edge like the Z80. The m6502_data SM waits on wait 0 gpio CLK2 to time the data capture.
  • RDY-based wait states — instead of the Z80's /WAIT signal, the 6502 uses RDY. When RDY is low during a read cycle, the processor pauses. The fetch and read SMs check RDY via jmp pin after each PHI2 rising edge.
  • No refresh cycle — the 6502 does not have a DRAM refresh cycle, so fetch cycles are simpler (no T3–T4 refresh phase).
  • No I/O-specific cycles — the 6502 has no IN/OUT instructions. All peripheral access is via memory-mapped reads and writes.

Signal Monitoring State Machines
Three dedicated SMs monitor the 6502's asynchronous input signals:
  • m6502_irq (PIO 1 SM 2) — monitors the /IRQ pin. When /IRQ goes low, it sets PIO IRQ 5 and holds it until the pin returns high, then clears the flag. Core 1 checks IRQ 5 to decide whether to inject an interrupt vector fetch sequence.
  • m6502_nmi (PIO 1 SM 3) — monitors /NMI and sets/clears PIO IRQ 4. The NMI handler in Core 1 pushes the appropriate bus cycle sequence to vector through $FFFA/$FFFB.
  • m6502_so (PIO 1 SM 3) — monitors the SO (Set Overflow) pin and sets/clears PIO IRQ 6. This is used by some 6502 systems (notably the Commodore disk drive) to signal data-ready events.
All three SMs use the same pattern: jmp pin to detect the pin going active, irq set to signal Core 1, then jmp pin in a loop to detect the pin returning inactive, followed by irq clear. This converts asynchronous edge events into synchronous IRQ flags that Core 1 can poll efficiently in the hot loop.

Memory Model

The pico6502 memory model is structurally identical to the picoZ80 model with one critical difference: the 6502 has no separate I/O address space. There is no ioPtr[] array in t_6502PSRAM and no iomap JSON section. All peripheral registers are mapped into the 64KB memory address space using FUNC-type blocks.

Tier 1 — RP2350 SRAM (Fast Dispatch Table)

128 × 32-bit entries in _membankPtr[], one per 512-byte block of the 64KB address space. Each entry encodes the block type, PSRAM bank number, and block base address in a single 32-bit word for O(1) dispatch on every bus cycle:
// 32-bit membankPtr encoding
// Bits 31–24: MEMBANK_TYPE_xxx constant
// Bits 23–16: PSRAM bank number (0–63)
// Bits 15–0:  Block base address >> 9 (i.e. upper 7 bits of 16-bit address)
#define MEMBANK_ENCODE(type, bank, base) (((type) << 24) | ((bank) << 16) | ((base) >> 9))

Tier 2 — PSRAM (8MB)

The 8MB PSRAM is divided between the RAM/ROM area and the function-pointer tables:
typedef struct {
    uint8_t      RAM[MAX_MEMORY_BANKS * MEMORY_PAGE_SIZE]; // 64 banks × 64KB = 4MB RAM/ROM area
    MemoryFunc   memPtr[MEMORY_PAGE_SIZE];                  // 64K per-byte read redirect (PTR type)
    MemoryFunc   memioPtr[MEMORY_PAGE_SIZE];                // 64K memory-mapped handler array (FUNC type)
    // Note: no ioPtr[] — 6502 has no separate I/O space
} t_6502PSRAM;

Tier 3 — Flash (16MB)

The 16MB Flash holds the bootloader, two 5MB application firmware slots, two configuration slots for ROM images and minified JSON, general configuration, and the partition table. See the Flash Memory Layout table in the Firmware Architecture section above.

Memory Block Types

Constant Value Behaviour
MEMBANK_TYPE_PHYSICAL 0 Pass-through to real host hardware — RP2350 releases bus
MEMBANK_TYPE_PHYSICAL_VRAM 1 Host video RAM with configurable wait states
MEMBANK_TYPE_RAM 2 Read/write — backed by PSRAM bank
MEMBANK_TYPE_ROM 3 Read-only — backed by PSRAM bank; writes are silently discarded
MEMBANK_TYPE_VRAM 4 PSRAM video RAM mirror with wait states
MEMBANK_TYPE_FUNC 5 Virtual device — memioPtr[addr] handler called on every access
MEMBANK_TYPE_PTR 6 Per-byte redirect — memPtr[addr] handler used for reads

Configuration Reference

The pico6502 uses the same JSON configuration mechanism as the picoZ80. The top-level keys are "esp32" and "rp2350". The CPU-specific section uses the key "6502" (rather than "z80"). Because the 6502 has no I/O space there is no "io" array — only a "memory" array.

esp32.core

Key Type Description
device string CPU device type. Must be "6502" for the pico6502.
mode integer Default boot mode: 0 = client (station), 1 = Access Point.

esp32.wifi

Key Type Description
override 0/1 1 = apply all wifi settings from this block; 0 = use NVS settings.
wifimode string "ap" or "client".
ssid string Network name to create (AP) or join (client).
password string WiFi passphrase.
ip string Fixed IP address.
netmask string Subnet mask.
gateway string Default gateway.
dhcp 0/1 Client mode only. 1 = DHCP, 0 = fixed IP.
webfs string Web filesystem root directory on SD card (default "webfs").
persist 0/1 1 = write resolved settings back to NVS each boot.

rp2350.core

Key Type Description
cpufreq integer RP2350 system clock in Hz (e.g. 300000000).
psramfreq integer PSRAM SPI clock in Hz (e.g. 133000000).
voltage float RP2350 core voltage (e.g. 1.10).

rp2350.6502.memory[ ]

Defines the 6502 memory map. All peripherals must appear here as FUNC-type entries — there is no separate I/O map.
Key Type Description
enable 0/1 Whether this entry is active.
addr hex string Start address in the 6502 address space (e.g. "0xE000").
size hex string Region size in bytes (e.g. "0x2000").
type string PHYSICAL, PHYSICAL_VRAM, RAM, ROM, FUNC, or PTR.
bank integer PSRAM bank number for RAM/ROM types (0–63).
tcycwait integer Wait states to insert (RDY stretching) for this region.
task string Named task / driver handler for FUNC-type blocks.
file string SD-card path to a ROM image to load at boot (ROM type).

rp2350.6502.drivers[ ]

Driver entries for the 6502 are simpler than those for the Z80. Each entry activates a named driver (matched to the firmware's virtualFuncMap[] table) and optionally loads ROM images into PSRAM at boot.
Key Type Description
enable 0/1 Whether this driver entry is active.
name string Driver name — matched case-insensitively to virtualFuncMap[].
rom[] array ROM images to load at boot. Each entry: enable, file, loadaddr[].

rom[] entry:

Key Type Description
enable 0/1 Whether to load this ROM image.
file string SD-card path to ROM binary.
loadaddr[] array One or more load-address descriptors: enable, position, addr, bank, size.

Virtual Device Framework

The virtual device framework is structurally identical to the picoZ80 framework described in the picoZ80 Technical Guide. The key difference is that all virtual devices are registered in memioPtr[] — there is no ioPtr[] equivalent for the 6502.

Handler Signatures

// Memory / peripheral handler — installed in memioPtr[addr]
// Called for every access to a MEMBANK_TYPE_FUNC block
typedef uint8_t (*MemoryFunc)(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data);

// Driver init function — registered in virtualFuncMap[]
// Called twice: pass=0 (validation), pass=1 (configuration)
typedef int (*VirtualFunc)(M6502CPU *cpu, t_drvConfig *drvConfig, int pass);

Writing a Peripheral Driver

To add a virtual peripheral for the pico6502:
  1. Create a handler function with the MemoryFunc signature. The handler receives read=true for 6502 read cycles (RNW=1) and read=false for write cycles (RNW=0).
  2. Create an init function with the VirtualFunc signature. In the configuration pass (pass=1), install your handler in cpu->_6502PSRAM->memioPtr[addr] for each address your peripheral occupies.
  3. Register the driver name and init function in the virtualFuncMap[] table in M6502CPU.c.
  4. Add a FUNC-type entry in the memory array of config.json for the address range.
  5. Add a driver entry in config.json with the matching "name" field.
See the pico6502 Developer's Guide for a complete worked example including a VIA6522 peripheral implementation.

ESP32 Co-processor

The ESP32 co-processor is identical in function and implementation to the picoZ80 ESP32 — refer to the picoZ80 Technical Guide — ESP32 Co-processor for the full description of the SD card interface, web server structure, and RP2350–ESP32 command protocol.

SD Card

The SD card is managed exclusively by the ESP32 over SPI. The RP2350 requests file reads and writes by posting messages to the inter-core queue; Core 0 relays these requests to the ESP32 over UART and returns the results. The SD card directory layout for the pico6502 is identical to the picoZ80: webfs/ for web files, ROM/ for ROM images, and config.json in the root.

Web Server

The same seven-page Bootstrap 4 web server runs on the ESP32. The web interface automatically detects the connected device type via the esp32.core.device field in config.json and adjusts its CSS theme and labels accordingly (the p6502.css stylesheet applies the 6502-specific colour scheme).

Command Protocol

The RP2350–ESP32 command protocol is identical for both the picoZ80 and pico6502. Commands are exchanged over a 460.8kbaud UART link (backed by 50MHz FSPI for bulk data transfer). The protocol is defined in ESP.c / ESP.h and is shared between both firmware variants.

SWD Debugging — RP2350

The SWD debugging setup for the pico6502 is identical to the picoZ80 — refer to the picoZ80 Technical Guide — SWD Debugging for the full description of hardware connections, the custom rp2350_tzpu.cfg OpenOCD target, and global GDB initialisation. The differences from the picoZ80 are:
  • The main firmware ELF is build/bin/model/BaseM6502/BaseM6502_0x10020000.elf (not BaseZ80).
  • The add-auto-load-safe-path entry in ~/.gdbinit must reference BaseM6502.

OpenOCD Setup

sudo cp rp2350_tzpu.cfg /usr/local/share/openocd/scripts/target/
openocd -f interface/cmsis-dap.cfg -f target/rp2350_tzpu.cfg -c "adapter speed 5000"

GDB Configuration

set history save on
set history filename ~/.gdb_history
set history size 65536
add-auto-load-safe-path build/bin/model/BaseM6502/.gdbinit:build/bin/model/Bootloader/.gdbinit
# Bootloader — Core 0
cd build/bin/model/Bootloader
cp ../../../../.gdbinit.bootloader.3333 .gdbinit
gdb-multiarch Bootloader.elf

# Bootloader — Core 1 (separate terminal)
cd build/bin/model/Bootloader
cp ../../../../.gdbinit.bootloader.3334 .gdbinit
gdb-multiarch Bootloader.elf
# Main firmware — Core 0
cd build/bin/model/BaseM6502
cp ../../../../.gdbinit.3333 .gdbinit
gdb-multiarch BaseM6502_0x10020000.elf

# Main firmware — Core 1 (separate terminal)
cd build/bin/model/BaseM6502
cp ../../../../.gdbinit.3334 .gdbinit
gdb-multiarch BaseM6502_0x10020000.elf

ESP32 — USB Debugging

Identical to the picoZ80 — connect USB to the ESP32 USB port and use the ESP32-S3 built-in USB-JTAG interface (no external probe required).
openocd -f board/esp32s3-builtin.cfg

xtensa-esp32s3-elf-gdb esp32/build/main.elf
(gdb) target extended-remote :3333

Build System

The build system is identical to the picoZ80 — CMake with Pico SDK 2.x targeting the RP2350. The pico6502 does not require the Zeta Z80 emulator library. Refer to the picoZ80 Technical Guide — Build System for the full description of prerequisites, Docker setup for ESP-IDF, and the build script. The pico6502-specific differences are noted below.

Build Targets

Target Output Description
BaseM6502 BaseM6502_0x10020000.uf2 Main 6502 firmware — Slot 1 load address
BaseM6502 BaseM6502_0x10520000.uf2 Main 6502 firmware — Slot 2 load address
Bootloader Bootloader.uf2 Shared bootloader (same as picoZ80)
ESP32 main.bin ESP32 firmware (shared with picoZ80)

Build Commands

# Set up (once) — from project root
export PICO_PATH=/path/to/pico-sdk
./get_and_build_sdk.sh

# Standard release build
./build_tzpuPico.sh

# Debug build
./build_tzpuPico.sh DEBUG

# Full build including ESP32 firmware
./build_tzpuPico.sh ALL

# ESP32 only (using Docker idf54 alias)
cd projects/tzpuPico/esp32
idf54 build

# Flash RP2350 via USB mass-storage (BOOTSEL mode)
cp build/bin/model/Bootloader/Bootloader.uf2 /media/$USER/RPI-RP2/
cp build/bin/model/BaseM6502/BaseM6502_0x10020000.uf2 /media/$USER/RPI-RP2/

# Flash ESP32 (initial, via esptool)
esptool.py --chip esp32s3 --port /dev/ttyUSB0 --baud 460800 \
  write_flash 0x0   esp32/build/bootloader/bootloader.bin \
             0x8000 esp32/build/partition_table/partition-table.bin \
             0x10000 esp32/build/main.bin

Reference Sites

Resource Link
pico6502 project page /pico6502/
pico6502 User Manual /pico6502-usermanual/
pico6502 Developer’s Guide /pico6502-developersguide/
picoZ80 Technical Guide /picoz80-technicalguide/
picoZ80 project page /picoz80/
RP2350 Datasheet datasheets.raspberrypi.com
Pico SDK Multicore API raspberrypi.github.io/pico-sdk-doxygen
MOS 6502 Datasheet archive.org
esptool documentation docs.espressif.com
cJSON Library github.com/DaveGamble/cJSON

Wireless Regulatory Notice

This device incorporates an ESP32-S3-PICO-1 wireless module that transmits in the 2.4 GHz ISM band, making it an intentional radiator under radio-frequency regulations worldwide (including FCC Part 15 Subpart C in the United States, and the Radio Equipment Directive 2014/53/EU in the European Union).
Although the ESP32-S3-PICO-1 module itself carries pre-existing regulatory certifications (FCC, CE, and others), those module-level certifications do not automatically extend to a finished product that incorporates the module. The pre-certified module exemption permits individual hobbyists to build a limited number of devices for personal, experimental, or educational use without obtaining separate equipment authorisation.
Important Limitations
  • Assembled devices must not be sold, offered for sale, gifted, or otherwise distributed to third parties unless the finished product has been independently tested and granted its own equipment authorisation (e.g. FCC ID, CE marking with a Notified Body assessment) in the relevant jurisdiction.
  • Building this project for personal use in limited quantities is generally permitted under hobbyist and experimental-use provisions (e.g. FCC § 15.23), provided the device does not cause harmful interference.
  • Regulatory requirements vary by country. Builders outside the United States should consult their national radio-frequency authority for applicable rules.
Builder’s Responsibility
It is the builder’s sole responsibility to ensure that any device constructed from these designs complies with all applicable radio-frequency regulations in their jurisdiction. The author provides these designs for personal, educational, and hobbyist use and makes no representation that a device built from them satisfies the regulatory requirements for commercial distribution.