pico6502 Technischer Leitfaden
Hinweis: Das pico6502-Projekt befindet sich in einer fruehen Entwicklungsphase. Hardware, PIO-Bus-Interface, Speichermodell und Build-System sind vollstaendig implementiert und funktionsfaehig. Maschinen-Persona-Treiber sind in einem fruehen Stadium. Dieser Leitfaden beschreibt die technische Architektur wie sie heute besteht.
Uebersicht
Die technische Architektur des pico6502 ist in allen Punkten identisch mit dem picoZ80, ausser dem CPU-Bus-Interface. Der gleiche RP2350B Dual-Core-Prozessor, das gleiche PSRAM-Speichermodell, das gleiche Flash-Layout, der gleiche ESP32-Koprozessor und das gleiche Treiberframework werden von beiden Produkten geteilt. Dieser Leitfaden konzentriert sich auf die 6502-spezifischen Unterschiede und verweist fuer vollstaendig gemeinsame Themen auf den picoZ80 Technischen Leitfaden.
Hardwarearchitektur
Blockdiagramm
┌─────────────────────────────────────────────────────────────────────────┐ │ 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 ] │ └─────────────────────────────────────────────────────────────────────────┘
Hauptkomponenten
| Komponente | Bauteil | Spezifikation |
|---|---|---|
| Hauptprozessor | RP2350B | Dual Cortex-M33, bis 300 MHz, 512KB SRAM, 48 GPIO |
| PSRAM | SPI PSRAM | 8MB, QSPI-Interface, bis 133 MHz |
| Flash | SPI NOR Flash | 16MB, XIP (Execute-in-Place) |
| Koprozessor | ESP32-S3 | WiFi, SD-Karte, Webserver, 460,8kBaud UART zum RP2350 |
| SD-Karte | FAT32 | ROM-Images, Disk-Images, config.json, Web-Dateien |
| Bus-Interface | Widerstandsnetzwerk | Serienwiderstande fuer 5V - 3,3V Pegelanpassung |
| Stromversorgung | TLV62590BV | Synchroner Abwaertswandler, 5V (VCC-Pin) auf 3,3V, gesamte Platinenversorgung |
| USB | Integrierter Hub | RP2350 USB-Massenspeicher-Bruecke fuer Firmware-Flashen |
GPIO-Zuweisung
Die unten stehenden GPIO-Zuweisungen zeigen das typische Layout der pico6502 v2.2-Platine. Der KiCad-Schaltplan (
kicad/PICO6502/PICO6502_Schematic.pdf) ist die massgebliche Quelle.
| GPIO | Signal | Richtung | Hinweise |
|---|---|---|---|
| 0–15 | A0–A15 | Ausgang | 6502 Adressbus — getrieben von PIO 0 m6502_addr |
| 16–23 | D0–D7 | Bidirektional | 6502 Datenbus — getrieben/abgetastet von PIO 0 m6502_data |
| 24 | PHI0 | Eingang | Externer Takteingang fuer PIO 2 |
| 25 | PHI1 | Ausgang | Phase-1-Taktausgang — erzeugt von PIO 2 |
| 26 | PHI2 | Ausgang | Phase-2-Taktausgang — erzeugt von PIO 2 |
| 27 | RNW | Eingang | Read/Not-Write — abgetastet von PIO 1 |
| 28 | SYNC | Ausgang | Opcode-Fetch-Indikator — getrieben von PIO 1 |
| 29 | IRQ | Eingang | Maskierbarer Interrupt (aktiv low) — ueberwacht von PIO 1 |
| 30 | NMI | Eingang | Nicht-maskierbarer Interrupt (aktiv low) — ueberwacht von PIO 1 |
| 31 | RDY | Eingang | Ready-Signal — abgetastet von PIO 1 |
| 32 | SO | Eingang | Set Overflow — ueberwacht von PIO 1 |
| 33 | RESET | Bidirektional | System-Reset (aktiv low) |
| 34–39 | Flash | — | SPI NOR Flash (XIP) |
| 40–45 | PSRAM | — | QSPI PSRAM |
| 46–47 | ESP32 FSPI | — | SCLK, CS zum ESP32 |
| 48–49 | ESP32 UART | — | TX/RX 460,8kBaud zum ESP32 |
Firmwarearchitektur
Flash-Speicherlayout
Identisch mit dem picoZ80-Layout:
| Partition | Adressbereich | Groesse | Inhalt |
|---|---|---|---|
| Bootloader | 0x10000000–0x1001FFFF |
128KB | USB-Bruecke, Firmware-Update, Partitionsauswahl |
| App Slot 1 | 0x10020000–0x1051FFFF |
5MB | 6502-Hauptfirmware (Partition 1) |
| App Slot 2 | 0x10520000–0x10A1FFFF |
5MB | 6502-Hauptfirmware (Partition 2) |
| App Config 1 | 0x10A20000–0x10C9FFFF |
2.5MB | ROM-Images + minimierte Config-JSON (Slot 1) |
| App Config 2 | 0x10CA0000–0x10F1FFFF |
2.5MB | ROM-Images + minimierte Config-JSON (Slot 2) |
| General Config | 0x10F20000–0x10FFEFFF |
892KB | Kerneinstellungen, Scratch-Bereich |
| Partition Table | 0x10FFF000–0x11000000 |
4KB | Aktiver Slot, Pruefsummen, Metadaten |
Dual-Core-Design
| Kern | Verantwortlichkeiten |
|---|---|
| Core 0 | USB-Massenspeicher-Bruecke; Firmware-Partitionsverwaltung; Datei-I/O-Relay zum ESP32; ESP32-UART-Befehlsverteilung; Inter-Core-Queue-Bedienung |
| Core 1 | 6502-Bus-Emulations-Hauptschleife — bedient PIO-FIFOs fuer jeden Buszyklus, loest Adressen gegen die Speicherbelegung auf, leitet an PSRAM / PHYSICAL / FUNC-Handler weiter, ruft Treiber-Poll-Callbacks auf |
PIO-Bus-Interface
Das 6502-Bus-Interface ist in
M6502.pio ueber alle drei RP2350-PIO-Bloecke implementiert. Der Hauptunterschied zum Z80-Interface ist das Zweiphasen-nicht-ueberlappende Taktschema des 6502: PHI0 ist ein externer Takteingang; PIO 2 erzeugt daraus PHI1 und PHI2. Dies stellt korrektes 6502-Bus-Timing unabhaengig vom Core 1-Scheduling sicher.
PIO-Programme
| PIO-Block | Programm | Zustandsmaschinen | Funktion |
|---|---|---|---|
| PIO 0 | m6502_addr |
SM 0 | Gibt 16-Bit-Adresse A0-A15 aus; signalisiert IRQ 0 (Zyklusstart) |
| PIO 0 | m6502_data |
SM 1 | Treibt oder tastet D0-D7 ab; signalisiert IRQ 1 (Datenphase); Tri-State-Steuerung ueber RNW |
| PIO 1 | m6502_cycle |
SM 0 | Uebergeordneter Buszyklus-Sequenzer; IRQ 7 = Ausfuehrungsschleifen-Austritt |
| PIO 1 | m6502_fetch |
SM 1 | Opcode-Fetch-Zyklus (SYNC aktiviert, PHI2 hoch, RNW=1) |
| PIO 1 | m6502_read |
SM 1 | Speicher-Lese-Zyklus |
| PIO 1 | m6502_write |
SM 2 | Speicher-Schreib-Zyklus |
| PIO 1 | m6502_irq |
SM 2 | Ueberwacht IRQ-Pin; signalisiert PIO IRQ 5 bei Aktivierung |
| PIO 1 | m6502_nmi |
SM 3 | Ueberwacht NMI-Pin; signalisiert PIO IRQ 4 |
| PIO 1 | m6502_so |
SM 3 | Ueberwacht SO (Set Overflow)-Pin; signalisiert PIO IRQ 6 |
| PIO 2 | m6502_clock_6502 |
SM 0 | Erzeugt PHI1/PHI2-Zweiphasentakte aus externem PHI0-Eingang |
IRQ-Signalkonventionen
| PIO IRQ Flag | Signal | Ausgeloest durch | Verarbeitet von |
|---|---|---|---|
| IRQ 0 | Zyklusstart | m6502_addr — Adresse gueltig bei PHI1 |
Core 1 Dispatch-Schleife |
| IRQ 1 | Datenphase | m6502_data — Datenbus aktiv |
Core 1 Dispatch-Schleife |
| 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 | Schleifen-Austritt | Software-Anfrage | m6502_cycle — verlaesst Ausfuehrungsschleife |
PHI1/PHI2-Takterzeugung
Der 6502 benoetigt zwei nicht-ueberlappende Taktphasen. PIO 2 fuehrt das
m6502_clock_6502-Programm aus, das einen externen PHI0-Eingang auf einem dedizierten GPIO akzeptiert und PHI1 und PHI2 mit dem korrekten Nicht-Ueberlappungs-Timing erzeugt. Die Widmung eines ganzen PIO-Blocks fuer die Takterzeugung stellt sicher, dass das 6502-Bus-Timing niemals durch Core 1-Aktivitaet oder FIFO-Stalls beeinflusst wird.
Wartezustaende und RDY
Das
RDY-Signal des 6502 kann zur Einfuegung von Wartezustaenden verwendet werden — das Halten von RDY auf Low waehrend eines Lesezyklus pausiert den Prozessor, bis RDY wieder High wird. Der pico6502 kann RDY programmatisch von Core 1 aus aktivieren, um Wartezustaende beim Zugriff auf langsamere virtuelle Geraete (z.B. Diskettenemulation) einzufuegen. Der tcycwait-Parameter im Speicherbelegungs-JSON-Eintrag gibt die Anzahl der einzufuegenden Wartezustaende fuer einen bestimmten Speicherbereich an.
PIO-Architektur — Wie 6502-Buszyklen nachgebildet werden
Das PIO-Subsystem des RP2350 bildet zyklusgenaues 6502-Bus-Timing mit 10 Zustandsmaschinen ueber alle drei PIO-Bloecke nach. Die Architektur unterscheidet sich in zwei grundlegenden Punkten vom picoZ80-PIO: Der 6502 verwendet ein Zweiphasen-nicht-ueberlappendes Taktschema (PHI1/PHI2) anstelle eines Einzeltakts und ein einzelnes
Zweiphasen-Takterzeugung
R/W̄ (Read/Not-Write)-Signal anstelle separater /RD- und /WR-Signale.
Der 6502 benoetigt zwei nicht-ueberlappende Takte — PHI1 und PHI2. Ein externes PHI0-Signal liefert die Referenz; PIO 2 erzeugt daraus PHI1 und PHI2. Die
m6502_clock_6502-Zustandsmaschine (PIO 2 SM 0) implementiert dies:
PHI0 (input): ──┐ ┌──┐ ┌──
│ │ │ │
└────────┘ └────────┘
PHI1 (output): ┌──────┐ ┌──────┐
│ │ │ │
───┘ └──────────────┘ └───
PHI2 (output): ───┐ ┌──────┐ ┌──
│ │ │ │
└──────────────┘ └──────────────┘
↑ ↑ ↑
│ │ │
PHI0 faellt PHI0 steigt PHI0 faellt
→ kurze Luecke → kurze Luecke → kurze Luecke
→ PHI1 steigt → PHI1 faellt
→ PHI2 steigt
Die SM verwendet
Der jmp pin zur Erkennung von PHI0-Flanken und set pins zum Treiben von PHI1 und PHI2 mit den korrekten Nicht-Ueberlappungs-Luecken. Die [1]-Verzoegerungsannotation auf der ersten set pins-Instruktion erzeugt die Nicht-Ueberlappungsperiode — beide Takte sind fuer ein kurzes Intervall waehrend der Uebergaenge auf Low. Die Widmung eines ganzen PIO-Blocks fuer die Takterzeugung stellt sicher, dass das 6502-Bus-Timing niemals durch FIFO-Stalls oder Core 1-Latenz beeinflusst wird.
out exec, 32-Mechanismus
Wie der picoZ80 verwendet der pico6502 dynamische Instruktionsinjektion ueber
out exec — aber mit einem wesentlichen Unterschied: Die 6502-Zyklus-SM verwendet out exec, 32 (32-Bit-Instruktionen) anstelle der Z80-Version out exec, 16. Dies bietet die vollstaendige 32-Bit-PIO-Instruktionskodierung einschliesslich Side-Set-Bits, Verzoegerungswerten und erweiterten Operanden.
Die m6502_cycle-SM (PIO 1 SM 0) orchestriert alle Buszyklen:
// 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
Der C-Code berechnet 32-Bit-Instruktionssequenzen fuer jeden Zyklustyp (Fetch, Read, Write) vor und schiebt sie in den FIFO. Die Zyklus-SM zieht und fuehrt jede Instruktion der Reihe nach aus und steuert die
6502-Buszyklustypen
SYNC- und R/W̄-Signale, waehrend sie sich ueber IRQ-Flags mit den Adress- und Daten-SMs koordiniert.
Der 6502 hat drei Buszyklustypen, die alle durch den Zustand von
R/W̄ und SYNC gesteuert werden:
Opcode Fetch (m6502_fetch):
PHI1: ┌──────┐ ┌──
│ │ │
───┘ └──────────────┘
PHI2: ───┐ ┌──────┐
│ │ │
└──────────────┘ └───
A0–A15: ══╤═══ PC address ══════════╗ (gueltig bei steigender PHI1-Flanke)
R/W̄: ──┤── high (read) ─────────╢
SYNC: ──┤── high (fetch) ────────╢ (SYNC high = Opcode-Fetch)
D0–D7: ══════════════════╤════════╗ (abgetastet bei fallender PHI2-Flanke)
opcode
Memory Read (m6502_read):
Gleiches Timing wie Fetch, aber SYNC = low.
Memory Write (m6502_write):
PHI1: ┌──────┐ ┌──
│ │ │
───┘ └──────────────┘
PHI2: ───┐ ┌──────┐
│ │ │
└──────────────┘ └───
A0–A15: ══╤═══ address ═════════════╗ (gueltig bei steigender PHI1-Flanke)
R/W̄: ──┤── low (write) ─────────╢ (R/W̄ low = Schreiben)
SYNC: ──┤── low ─────────────────╢
D0–D7: ══════════════╤═══ data ═══╗ (getrieben waehrend PHI2 high)
Wesentliche Unterschiede zur Z80-PIO-Implementierung:
Signalueberwachungs-Zustandsmaschinen
- Einzelnes R/W̄-Signal — ersetzt die separaten
/RD- und/WR-Signale des Z80. Diem6502_fetch- undm6502_read-SMs setzenR/W̄high;m6502_writesetzt es low. - SYNC-Signal — der 6502 aktiviert
SYNCwaehrend Opcode-Fetches, um diese von gewoehnlichen Lesevorgaengen zu unterscheiden. Diem6502_fetch-SM setztSYNChigh;m6502_readundm6502_writelassen es low. - PHI2-basierte Datenabtastung — der Datenbus wird bei der fallenden PHI2-Flanke (Ende des Zyklus) abgetastet, nicht bei einer bestimmten T-State-Taktflanke wie beim Z80. Die
m6502_data-SM wartet aufwait 0 gpio CLK2, um die Datenerfassung zeitlich abzustimmen. - RDY-basierte Wartezustaende — anstelle des
/WAIT-Signals des Z80 verwendet der 6502RDY. WennRDYwaehrend eines Lesezyklus low ist, pausiert der Prozessor. Die Fetch- und Read-SMs pruefen RDY ueberjmp pinnach jeder steigenden PHI2-Flanke. - Kein Refresh-Zyklus — der 6502 hat keinen DRAM-Refresh-Zyklus, sodass Fetch-Zyklen einfacher sind (keine T3-T4-Refresh-Phase).
- Keine I/O-spezifischen Zyklen — der 6502 hat keine
IN/OUT-Instruktionen. Alle Peripheriezugriffe erfolgen ueber speicherabgebildete Lese- und Schreibvorgaenge.
Drei dedizierte SMs ueberwachen die asynchronen Eingangssignale des 6502:
m6502_irq(PIO 1 SM 2) — ueberwacht den/IRQ-Pin. Wenn/IRQlow wird, setzt sie PIO IRQ 5 und haelt es, bis der Pin wieder high wird, dann loescht sie das Flag. Core 1 prueft IRQ 5, um zu entscheiden, ob eine Interrupt-Vektor-Fetch-Sequenz injiziert werden soll.m6502_nmi(PIO 1 SM 3) — ueberwacht/NMIund setzt/loescht PIO IRQ 4. Der NMI-Handler in Core 1 schiebt die entsprechende Buszyklus-Sequenz zum Vektorieren durch$FFFA/$FFFB.m6502_so(PIO 1 SM 3) — ueberwacht denSO(Set Overflow)-Pin und setzt/loescht PIO IRQ 6. Dies wird von einigen 6502-Systemen (insbesondere dem Commodore-Diskettenlaufwerk) verwendet, um Data-Ready-Ereignisse zu signalisieren.
jmp pin zur Erkennung des aktiv werdenden Pins, irq set zur Signalisierung an Core 1, dann jmp pin in einer Schleife zur Erkennung des inaktiv werdenden Pins, gefolgt von irq clear. Dies wandelt asynchrone Flankenereignisse in synchrone IRQ-Flags um, die Core 1 effizient in der Hauptschleife abfragen kann.
Speichermodell
Das pico6502-Speichermodell ist strukturell identisch mit dem picoZ80-Modell mit einem entscheidenden Unterschied: Der 6502 hat keinen separaten I/O-Adressraum. Es gibt kein
ioPtr[]-Array in t_6502PSRAM und keinen iomap-JSON-Abschnitt. Alle Peripherieregister werden in den 64KB-Speicheradressraum mittels FUNC-Typ-Bloecken abgebildet.
Stufe 1 — RP2350 SRAM (Schnelle Dispatch-Tabelle)
128 x 32-Bit-Eintraege in
_membankPtr[], einer pro 512-Byte-Block des 64KB-Adressraums. Jeder Eintrag kodiert den Blocktyp, die PSRAM-Banknummer und die Block-Basisadresse in einem einzigen 32-Bit-Wort fuer O(1)-Dispatch bei jedem Buszyklus:
// 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))
Stufe 2 — PSRAM (8MB)
Die 8MB PSRAM werden zwischen dem RAM/ROM-Bereich und den Funktionszeiger-Tabellen aufgeteilt:
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;
Stufe 3 — Flash (16MB)
Der 16MB-Flash speichert den Bootloader, zwei 5MB-Anwendungsfirmware-Slots, zwei Konfigurationsslots fuer ROM-Images und minimierte JSON, allgemeine Konfiguration und die Partitionstabelle. Siehe die Flash-Speicherlayout-Tabelle im Abschnitt Firmwarearchitektur oben.
Speicherblocktypen
| Konstante | Wert | Verhalten |
|---|---|---|
MEMBANK_TYPE_PHYSICAL |
0 | Durchleitung zur realen Host-Hardware — RP2350 gibt Bus frei |
MEMBANK_TYPE_PHYSICAL_VRAM |
1 | Host-Video-RAM mit konfigurierbaren Wartezustaenden |
MEMBANK_TYPE_RAM |
2 | Lesen/Schreiben — durch PSRAM-Bank unterstuetzt |
MEMBANK_TYPE_ROM |
3 | Nur-Lesen — durch PSRAM-Bank unterstuetzt; Schreibzugriffe werden stillschweigend verworfen |
MEMBANK_TYPE_VRAM |
4 | PSRAM-Video-RAM-Spiegel mit Wartezustaenden |
MEMBANK_TYPE_FUNC |
5 | Virtuelles Geraet — memioPtr[addr]-Handler wird bei jedem Zugriff aufgerufen |
MEMBANK_TYPE_PTR |
6 | Pro-Byte-Umleitung — memPtr[addr]-Handler fuer Lesezugriffe |
Konfigurationsreferenz
Der pico6502 verwendet den gleichen JSON-Konfigurationsmechanismus wie der picoZ80. Die Top-Level-Schluessel sind
"esp32" und "rp2350". Der CPU-spezifische Abschnitt verwendet den Schluessel "6502" (statt "z80"). Da der 6502 keinen I/O-Adressraum hat, gibt es kein "io"-Array — nur ein "memory"-Array.
esp32.core
| Schluessel | Typ | Beschreibung |
|---|---|---|
device |
string | CPU-Geraetetyp. Muss "6502" fuer den pico6502 sein. |
mode |
integer | Standard-Bootmodus: 0 = Client (Station), 1 = Access Point. |
esp32.wifi
| Schluessel | Typ | Beschreibung |
|---|---|---|
override |
0/1 | 1 = alle WiFi-Einstellungen aus diesem Block anwenden; 0 = NVS-Einstellungen verwenden. |
wifimode |
string | "ap" oder "client". |
ssid |
string | Netzwerkname zum Erstellen (AP) oder Beitreten (Client). |
password |
string | WiFi-Passphrase. |
ip |
string | Feste IP-Adresse. |
netmask |
string | Subnetzmaske. |
gateway |
string | Standard-Gateway. |
dhcp |
0/1 | Nur Client-Modus. 1 = DHCP, 0 = feste IP. |
webfs |
string | Web-Dateisystem-Stammverzeichnis auf SD-Karte (Standard "webfs"). |
persist |
0/1 | 1 = aufgeloeste Einstellungen bei jedem Start in NVS schreiben. |
rp2350.core
| Schluessel | Typ | Beschreibung |
|---|---|---|
cpufreq |
integer | RP2350-Systemtakt in Hz (z.B. 300000000). |
psramfreq |
integer | PSRAM-SPI-Takt in Hz (z.B. 133000000). |
voltage |
float | RP2350-Kernspannung (z.B. 1.10). |
rp2350.6502.memory[ ]
Definiert die 6502-Speicherbelegung. Alle Peripheriegeraete muessen hier als
FUNC-Typ-Eintraege erscheinen — es gibt keine separate I/O-Zuordnung.
| Schluessel | Typ | Beschreibung |
|---|---|---|
enable |
0/1 | Ob dieser Eintrag aktiv ist. |
addr |
hex string | Startadresse im 6502-Adressraum (z.B. "0xE000"). |
size |
hex string | Bereichsgroesse in Bytes (z.B. "0x2000"). |
type |
string | PHYSICAL, PHYSICAL_VRAM, RAM, ROM, FUNC oder PTR. |
bank |
integer | PSRAM-Banknummer fuer RAM/ROM-Typen (0-63). |
tcycwait |
integer | Einzufuegende Wartezustaende (RDY-Stretching) fuer diesen Bereich. |
task |
string | Benannter Task-/Treiber-Handler fuer FUNC-Typ-Bloecke. |
file |
string | SD-Karten-Pfad zu einem ROM-Image zum Laden beim Booten (ROM-Typ). |
rp2350.6502.drivers[ ]
Treibereintraege fuer den 6502 sind einfacher als die fuer den Z80. Jeder Eintrag aktiviert einen benannten Treiber (abgeglichen gegen die
virtualFuncMap[]-Tabelle der Firmware) und laedt optional ROM-Images beim Booten in das PSRAM.
| Schluessel | Typ | Beschreibung |
|---|---|---|
enable |
0/1 | Ob dieser Treibereintrag aktiv ist. |
name |
string | Treibername — wird gross-/kleinschreibungsunabhaengig gegen virtualFuncMap[] abgeglichen. |
rom[] |
array | ROM-Images zum Laden beim Booten. Jeder Eintrag: enable, file, loadaddr[]. |
rom[]-Eintrag:
| Schluessel | Typ | Beschreibung |
|---|---|---|
enable |
0/1 | Ob dieses ROM-Image geladen wird. |
file |
string | SD-Karten-Pfad zur ROM-Binaerdatei. |
loadaddr[] |
array | Ein oder mehrere Ladeadressen-Deskriptoren: enable, position, addr, bank, size. |
Framework fuer virtuelle Geraete
Das Framework fuer virtuelle Geraete ist strukturell identisch mit dem picoZ80-Framework, beschrieben im picoZ80 Technischen Leitfaden. Der wesentliche Unterschied ist, dass alle virtuellen Geraete in
memioPtr[] registriert werden — es gibt kein ioPtr[]-Aequivalent fuer den 6502.
Handler-Signaturen
// 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);
Einen Peripherietreiber schreiben
Um ein virtuelles Peripheriegeraet fuer den pico6502 hinzuzufuegen:
- Erstellen Sie eine Handler-Funktion mit der
MemoryFunc-Signatur. Der Handler empfaengtread=truefuer 6502-Lesezyklen (RNW=1) undread=falsefuer Schreibzyklen (RNW=0). - Erstellen Sie eine Init-Funktion mit der
VirtualFunc-Signatur. Im Konfigurationsdurchlauf (pass=1) installieren Sie Ihren Handler incpu->_6502PSRAM->memioPtr[addr]fuer jede Adresse, die Ihr Peripheriegeraet belegt. - Registrieren Sie den Treibernamen und die Init-Funktion in der
virtualFuncMap[]-Tabelle inM6502CPU.c. - Fuegen Sie einen
FUNC-Typ-Eintrag immemory-Array derconfig.jsonfuer den Adressbereich hinzu. - Fuegen Sie einen Treibereintrag in
config.jsonmit dem passenden"name"-Feld hinzu.
Siehe den pico6502 Entwicklerhandbuch fuer ein vollstaendiges Beispiel einschliesslich einer VIA6522-Peripherie-Implementierung.
ESP32-Koprozessor
Der ESP32-Koprozessor ist in Funktion und Implementierung identisch mit dem picoZ80-ESP32 — siehe den picoZ80 Technischen Leitfaden — ESP32-Koprozessor fuer die vollstaendige Beschreibung des SD-Karten-Interfaces, der Webserverstruktur und des RP2350-ESP32-Befehlsprotokolls.
SD-Karte
Die SD-Karte wird ausschliesslich vom ESP32 ueber SPI verwaltet. Der RP2350 fordert Datei-Lese- und Schreibvorgaenge an, indem er Nachrichten an die Inter-Core-Queue sendet; Core 0 leitet diese Anfragen ueber UART an den ESP32 weiter und gibt die Ergebnisse zurueck. Das SD-Karten-Verzeichnislayout fuer den pico6502 ist identisch mit dem picoZ80:
webfs/ fuer Web-Dateien, ROM/ fuer ROM-Images und config.json im Stammverzeichnis.
Webserver
Der gleiche siebensseitige Bootstrap-4-Webserver laeuft auf dem ESP32. Die Weboberflaeche erkennt automatisch den verbundenen Geraetetyp ueber das
esp32.core.device-Feld in config.json und passt ihr CSS-Design und ihre Beschriftungen entsprechend an (das p6502.css-Stylesheet wendet das 6502-spezifische Farbschema an).
Befehlsprotokoll
Das RP2350-ESP32-Befehlsprotokoll ist fuer picoZ80 und pico6502 identisch. Befehle werden ueber eine 460,8kBaud-UART-Verbindung ausgetauscht (unterstuetzt durch 50MHz FSPI fuer Massendatentransfer). Das Protokoll ist in
ESP.c / ESP.h definiert und wird von beiden Firmware-Varianten geteilt.
SWD-Debugging — RP2350
Das SWD-Debugging-Setup fuer den pico6502 ist identisch mit dem picoZ80 — siehe den picoZ80 Technischen Leitfaden — SWD-Debugging fuer die vollstaendige Beschreibung der Hardwareverbindungen, des benutzerdefinierten
rp2350_tzpu.cfg OpenOCD-Targets und der globalen GDB-Initialisierung. Die Unterschiede zum picoZ80 sind:
- Die Hauptfirmware-ELF ist
build/bin/model/BaseM6502/BaseM6502_0x10020000.elf(nichtBaseZ80). - Der
add-auto-load-safe-path-Eintrag in~/.gdbinitmussBaseM6502referenzieren.
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-Konfiguration
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 (separates Terminal) cd build/bin/model/Bootloader cp ../../../../.gdbinit.bootloader.3334 .gdbinit gdb-multiarch Bootloader.elf
# Hauptfirmware — Core 0 cd build/bin/model/BaseM6502 cp ../../../../.gdbinit.3333 .gdbinit gdb-multiarch BaseM6502_0x10020000.elf # Hauptfirmware — Core 1 (separates Terminal) cd build/bin/model/BaseM6502 cp ../../../../.gdbinit.3334 .gdbinit gdb-multiarch BaseM6502_0x10020000.elf
ESP32 — USB-Debugging
Identisch mit dem picoZ80 — verbinden Sie USB mit dem ESP32-USB-Port und verwenden Sie das integrierte USB-JTAG-Interface des ESP32-S3 (kein externer Probe erforderlich).
openocd -f board/esp32s3-builtin.cfg xtensa-esp32s3-elf-gdb esp32/build/main.elf (gdb) target extended-remote :3333
Build-System
Das Build-System ist identisch mit dem picoZ80 — CMake mit Pico SDK 2.x fuer den RP2350. Der pico6502 benoetigt nicht die Zeta Z80-Emulator-Bibliothek. Siehe den picoZ80 Technischen Leitfaden — Build-System fuer die vollstaendige Beschreibung der Voraussetzungen, des Docker-Setups fuer ESP-IDF und des Build-Skripts. Die pico6502-spezifischen Unterschiede sind unten aufgefuehrt.
Build-Ziele
| Ziel | Ausgabe | Beschreibung |
|---|---|---|
BaseM6502 |
BaseM6502_0x10020000.uf2 |
6502-Hauptfirmware — Slot-1-Ladeadresse |
BaseM6502 |
BaseM6502_0x10520000.uf2 |
6502-Hauptfirmware — Slot-2-Ladeadresse |
Bootloader |
Bootloader.uf2 |
Gemeinsamer Bootloader (gleich wie picoZ80) |
| ESP32 | main.bin |
ESP32-Firmware (geteilt mit picoZ80) |
Build-Befehle
# Setup (einmalig) — vom Projektstammverzeichnis
export PICO_PATH=/path/to/pico-sdk
./get_and_build_sdk.sh
# Standard Release Build
./build_tzpuPico.sh
# Debug Build
./build_tzpuPico.sh DEBUG
# Vollstaendiger Build einschliesslich ESP32-Firmware
./build_tzpuPico.sh ALL
# Nur ESP32 (mit Docker idf54-Alias)
cd projects/tzpuPico/esp32
idf54 build
# RP2350 ueber USB-Massenspeicher flashen (BOOTSEL-Modus)
cp build/bin/model/Bootloader/Bootloader.uf2 /media/$USER/RPI-RP2/
cp build/bin/model/BaseM6502/BaseM6502_0x10020000.uf2 /media/$USER/RPI-RP2/
# ESP32 flashen (initial, ueber 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
Referenz-Websites
| Ressource | Link |
|---|---|
| pico6502 Projektseite | /pico6502/ |
| pico6502 Benutzerhandbuch | /pico6502-usermanual/ |
| pico6502 Entwicklerhandbuch | /pico6502-developersguide/ |
| picoZ80 Technischer Leitfaden | /picoz80-technicalguide/ |
| picoZ80 Projektseite | /picoz80/ |
| RP2350 Datasheet | datasheets.raspberrypi.com |
| Pico SDK Multicore API | raspberrypi.github.io/pico-sdk-doxygen |
| MOS 6502 Datasheet | archive.org |
| esptool Dokumentation | docs.espressif.com |
| cJSON Library | github.com/DaveGamble/cJSON |
Regulatorischer Hinweis fuer Funkgeraete
Dieses Geraet enthaelt ein ESP32-S3-PICO-1-Funkmodul, das im 2,4 GHz ISM-Band sendet und es damit zu einem beabsichtigten Strahler gemaess den Funkfrequenzvorschriften weltweit macht (einschliesslich FCC Part 15 Subpart C in den Vereinigten Staaten und der Funkanlagenrichtlinie 2014/53/EU in der Europaeischen Union).
Obwohl das ESP32-S3-PICO-1-Modul selbst ueber bestehende regulatorische Zertifizierungen verfuegt (FCC, CE und andere), erstrecken sich diese Modulzertifizierungen nicht automatisch auf ein fertiges Produkt, das das Modul enthaelt. Die Vorzertifizierungs-Ausnahme erlaubt es einzelnen Hobbyisten, eine begrenzte Anzahl von Geraeten fuer den persoenlichen, experimentellen oder bildungsbezogenen Gebrauch zu bauen, ohne eine separate Geraetezulassung zu erhalten.
Wichtige Einschraenkungen
Es liegt in der alleinigen Verantwortung des Bauherrn sicherzustellen, dass jedes aus diesen Designs konstruierte Geraet allen anwendbaren Funkfrequenzvorschriften in seiner Gerichtsbarkeit entspricht. Der Autor stellt diese Designs fuer den persoenlichen, bildungsbezogenen und Hobbygebrauch zur Verfuegung und gibt keine Zusicherung, dass ein aus ihnen gebautes Geraet die regulatorischen Anforderungen fuer den kommerziellen Vertrieb erfuellt.
- Zusammengebaute Geraete duerfen nicht verkauft, zum Verkauf angeboten, verschenkt oder anderweitig an Dritte verteilt werden, es sei denn, das fertige Produkt wurde unabhaengig getestet und hat eine eigene Geraetezulassung erhalten.
- Der Bau dieses Projekts fuer den persoenlichen Gebrauch in begrenzten Stueckzahlen ist im Allgemeinen unter Hobbyisten- und Experimentiervorschriften gestattet (z.B. FCC § 15.23), vorausgesetzt das Geraet verursacht keine schaedlichen Stoerungen.
- Regulatorische Anforderungen variieren je nach Land. Bauherren ausserhalb der Vereinigten Staaten sollten ihre nationale Funkfrequenzbehoerde konsultieren.
Es liegt in der alleinigen Verantwortung des Bauherrn sicherzustellen, dass jedes aus diesen Designs konstruierte Geraet allen anwendbaren Funkfrequenzvorschriften in seiner Gerichtsbarkeit entspricht. Der Autor stellt diese Designs fuer den persoenlichen, bildungsbezogenen und Hobbygebrauch zur Verfuegung und gibt keine Zusicherung, dass ein aus ihnen gebautes Geraet die regulatorischen Anforderungen fuer den kommerziellen Vertrieb erfuellt.