pico6502 Entwicklerhandbuch
Hinweis: Das pico6502-Projekt befindet sich in einer fruehen Entwicklungsphase. Das Treiberframework und das Speichermodell sind vollstaendig implementiert und teilen die gleiche Architektur wie der picoZ80. Allerdings existiert derzeit nur ein Platzhalter-BBC-Model-B-Persona — dieser Leitfaden erklaert, wie Sie auf dieser Grundlage eigene Treiber hinzufuegen koennen. Wo der pico6502 strukturell identisch mit dem picoZ80 ist, werden Querverweise zum picoZ80 Entwicklerhandbuch angegeben.
Uebersicht
Die pico6502-Firmware ist strukturell identisch mit der picoZ80-Firmware. Sie verwendet die gleiche Dual-Core-RP2350B-Architektur, das gleiche PSRAM-Speichermodell, das gleiche JSON-Konfigurationssystem und das gleiche Treiberframework — die wesentlichen Unterschiede sind:
- M6502CPU.c / M6502CPU.h ersetzen Z80CPU.c / Z80CPU.h als Haupt-Dispatch- und Treiberframework-Dateien.
- Der 6502 hat keinen separaten I/O-Adressraum — es gibt kein
ioPtr[]-Array und keineniomap-JSON-Abschnitt. Alle Peripheriegeraete werden alsFUNC-Typ-Bloecke in der 64KB-Speicherbelegung virtualisiert. - Das PIO-Bus-Interface (
M6502.pio) implementiert Zweiphasen-PHI1/PHI2-Taktung anstelle des Z80-Einzeltaktmodells. - Das Build-Zielverzeichnis ist
BaseM6502stattBaseZ80. - Der JSON-CPU-Abschnittsschluessel ist
"6502"statt"z80".
Alles andere — das Inter-Core-Queue-Muster, Treiber-Lifecycle-Callbacks (
reset_ptr, poll_ptr, task_ptr), die virtualFuncMap[]-Registrierungstabelle, Speicherblocktyp-Konstanten, die t_6502PSRAM-Struktur, das ESP32-Koprozessor-Protokoll und das Build-System — wird mit dem picoZ80-Codebase geteilt.
Quellbaum
Der gesamte Quellcode befindet sich unter
projects/tzpuPico/ im Repository-Stammverzeichnis. Das folgende Layout hebt pico6502-spezifische Dateien hervor:
tzpuPico/
├── CMakeLists.txt Top-Level-Build-Datei
├── src/
│ ├── CMakeLists.txt Quellcode-Build-Datei — neue Treiberdateien hier hinzufuegen
│ ├── M6502CPU.c *** SCHLUESSELDATEI: 6502-Dispatch, Treiberframework, virtualFuncMap
│ ├── M6502CPU.h (Legacy — eingebunden ueber include/)
│ ├── M6502.c PIO-Initialisierung und Buszyklus-Einstiegspunkte
│ ├── M6502.pio PIO-Programme: clock, addr, data, cycle, fetch, read, write, irq, nmi, so
│ ├── Z80CPU.c / Z80CPU.h Z80-Gegenstueck (nicht in pico6502-Builds verwendet)
│ ├── FSPI.c / FSPI.h Flash-SPI-Interface (gemeinsam)
│ ├── ESP.c / ESP.h ESP32-Kommunikationsschicht (gemeinsam)
│ ├── psram.c / psram.h PSRAM-Allokation und Verwaltung (gemeinsam)
│ ├── cJSON.c / cJSON.h JSON-Parser fuer config.json (gemeinsam)
│ ├── include/
│ │ ├── M6502CPU.h *** SCHLUESSELDATEI: alle 6502-Typdefinitionen und Makros
│ │ ├── M6502.h PIO-Hilfsdefinitionen
│ │ └── drivers/
│ │ └── BBC/
│ │ └── ModelB.h BBC Model B Treiber-Header (fruehes Platzhalter-Stadium)
│ ├── drivers/
│ │ └── BBC/
│ │ └── ModelB.c *** BEISPIEL/PLATZHALTER-TREIBER (BBC Model B Persona)
│ └── model/
│ ├── BaseM6502/
│ │ ├── CMakeLists.txt Modellspezifische Build-Ziele
│ │ ├── main.c Einstiegspunkt (Core 0 + Core 1 Start)
│ │ ├── main_memmap_partition_1.ld Linker-Skript fuer Slot 1
│ │ └── main_memmap_partition_2.ld Linker-Skript fuer Slot 2
│ └── Bootloader/
│ ├── CMakeLists.txt
│ └── main.c Gemeinsamer Bootloader (gleich wie picoZ80)
└── esp32/
├── CMakeLists.txt
└── main/
└── ... ESP32-Firmware (geteilt mit picoZ80)
Wesentliche Unterschiede zum picoZ80
Kein separater I/O-Adressraum
Der wichtigste architektonische Unterschied ist, dass der 6502 keine
IN/OUT-Instruktionen und kein IORQ-Signal hat. Jedes Peripheriegeraet muss irgendwo in der 64KB-Speicherbelegung erscheinen. Beim picoZ80 koennen virtuelle Geraete ueber memioPtr[] (speicherabgebildet) oder ioPtr[] (I/O-abgebildet) registriert werden. Beim pico6502 gibt es nur memioPtr[] — aber da alle Peripheriezugriffe ueber den Speicherbus erfolgen, deckt dies alle Faelle ab.
Die
t_6502PSRAM-Struktur hat daher kein ioPtr[]-Array. Die JSON-Konfiguration hat kein "io"-Array. Die Dispatch-Schleife in M6502CPU.c prueft nur das _membankPtr[]-Array und ruft fuer MEMBANK_TYPE_FUNC-Bloecke den entsprechenden memioPtr[]-Handler auf.
PIO-Bus-Interface-Unterschiede
Der 6502 verwendet ein Zweiphasen-nicht-ueberlappendes Taktschema. PHI0 ist ein externer Takteingang; der RP2350 erzeugt daraus PHI1 und PHI2 ueber eine dedizierte PIO 2-Zustandsmaschine (
m6502_clock_6502). Dies unterscheidet sich vom Z80, der ein einzelnes CLK-Signal verwendet.
| PIO-Block | Zustandsmaschinen | Zweck |
|---|---|---|
| PIO 0 | m6502_addr, m6502_data |
Adressbus (A0-A15), Datenbus (D0-D7) |
| PIO 1 | m6502_cycle, m6502_fetch, m6502_read, m6502_write, m6502_irq, m6502_nmi, m6502_so |
Buszyklus-Sequenzierung und Steuersignalueberwachung |
| PIO 2 | m6502_clock_6502 |
PHI1/PHI2-Zweiphasen-Takterzeugung aus externem PHI0 |
Die IRQ-Konvention unterscheidet sich leicht vom Z80-PIO-Interface:
| IRQ Flag | Signal | Bedeutung |
|---|---|---|
| IRQ 0 | Adresse/Zyklusstart | Neuer 6502-Buszyklus — Adresse gueltig bei steigender PHI1-Flanke |
| IRQ 1 | Datenphase | Datenbus aktiv — Lesen oder Schreiben je nach RNW |
| IRQ 4 | NMI | Nicht-maskierbarer Interrupt aktiviert |
| IRQ 5 | IRQ | Maskierbarer Interrupt aktiviert |
| IRQ 6 | SO | Set Overflow-Pin aktiviert |
| IRQ 7 | Schleifen-Austritt | Core 1-Ausfuehrungsschleifen-Austrittsanfrage |
PIO-Programmierung — Wie C-Code Buszyklen steuert
Der pico6502 verwendet den gleichen
out exec-Mechanismus wie der picoZ80 fuer dynamische Instruktionsinjektion, aber mit 32-Bit-Instruktionen (out exec, 32) anstelle von 16-Bit. Der C-Code auf Core 1 schiebt vorab kodierte PIO-Instruktionssequenzen in den TX-FIFO der Zyklus-SM, um jede Bustransaktion zu steuern.
Der Koordinationsablauf fuer einen 6502-Speicher-Lesezyklus:
Core 1 (C code) PIO State Machines
───────────── ──────────────────
1. Resolve address m6502_cycle: IRQ 0 set
from memory map (waiting on PHI2 low)
│
2. Push addr → TX FIFO ──────────────────→ m6502_addr: receives addr
Clear IRQ 0 outputs A0–A15 on pins
│
3. Push cycle instructions ──────────────→ m6502_cycle: out exec, 32
(read sequence) into executes: set R/W̄ high, SYNC low
cycle SM TX FIFO executes: wait PHI2 high
│ executes: check RDY
4. Wait for RX FIFO ←──────────────────── m6502_data: samples D0–D7
(data byte from bus) at PHI2 falling edge
│
5. Read data from m6502_cycle: JMP start_cycle
RX FIFO (ready for next cycle)
│
6. Dispatch to PSRAM
or driver handler
Bei Schreibzyklen schiebt Core 1 das Datenbyte nach der Adresse in den TX-FIFO der
m6502_data-SM. Die Daten-SM treibt D0-D7 waehrend der PHI2-High-Phase und setzt den Datenbus in Tri-State, wenn PHI2 faellt. Die Zyklus-SM setzt R/W̄ low, um einen Schreibvorgang anzuzeigen.
Fuer eine detaillierte Erklaerung der PIO-Grundlagen, des out exec-Mechanismus und der Zustandsmaschinen-Koordinierungsmuster siehe den picoZ80 Technischen Leitfaden — PIO-Architektur Deep Dive. Die 6502-spezifischen PIO-Unterschiede sind:
- 32-Bit
out exec— erlaubt vollstaendige PIO-Instruktionskodierung einschliesslich Side-Set- und Delay-Feldern in einem einzigen FIFO-Push. - Taktphasen-Synchronisation — Zyklus-SMs synchronisieren sich auf PHI2-Flanken (
wait 0/1 gpio CLK2) anstelle eines einzelnen CLK-Signals. - Kein BUSREQ/BUSACK — der 6502 hat keinen Bus-Request-Mechanismus, daher gibt es kein Aequivalent zur Z80-
z80_busrq-SM. - RDY statt WAIT — Wartezustaende werden durch Pruefen des RDY-Pins nach der steigenden PHI2-Flanke eingefuegt, anstelle des Z80-
/WAIT-Pins bei fallender T2-Flanke.
t_6502PSRAM-Struktur
Aequivalent zu
t_Z80PSRAM im picoZ80, aber ohne das ioPtr[]-Array:
// src/include/M6502CPU.h (simplified)
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[] — the 6502 has no separate I/O space
} t_6502PSRAM;
Handler-Funktionssignatur
Die
MemoryFunc-Typdefinition ist die gleiche wie beim picoZ80:
// Handler called for MEMBANK_TYPE_FUNC blocks on every access typedef uint8_t (*MemoryFunc)(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data); // Parameters: // cpu — pointer to the M6502CPU struct (access PSRAM, state, queues via this) // read — true for a 6502 read cycle (RNW=1), false for a write cycle (RNW=0) // addr — 16-bit address that triggered this handler // data — byte written (only meaningful when read=false) // Return: // byte to place on the data bus (only meaningful when read=true)
Da es keinen I/O-Adressraum gibt, gibt es keine separate
IOFunc-Typdefinition — MemoryFunc verarbeitet alle Peripheriezugriffe.
Treiberframework
Das Treiberframework in
M6502CPU.c ist strukturell identisch mit dem picoZ80-Treiberframework. Siehe den picoZ80 Entwicklerhandbuch — Treiberframework-Abschnitt fuer die vollstaendige Beschreibung von:
- Der
virtualFuncMap[]-Registrierungstabelle und wie das JSON-"name"-Feld mit einer Treiber-Init-Funktion abgeglichen wird. - Der
VirtualFunc-Typdefinition undM6502CPU_getVirtualFunc()-Suche. - Dem Zweiphasen-Init-Ablauf (Validierungsdurchlauf dann Konfigurationsdurchlauf).
- Treiber-Lifecycle-Callbacks:
reset_ptr,poll_ptr,task_ptr.
Die einzigen Namensunterschiede sind:
| picoZ80 | pico6502 | Hinweise |
|---|---|---|
Z80CPU struct |
M6502CPU struct |
Gleiche Felder, gleiches Layout |
Z80CPU_getVirtualFunc() |
M6502CPU_getVirtualFunc() |
Gleiche Suchlogik |
Z80CPU_cpu() |
M6502CPU_cpu() |
Core 1-Hauptschleifen-Einstiegspunkt |
Z80CPU_readMem() |
M6502CPU_readMem() |
Speicher-Lese-Dispatch |
Z80CPU_writeMem() |
M6502CPU_writeMem() |
Speicher-Schreib-Dispatch |
Z80CPU_readIO() |
— | Kein Aequivalent — 6502 hat keinen I/O-Adressraum |
Z80CPU_writeIO() |
— | Kein Aequivalent — 6502 hat keinen I/O-Adressraum |
cpu->_z80PSRAM |
cpu->_6502PSRAM |
PSRAM-Strukturzeiger |
Core 1-Dispatch-Schleife
Die Core 1-Hauptschleife in
M6502CPU_cpu() folgt dem gleichen Muster wie beim picoZ80. Bei jedem 6502-Buszyklus:
- Warte auf IRQ 0 (Adresse gueltig bei PHI1).
- Lese die 16-Bit-Adresse aus dem PIO 0 RX FIFO.
- Schlage
_membankPtr[addr >> 9]nach, um Blocktyp, Bank und Basis zu erhalten. - Bestimme RNW (Read/Not-Write) vom Steuer-PIO.
- Dispatch basierend auf Blocktyp: PHYSICAL (an Host weiterleiten), RAM (PSRAM lesen/schreiben), ROM (nur PSRAM lesen), FUNC (
memioPtr[addr]aufrufen), PTR (uebermemPtr[addr]umleiten). - Bei Lesen: Ergebnis ueber PIO 0 TX FIFO auf Datenbus legen. Auf IRQ 1 (Datenphase) warten. Bei Schreiben: Daten aus PIO 0 RX FIFO nach IRQ 1 lesen.
poll_ptrfuer jeden registrierten Treiber aufrufen (ca. alle ~2048 Zyklen).
// Simplified M6502CPU_readMem / M6502CPU_writeMem dispatch
uint8_t M6502CPU_readMem(M6502CPU *cpu, uint16_t addr)
{
uint32_t entry = cpu->_membankPtr[addr >> 9];
uint8_t type = (entry >> 24) & 0xFF;
uint8_t bank = (entry >> 16) & 0xFF;
uint32_t base = (entry & 0xFFFF) << 9;
switch(type)
{
case MEMBANK_TYPE_RAM:
case MEMBANK_TYPE_ROM:
return cpu->_6502PSRAM->RAM[(bank * MEMORY_PAGE_SIZE) + addr];
case MEMBANK_TYPE_FUNC:
if(cpu->_6502PSRAM->memioPtr[addr] != NULL)
return cpu->_6502PSRAM->memioPtr[addr](cpu, true, addr, 0);
return 0x00;
case MEMBANK_TYPE_PTR:
if(cpu->_6502PSRAM->memPtr[addr] != NULL)
return cpu->_6502PSRAM->memPtr[addr](cpu, true, addr, 0);
return 0x00;
case MEMBANK_TYPE_PHYSICAL:
default:
return 0xFF; // Pass-through to real host hardware
}
}
Einen neuen Treiber schreiben
Der Prozess zum Schreiben eines pico6502-Treibers ist identisch mit dem picoZ80-Prozess, beschrieben im picoZ80 Entwicklerhandbuch — Einen neuen Treiber schreiben. Die sechs Schritte sind die gleichen:
- Eine Header-Datei in
src/include/drivers/<Familie>/MyDriver.herstellen - Eine Implementierungsdatei in
src/drivers/<Familie>/MyDriver.cerstellen - Die Quelldatei zu
src/CMakeLists.txthinzufuegen - Den Treiber in
M6502CPU.cunter einem#ifdef INCLUDE_<FAMILY>_DRIVERS-Guard einbinden - Den Treiber in
virtualFuncMap[]inM6502CPU.cregistrieren - Einen JSON-Treibereintrag in
config.jsonhinzufuegen
Der wesentliche Unterschied ist, dass anstelle eines
Z80CPU *cpu-Parameters alle Funktionen einen M6502CPU *cpu-Parameter empfangen und Sie auf PSRAM ueber cpu->_6502PSRAM statt cpu->_z80PSRAM zugreifen. Es gibt keine ioPtr[]-Slots zum Installieren — alle virtuellen Peripheriegeraete werden in memioPtr[] registriert.
Minimale Treibervorlage
Das Folgende zeigt einen minimalen 6502-Peripherietreiber — eine virtualisierte 6522 VIA (Versatile Interface Adapter) bei Adresse
0xC000-0xC00F:
// src/include/drivers/BBC/VIA6522.h #ifndef VIA6522_H #define VIA6522_H #include "M6502CPU.h" int VIA6522_Init(M6502CPU *cpu, t_drvConfig *drvConfig, int pass); #endif
// src/drivers/BBC/VIA6522.c
#include "../../include/M6502CPU.h"
#include "../../include/drivers/BBC/VIA6522.h"
// --- Internal state ---
typedef struct {
uint8_t regs[16]; // VIA internal registers (ORB, ORA, DDRB, DDRA, T1CL, T1CH, ...)
bool irqPending;
} t_VIA6522State;
static t_VIA6522State ViaState = { .irqPending = false };
// --- Memory handler (called for every access to 0xC000–0xC00F) ---
static uint8_t VIA6522_Handler(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data)
{
uint8_t reg = addr & 0x0F; // VIA has 16 internal registers
if(read)
{
return ViaState.regs[reg];
}
else
{
ViaState.regs[reg] = data;
// TODO: implement timer, shift register, port logic as needed
return 0;
}
}
// --- Reset handler (called when host system resets) ---
static uint8_t VIA6522_Reset(M6502CPU *cpu)
{
memset(&ViaState.regs, 0, sizeof(ViaState.regs));
ViaState.irqPending = false;
return 0;
}
// --- Init function (called during JSON config parse) ---
int VIA6522_Init(M6502CPU *cpu, t_drvConfig *drvConfig, int pass)
{
if(pass == 0)
{
// Validation pass — just check the name matches
return (strcasecmp(drvConfig->name, "via6522") == 0) ? 1 : 0;
}
// Configuration pass — install handlers
// Install the handler for all 16 VIA registers at 0xC000–0xC00F
for(uint16_t addr = 0xC000; addr <= 0xC00F; addr++)
{
cpu->_6502PSRAM->memioPtr[addr] = VIA6522_Handler;
}
// Register reset callback
cpu->reset_ptr = VIA6522_Reset;
debugf("VIA6522: Initialised at 0xC000–0xC00F\n");
return 1;
}
JSON-Konfiguration
Um den VIA6522-Treiber zu aktivieren, fuegen Sie einen
FUNC-Block zur Speicherbelegung und einen Treibereintrag hinzu:
{
"rp2350": {
"6502": {
"memory": [
{ "enable":1, "addr":"0x0000", "size":"0xC000",
"type":"RAM", "bank":0, "task":"", "file":"" },
{ "enable":1, "addr":"0xC000", "size":"0x0010",
"type":"FUNC", "bank":0, "task":"via6522", "file":"" },
{ "enable":1, "addr":"0xE000", "size":"0x2000",
"type":"ROM", "bank":0, "task":"", "file":"/ROM/bios.rom" }
],
"drivers": [
{ "enable":1, "name":"via6522" }
]
}
}
}
In virtualFuncMap registrieren
Fuegen Sie einen Eintrag zur
virtualFuncMap[]-Tabelle in M6502CPU.c hinzu. Der name-String wird gross-/kleinschreibungsunabhaengig gegen das JSON-Treiber-"name"-Feld abgeglichen:
// In M6502CPU.c — add to virtualFuncMap[]
static const t_VirtualFuncMap virtualFuncMap[] = {
{ "BBCModelB", BBCModelB_Init }, // existing entry
{ "via6522", VIA6522_Init }, // your new driver
{ NULL, NULL } // terminator
};
CMakeLists.txt-Aenderung
Fuegen Sie die neue Quelldatei hinzu und aktivieren Sie sie ueber eine Kompilierungsdefinition in
src/CMakeLists.txt:
# In src/CMakeLists.txt
target_sources(tzpuPico PRIVATE
...
drivers/BBC/ModelB.c # existing
drivers/BBC/VIA6522.c # your new driver
)
target_compile_definitions(tzpuPico PRIVATE
INCLUDE_BBC_DRIVERS=1
)
Erstellen und Testen
# Vom Projektstammverzeichnis ./build_tzpuPico.sh # Ueber USB-Massenspeicher flashen cp build/bin/model/BaseM6502/BaseM6502_0x10020000.uf2 /media/$USER/RPI-RP2/ # Oder OTA: hochladen ueber http://<device-ip>/ota-rp2350.htm
Speicher-Hook-Muster
Da der 6502 keinen I/O-Adressraum hat, verwenden alle Hook-Muster
memioPtr[]. Die Muster sind die gleichen wie im picoZ80 Entwicklerhandbuch — Speicher-Hook-Muster beschrieben, wobei das I/O-Port-Handler-Muster durch einen speicherabgebildeten Handler an einer beliebigen Adresse ersetzt wird. Die wichtigsten Muster fuer 6502-Treiber sind:
FUNC-Block — Virtuelles Peripheriegeraet
Installieren Sie einen Handler fuer einen zusammenhaengenden Adressbereich. Dies ist das Standardmuster fuer alle 6502-Peripherie-Emulation:
// Install handler for address range 0xD000–0xD0FF (256-byte peripheral block)
for(uint16_t addr = 0xD000; addr <= 0xD0FF; addr++)
{
cpu->_6502PSRAM->memioPtr[addr] = MyPeripheral_Handler;
}
RAM-Schreib-Abfangen
Fangen Sie Schreibzugriffe auf einen RAM-Bereich ab, waehrend Lesezugriffe weiterhin aus dem PSRAM bedient werden. Nuetzlich fuer das Spiegeln von Zero-Page-Zugriffen oder das Erkennen von Schreibzugriffen auf bestimmte Adressen:
// Handler intercepts writes; passes reads to PSRAM
static uint8_t ZeroPage_Intercept(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data)
{
if(read)
{
// Read from PSRAM normally
return cpu->_6502PSRAM->RAM[addr];
}
else
{
// Write to PSRAM and update shadow state
cpu->_6502PSRAM->RAM[addr] = data;
MyDriver_OnZeroPageWrite(addr, data);
return 0;
}
}
// In init: set the block type to FUNC and install the handler
cpu->_membankPtr[0x0000 >> 9] = MEMBANK_ENCODE(MEMBANK_TYPE_FUNC, 0, 0x0000);
cpu->_6502PSRAM->memioPtr[0x0000] = ZeroPage_Intercept;
// ... repeat for each 512-byte block in the range
Verteilte / einzelne Adressen
Fuer Hardware, bei der nur wenige Adressen innerhalb eines groesseren Bereichs relevant sind (z.B. ein 4-Bit-Adressdecoder), installieren Sie den Handler nur an diesen spezifischen Adressen und lassen den Rest
0xFF oder PSRAM-Daten zurueckgeben:
// Only addresses 0xFFFE and 0xFFFF (6502 reset vector) are intercepted cpu->_6502PSRAM->memioPtr[0xFFFE] = ResetVector_Lo_Handler; cpu->_6502PSRAM->memioPtr[0xFFFF] = ResetVector_Hi_Handler;
BBC Model B Persona (Platzhalter)
Der einzige derzeit in der pico6502-Firmware vorhandene Treiber ist die BBC Model B Persona (
src/drivers/BBC/ModelB.c). Dies ist ein fruehes Platzhalter-Stadium, das das Treiberregistrierungsmuster demonstriert, aber noch nicht die vollstaendige BBC Micro-Hardware implementiert — der 6845 CRTC, die 6522 VIAs, der 6850 ACIA, der SAA5050-Teletext-Chip und die ULA sind nicht virtualisiert.
Der BBC Model B ist ein geeignetes erstes Ziel fuer den pico6502, da er einen Standard-6502 mit 2MHz verwendet, gut dokumentierte Hardware hat und ausschliesslich auf speicherabgebildete Peripheriegeraete angewiesen ist — was sich natuerlich mit dem FUNC-basierten Peripheriemodell des pico6502 deckt. Wenn die Persona vollstaendig ist, muss sie mindestens Folgendes virtualisieren:
| Adresse | Breite | Chip | Funktion |
|---|---|---|---|
0xFC00–0xFCFF |
256B | 6845 CRTC | Video-Timing-/Speicheradressgenerator |
0xFE00–0xFE0F |
16B | 6522 VIA A | System-VIA (Tastatur, Sound, Echtzeituhr) |
0xFE40–0xFE4F |
16B | 6522 VIA B | User-VIA (Parallelport, Benutzer-I/O) |
0xFE60–0xFE6F |
16B | 6850 ACIA | Serielles Interface |
0xFC00–0xFCFF |
256B | SAA5050 / ULA | Teletext / Video-ULA |
0xFE30 |
1B | ROM select | Seitenweise ROM-Bankauswahl-Register |
Core 0 / Core 1-Interaktion
Das Inter-Core-Queue-Muster ist identisch mit dem picoZ80. Siehe den picoZ80 Entwicklerhandbuch — Core 0 / Core 1-Interaktion fuer die vollstaendige Beschreibung und das Codebeispiel. Der einzige Namensunterschied ist, dass auf die Queue ueber einen
M6502CPU *cpu-Zeiger statt Z80CPU *cpu zugegriffen wird.
Wichtige Regel: Handler- und Poll-Callbacks laufen auf Core 1. Jede Datei-I/O, UART-Befehle an den ESP32 oder andere blockierende Operationen muessen ueber
cpu->requestQueue an Core 0 gesendet werden. Ergebnisse werden ueber cpu->responseQueue zurueckgegeben und in task_ptr verarbeitet.
Haeufige Fallstricke
- Handler in ioPtr statt memioPtr installieren. Der pico6502 hat kein
ioPtr[]-Array. Alle Peripherie-Handler gehoeren inmemioPtr[]. Der Versuch,ioPtr[]zu verwenden, fuehrt zu einem Build-Fehler oder undefiniertem Verhalten. - I/O-Dispatch-Aufruf erwarten. Es gibt kein
M6502CPU_readIO()oderM6502CPU_writeIO(). Wenn Sie einen Z80-Treiber portieren, derioPtr[]verwendet, verschieben Sie alle diese Handler aufmemioPtr[]an den entsprechenden Speicheradressen. - Blockieren in einem Handler. Jeder Aufruf von
debugf,sleep_msoderfopenaus einem Handler heraus blockiert Core 1 und beschaedigt das 6502-Bus-Timing. Verwenden Sie die Inter-Core-Queue fuer alle blockierenden Operationen. - Nicht uebereinstimmender virtualFuncMap-Name. Das JSON-
"name"-Feld wird gross-/kleinschreibungsunabhaengig gegen dievirtualFuncMap[]-Tabelle inM6502CPU.cabgeglichen. Ein Tippfehler in einem der beiden ueberspringt den Treiber stillschweigend. Fuegen Sie ein temporaeresdebugfinM6502CPU_getVirtualFunc()zur Diagnose hinzu. - Off-by-one im Handler-Bereich. Verwenden Sie
addr <= endAddrund nichtaddr < endAddr + 1— Letzteres riskiert einen Integer-Ueberlauf bei0xFFFF. Verwenden Sieaddr <= 0xFFFFmit eineruint32_t-Schleifenvariable, wenn der Bereich bis zum oberen Speicherende reicht. - Vergessen, den Blocktyp auf FUNC zu setzen. Die Installation eines Handlers in
memioPtr[]hat keine Wirkung, wenn die entsprechenden_membankPtr[]-Eintraege nochMEMBANK_TYPE_RAModerMEMBANK_TYPE_ROManzeigen. Rufen Sie immerMEMBANK_ENCODE(MEMBANK_TYPE_FUNC, ...)fuer jeden 512-Byte-Block in Ihrem Handler-Bereich auf. - reset_ptr beim Treiber-Shutdown nicht geloescht. Wenn Ihr Treiber zur Laufzeit neu konfiguriert wird und der Reset-Callback nicht mehr gueltig ist, setzen Sie
cpu->reset_ptrvor der Neuinitialisierung aufNULL, andernfalls ruft Core 1 beim naechsten Reset einen veralteten Funktionszeiger auf.
Referenz-Websites
| Ressource | Link |
|---|---|
| pico6502 Projektseite | /pico6502/ |
| pico6502 Benutzerhandbuch | /pico6502-usermanual/ |
| pico6502 Technischer Leitfaden | /pico6502-technicalguide/ |
| picoZ80 Entwicklerhandbuch | /picoz80-developersguide/ |
| picoZ80 Projektseite | /picoz80/ |
| RP2350 Datasheet | datasheets.raspberrypi.com |
| Pico SDK Multicore API | raspberrypi.github.io/pico-sdk-doxygen |
| MOS 6502 Datasheet | archive.org |
| BBC Micro Hardware Guide | stardot.org.uk |
| 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.