pico6502 Guida per Sviluppatori

English

Nota: Il progetto pico6502 e in fase di sviluppo iniziale. Il framework driver e il modello di memoria sono completamente implementati e condividono la stessa architettura del picoZ80. Tuttavia, attualmente esiste solo una persona BBC Model B segnaposto — questa guida spiega come costruire su quella base per aggiungere i propri driver. Dove il pico6502 e architetturalmente identico al picoZ80, vengono forniti riferimenti incrociati alla Guida dello sviluppatore picoZ80.

Panoramica

Il firmware del pico6502 e strutturato in modo identico al firmware del picoZ80. Usa la stessa architettura dual-core RP2350B, lo stesso modello di memoria PSRAM, lo stesso sistema di configurazione JSON e lo stesso framework driver — le differenze principali sono:
  • M6502CPU.c / M6502CPU.h sostituiscono Z80CPU.c / Z80CPU.h come file principali di dispatch e framework driver.
  • Il 6502 non ha uno spazio di indirizzamento I/O separato — non c'e un array ioPtr[] e nessuna sezione JSON iomap. Tutte le periferiche sono virtualizzate come blocchi tipo FUNC nella mappa di memoria da 64 KB.
  • L'interfaccia bus PIO (M6502.pio) implementa il clock bifase PHI1/PHI2 anziche il modello a clock singolo dello Z80.
  • La directory target di compilazione e BaseM6502 anziche BaseZ80.
  • La chiave della sezione CPU JSON e "6502" anziche "z80".
Tutto il resto — il pattern di coda inter-core, i callback del ciclo di vita dei driver (reset_ptr, poll_ptr, task_ptr), la tabella di registrazione virtualFuncMap[], le costanti tipo blocco memoria, la struct t_6502PSRAM, il protocollo del coprocessore ESP32 e il sistema di compilazione — e condiviso con il codebase del picoZ80.

Albero dei sorgenti

Tutto il codice sorgente si trova sotto projects/tzpuPico/ nella radice del repository. Il layout seguente evidenzia i file specifici del pico6502:
tzpuPico/
├── CMakeLists.txt                          File di compilazione di livello superiore
├── src/
│   ├── CMakeLists.txt                      File di compilazione a livello sorgente — aggiungere nuovi file driver qui
│   ├── M6502CPU.c                          *** FILE CHIAVE: dispatch 6502, framework driver, virtualFuncMap
│   ├── M6502CPU.h                          (legacy — incluso via include/)
│   ├── M6502.c                             Inizializzazione PIO e punti di ingresso cicli bus
│   ├── M6502.pio                           Programmi PIO: clock, addr, data, cycle, fetch, read, write, irq, nmi, so
│   ├── Z80CPU.c / Z80CPU.h                 Controparte Z80 (non usata per le compilazioni pico6502)
│   ├── FSPI.c / FSPI.h                     Interfaccia Flash SPI (condivisa)
│   ├── ESP.c / ESP.h                       Livello comunicazione ESP32 (condiviso)
│   ├── psram.c / psram.h                   Allocazione e gestione PSRAM (condivisa)
│   ├── cJSON.c / cJSON.h                   Parser JSON per config.json (condiviso)
│   ├── include/
│   │   ├── M6502CPU.h                      *** FILE CHIAVE: tutte le definizioni tipo e macro 6502
│   │   ├── M6502.h                         Definizioni helper PIO
│   │   └── drivers/
│   │       └── BBC/
│   │           └── ModelB.h               Header driver BBC Model B (segnaposto iniziale)
│   ├── drivers/
│   │   └── BBC/
│   │       └── ModelB.c                   *** DRIVER ESEMPIO/SEGNAPOSTO (persona BBC Model B)
│   └── model/
│       ├── BaseM6502/
│       │   ├── CMakeLists.txt             Target compilazione per modello
│       │   ├── main.c                     Punto di ingresso (lancio Core 0 + Core 1)
│       │   ├── main_memmap_partition_1.ld Script linker per Slot 1
│       │   └── main_memmap_partition_2.ld Script linker per Slot 2
│       └── Bootloader/
│           ├── CMakeLists.txt
│           └── main.c                     Bootloader condiviso (stesso del picoZ80)
└── esp32/
    ├── CMakeLists.txt
    └── main/
        └── ...                            Firmware ESP32 (condiviso con picoZ80)

Differenze chiave dal picoZ80

Nessuno spazio I/O separato

La differenza architetturale piu importante e che il 6502 non ha istruzioni IN/OUT e nessun segnale IORQ. Ogni periferica deve apparire da qualche parte nella mappa di memoria da 64 KB. Nel picoZ80, le periferiche virtuali possono essere registrate tramite memioPtr[] (mappate in memoria) o ioPtr[] (mappate in I/O). Nel pico6502 c'e solo memioPtr[] — ma poiche tutti gli accessi periferici passano attraverso il bus memoria, questo copre tutti i casi.
La struct t_6502PSRAM quindi non ha un array ioPtr[]. La configurazione JSON non ha un array "io". Il loop di dispatch in M6502CPU.c controlla solo l'array _membankPtr[] e, per i blocchi MEMBANK_TYPE_FUNC, chiama l'handler memioPtr[] corrispondente.

Struct t_6502PSRAM

Equivalente a t_Z80PSRAM nel picoZ80, ma senza l'array ioPtr[]:
// src/include/M6502CPU.h (semplificato)
typedef struct {
    uint8_t      RAM[MAX_MEMORY_BANKS * MEMORY_PAGE_SIZE]; // 64 banchi x 64 KB = 4 MB area RAM/ROM
    MemoryFunc   memPtr[MEMORY_PAGE_SIZE];                  // 64K reindirizzamento lettura per byte (tipo PTR)
    MemoryFunc   memioPtr[MEMORY_PAGE_SIZE];                // 64K array handler mappati memoria (tipo FUNC)
    // NOTA: nessun ioPtr[] — il 6502 non ha spazio I/O separato
} t_6502PSRAM;

Firma della funzione handler

// Handler chiamato per i blocchi MEMBANK_TYPE_FUNC ad ogni accesso
typedef uint8_t (*MemoryFunc)(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data);

// Parametri:
//   cpu  — puntatore alla struct M6502CPU (accesso PSRAM, stato, code tramite questo)
//   read — true per ciclo lettura 6502 (RNW=1), false per ciclo scrittura (RNW=0)
//   addr — indirizzo 16 bit che ha attivato questo handler
//   data — byte scritto (significativo solo quando read=false)
// Ritorno:
//   byte da posizionare sul bus dati (significativo solo quando read=true)

Framework driver

Il framework driver in M6502CPU.c e strutturalmente identico al framework driver del picoZ80. Fare riferimento alla sezione Guida dello sviluppatore picoZ80 — Framework driver per la descrizione completa della tabella di registrazione virtualFuncMap[], del flusso di inizializzazione a due passaggi e dei callback del ciclo di vita dei driver.
picoZ80 pico6502 Note
struct Z80CPU struct M6502CPU Stessi campi, stesso layout
Z80CPU_getVirtualFunc() M6502CPU_getVirtualFunc() Stessa logica di ricerca
Z80CPU_cpu() M6502CPU_cpu() Punto ingresso loop Core 1
Z80CPU_readMem() M6502CPU_readMem() Dispatch lettura memoria
Z80CPU_writeMem() M6502CPU_writeMem() Dispatch scrittura memoria
Z80CPU_readIO() Nessun equivalente — il 6502 non ha spazio I/O
Z80CPU_writeIO() Nessun equivalente — il 6502 non ha spazio I/O
cpu->_z80PSRAM cpu->_6502PSRAM Puntatore struct PSRAM

Scrivere un nuovo driver

Il processo per scrivere un driver pico6502 e identico a quello del picoZ80 descritto nella Guida dello sviluppatore picoZ80 — Scrivere un nuovo driver. I sei passaggi sono gli stessi:
  1. Creare un file header in src/include/drivers/<Family>/MyDriver.h
  2. Creare un file di implementazione in src/drivers/<Family>/MyDriver.c
  3. Aggiungere il file sorgente a src/CMakeLists.txt
  4. Includere il driver in M6502CPU.c sotto una guardia #ifdef INCLUDE_<FAMILY>_DRIVERS
  5. Registrare il driver in virtualFuncMap[] in M6502CPU.c
  6. Aggiungere una voce driver JSON in config.json
La differenza chiave e che anziche un parametro Z80CPU *cpu, tutte le funzioni ricevono un parametro M6502CPU *cpu, e si accede alla PSRAM tramite cpu->_6502PSRAM anziche cpu->_z80PSRAM. Non ci sono slot ioPtr[] da installare — tutte le periferiche virtuali sono registrate in memioPtr[].

Template driver minimo

Quanto segue mostra un driver periferica 6502 minimo — un 6522 VIA (Versatile Interface Adapter) virtualizzato all'indirizzo 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"

// --- Stato interno ---
typedef struct {
    uint8_t  regs[16];      // Registri interni VIA (ORB, ORA, DDRB, DDRA, T1CL, T1CH, ...)
    bool     irqPending;
} t_VIA6522State;

static t_VIA6522State ViaState = { .irqPending = false };

// --- Handler memoria (chiamato per ogni accesso a 0xC000–0xC00F) ---
static uint8_t VIA6522_Handler(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data)
{
    uint8_t reg = addr & 0x0F;

    if(read)
    {
        return ViaState.regs[reg];
    }
    else
    {
        ViaState.regs[reg] = data;
        return 0;
    }
}

// --- Handler reset ---
static uint8_t VIA6522_Reset(M6502CPU *cpu)
{
    memset(&ViaState.regs, 0, sizeof(ViaState.regs));
    ViaState.irqPending = false;
    return 0;
}

// --- Funzione init ---
int VIA6522_Init(M6502CPU *cpu, t_drvConfig *drvConfig, int pass)
{
    if(pass == 0)
    {
        return (strcasecmp(drvConfig->name, "via6522") == 0) ? 1 : 0;
    }

    for(uint16_t addr = 0xC000; addr <= 0xC00F; addr++)
    {
        cpu->_6502PSRAM->memioPtr[addr] = VIA6522_Handler;
    }

    cpu->reset_ptr = VIA6522_Reset;

    debugf("VIA6522: Inizializzato a 0xC000–0xC00F\n");
    return 1;
}

Pattern hook memoria

Poiche il 6502 non ha spazio I/O, tutti i pattern hook usano memioPtr[]. I pattern sono gli stessi descritti nella Guida dello sviluppatore picoZ80 — Pattern hook memoria, con il pattern handler porta I/O sostituito da un handler mappato in memoria a qualsiasi intervallo di indirizzi.

Errori comuni

  • Installare un handler in ioPtr anziche memioPtr. Il pico6502 non ha un array ioPtr[]. Tutti gli handler periferiche vanno in memioPtr[].
  • Aspettarsi una chiamata dispatch I/O. Non esiste M6502CPU_readIO() o M6502CPU_writeIO(). Se state portando un driver Z80, spostate tutti gli handler in memioPtr[].
  • Bloccare in un handler. Qualsiasi chiamata a debugf, sleep_ms o fopen da un handler blocchera il Core 1 e corrompe il timing bus del 6502.
  • Nome virtualFuncMap non corrispondente. Il campo JSON "name" e confrontato senza distinzione maiuscole/minuscole con la tabella virtualFuncMap[].
  • Dimenticare di impostare il tipo blocco a FUNC. Installare un handler in memioPtr[] non ha effetto se le voci _membankPtr[] corrispondenti mostrano ancora MEMBANK_TYPE_RAM o MEMBANK_TYPE_ROM.

Siti di riferimento

Risorsa Link
Pagina progetto pico6502 /pico6502/
Manuale utente pico6502 /pico6502-usermanual/
Guida tecnica pico6502 /pico6502-technicalguide/
Guida sviluppatore picoZ80 /picoz80-developersguide/
Pagina progetto picoZ80 /picoz80/
Scheda tecnica RP2350 datasheets.raspberrypi.com
Scheda tecnica MOS 6502 archive.org

Avviso normativo wireless

Questo dispositivo incorpora un modulo wireless ESP32-S3-PICO-1 che trasmette nella banda ISM a 2,4 GHz, rendendolo un emettitore intenzionale secondo le normative sulle radiofrequenze a livello mondiale (incluso FCC Part 15 Subpart C negli Stati Uniti e la Direttiva Apparecchiature Radio 2014/53/EU nell'Unione Europea).
Sebbene il modulo ESP32-S3-PICO-1 stesso possieda certificazioni normative preesistenti (FCC, CE e altre), tali certificazioni a livello di modulo non si estendono automaticamente a un prodotto finito che incorpora il modulo. L'esenzione per moduli pre-certificati consente agli hobbisti individuali di costruire un numero limitato di dispositivi per uso personale, sperimentale o educativo senza ottenere un'autorizzazione separata per l'apparecchiatura.
Limitazioni importanti
  • I dispositivi assemblati non devono essere venduti, offerti in vendita, regalati o altrimenti distribuiti a terzi a meno che il prodotto finito non sia stato testato indipendentemente e abbia ottenuto la propria autorizzazione per l'apparecchiatura nella giurisdizione pertinente.
  • La costruzione di questo progetto per uso personale in quantita limitate e generalmente consentita in base alle disposizioni per hobbisti e uso sperimentale (es. FCC § 15.23), a condizione che il dispositivo non causi interferenze dannose.
  • I requisiti normativi variano da paese a paese. I costruttori al di fuori degli Stati Uniti dovrebbero consultare la propria autorita nazionale per le radiofrequenze per le regole applicabili.
Responsabilita del costruttore
E responsabilita esclusiva del costruttore assicurarsi che qualsiasi dispositivo costruito da questi design sia conforme a tutte le normative sulle radiofrequenze applicabili nella propria giurisdizione. L'autore fornisce questi design per uso personale, educativo e hobbistico e non garantisce che un dispositivo costruito da essi soddisfi i requisiti normativi per la distribuzione commerciale.