picoZ80 Guida Tecnica

picoZ80 Guida Tecnica

Questa guida documenta l'architettura hardware del picoZ80, l'interfaccia bus PIO dell'RP2350, il modello di memoria, il riferimento per la configurazione JSON, il framework dei dispositivi virtuali e le procedure di debug. E' destinata agli sviluppatori che desiderano comprendere i meccanismi interni, scrivere nuovi driver, portare il firmware su una nuova macchina host o risolvere problemi a livello firmware.
Per la configurazione utente e l'utilizzo dell'interfaccia web, consultare il picoZ80 User Manual. Per una panoramica del progetto e le istruzioni di compilazione, consultare la pagina del progetto picoZ80.

Architettura Hardware

Il picoZ80 integra cinque sottosistemi su un singolo PCB compatto, progettato per rientrare nell'ingombro di un package DIP-40. Tutta la logica opera a 3,3V; l'interfaccia bus Z80 gestisce la traslazione dei livelli e il pilotaggio di corrente per il bus host a 5V.

Schema a Blocchi del Sistema

┌─────────────────────────────────────────────────────────────────────────┐
│                         picoZ80 PCB                                     │
│                                                                         │
│  ┌────────────────────────────┐      ┌──────────────────────────────┐  │
│  │         RP2350B            │      │           ESP32-S3           │  │
│  │  (Cortex-M33, dual core)   │      │                              │  │
│  │                            │      │  ┌──────┐  ┌──────────────┐ │  │
│  │  Core 0: USB, file I/O,    │◄────►│  │  SD  │  │  Web Server  │ │  │
│  │          ESP32 relay       │ FSPI │  │ Card │  │  (Bootstrap) │ │  │
│  │  Core 1: Z80 bus hot loop  │ UART │  └──────┘  └──────────────┘ │  │
│  │                            │      │                              │  │
│  │  PIO 0,1,2: bus interface  │      │  WiFi ─── 802.11 b/g/n AP   │  │
│  │                            │      │           or Client mode     │  │
│  │  16MB SPI Flash            │      └──────────────────────────────┘  │
│  │  8MB PSRAM (SPI)           │                                         │
│  └────────────────────────────┘                                         │
│                │                                                         │
│       ┌────────┴────────┐                                               │
│       │ Z80 Bus Interface│                                               │
│       │ (40-pin DIP out) │                                               │
│       └────────┬────────┘                                               │
│                │ 5V bus (A0–A15, D0–D7, MREQ, IORQ, RD, WR...)         │
└────────────────┼────────────────────────────────────────────────────────┘
                 │
         ┌───────┴───────┐
         │  Host Z80     │
         │  DIP-40 socket│
         │  (legacy      │
         │   computer)   │
         └───────────────┘

Componenti Principali

Componente Dispositivo Funzione
MCU PrimarioRP2350B (QFN-80)Dual Cortex-M33, 150MHz (fino a 300MHz OC), 512KB SRAM, 12 macchine a stati PIO, 48 pin GPIO
FlashW25Q128 (16MB SPI)Bootloader, doppio slot firmware, partizioni di configurazione
PSRAM8MB SPI PSRAM64 × 64KB banchi RAM/ROM per lo spazio di indirizzamento Z80
CoprocessoreESP32-S3-PICO-1WiFi, scheda SD, web server, OTA
Hub USBCH334FHub USB, bridging per aggiornamento firmware
AlimentazioneTLV62590BVConvertitore buck sincrono 5V → 3,3V

Assegnazione GPIO RP2350B

Il package RP2350B QFN-80 fornisce 48 pin GPIO. Il picoZ80 utilizza praticamente tutti i pin. L'assegnazione e' fissata nel design della scheda e riflessa nei programmi PIO:
Intervallo GPIO Segnali Direzione
GPIO 0–15 A0–A15 (Bus Indirizzi Z80) Uscita (pilotato da PIO)
GPIO 16–23 D0–D7 (Bus Dati Z80) Bidirezionale (PIO tri-state)
GPIO 24 MREQ Uscita
GPIO 25 IORQ Uscita
GPIO 26 RD Uscita
GPIO 27 WR Uscita
GPIO 28 M1 Uscita
GPIO 29 RFSH Uscita
GPIO 30 BUSREQ Ingresso
GPIO 31 BUSACK Uscita
GPIO 32 HALT Uscita
GPIO 33 INT Ingresso
GPIO 34 NMI Ingresso
GPIO 35 WAIT Uscita
GPIO 36 CLK Ingresso (clock host)
GPIO 37 RESET Ingresso
GPIO 38–41 ESP32 FSPI (CS, CLK, MOSI, MISO) SPI
GPIO 42–43 ESP32 UART (TX, RX) UART
GPIO 44–45 PSRAM SPI SPI
GPIO 46–47 USB (D+, D–) USB

Architettura Firmware

Il firmware dell'RP2350 e' costruito con il Raspberry Pi Pico SDK 2.x per la piattaforma RP2350-arm-s. Il firmware e' suddiviso in due eseguibili indipendenti: il Bootloader e l'Applicazione.

Layout della Memoria Flash

Partizione Intervallo Indirizzi Dimensione Contenuti
Bootloader 0x10000000 – 0x1001FFFF 128KB Bridge USB, aggiornamento firmware, selettore partizione
App Slot 1 0x10020000 – 0x1051FFFF 5MB Firmware Z80 — applicazione attiva (slot 1)
App Slot 2 0x10520000 – 0x10A1FFFF 5MB Firmware Z80 — applicazione attiva (slot 2)
App Config 1 0x10A20000 – 0x10C9FFFF 2,5MB Immagini ROM + JSON di configurazione minificato (slot 1)
App Config 2 0x10CA0000 – 0x10F1FFFF 2,5MB Immagini ROM + JSON di configurazione minificato (slot 2)
General Config 0x10F20000 – 0x10FFEFFF 892KB Impostazioni principali, spazio di lavoro
Partition Table 0x10FFF000 – 0x11000000 4KB Numero slot attivo, checksum, metadati

Responsabilita' Dual-Core

I due core Cortex-M33 hanno responsabilita' completamente separate e comunicano tramite una coda di messaggi inter-core (queue_t). Questa separazione garantisce che il lavoro non in tempo reale sul Core 0 non introduca mai jitter nelle transazioni bus Z80 sul Core 1.
Core Responsabilita'
Core 0 Bridge USB CDC-seriale; coordinamento aggiornamento firmware; I/O file (inoltrato all'ESP32 via UART); invio comandi ESP32 (cambi immagine disco, ricaricamenti configurazione, query versione); gestione partizioni; invio messaggi inter-core.
Core 1 Hot loop di emulazione del bus Z80 — esegue in modo esclusivo. Gestisce i FIFO PIO, risolve ogni transazione bus rispetto alla mappa di memoria e inoltra a: hardware host fisico (PHYSICAL), PSRAM (RAM/ROM) o handler di dispositivo virtuale (FUNC). Il loop interno e' posizionato in SRAM.

Interfaccia Bus PIO

L'interfaccia bus Z80 e' implementata interamente in assembly PIO dell'RP2350 (z80.pio). L'RP2350 fornisce tre blocchi PIO (PIO 0, PIO 1, PIO 2) ciascuno con quattro macchine a stati — dodici macchine a stati in totale, delle quali il firmware Z80 le utilizza tutte e dodici.
I programmi PIO vengono eseguiti indipendentemente dai core Cortex-M33. L'interfaccia bus continua a rispondere in modo deterministico anche quando il Core 1 e' impegnato con accessi alla PSRAM o chiamate a funzioni di dispositivi virtuali. Le macchine a stati comunicano tramite flag IRQ PIO anziche' tramite polling, eliminando la latenza inter-macchina.

Tabella Programmi PIO

PIO Macchina a Stati Programma Funzione
0 SM 0 z80_addr Emette l’indirizzo a 16 bit (A0–A15) sul bus e segnala l’inizio del ciclo a SM 2.
0 SM 1 z80_data Pilota o campiona D0–D7 con controllo tri-state; rilasciato durante BUSRQ.
0 SM 2 z80_cycle Sequenziatore del ciclo bus di livello superiore — orchestra i cicli di fetch, lettura, scrittura, I/O e refresh DRAM.
0 SM 3 z80_fetch Ciclo di fetch opcode (M1 + MREQ + RD).
1 SM 0 z80_mem_read Ciclo di lettura memoria (MREQ + RD).
1 SM 1 z80_mem_write Ciclo di scrittura memoria (MREQ + WR).
1 SM 2 z80_io_read Ciclo di lettura I/O (IORQ + RD).
1 SM 3 z80_io_write Ciclo di scrittura I/O (IORQ + WR).
2 SM 0 z80_busrq Gestisce BUSREQ/BUSACK; rilascia /IORQ, /MREQ, /RFSH, /M1, /HALT, /WR, /RD.
2 SM 1 z80_nmi Rileva l’asserzione NMI e segnala il Core 1.
2 SM 2 z80_clk_sync Sincronizza le macchine a stati PIO con il segnale CLK dello Z80 host.
2 SM 3 z80_int_ack Gestisce i cicli di acknowledge degli interrupt (M1 + IORQ).

Convenzioni Segnali IRQ PIO

La comunicazione inter-macchina a stati utilizza i flag IRQ PIO. Il Core 1 monitora questi flag nell'hot loop per intraprendere azioni su ogni evento del bus:
IRQ Evento
IRQ 0 Indirizzo valido / inizio ciclo — e’ iniziato un nuovo ciclo bus e A0–A15 sono stabili.
IRQ 1 Fase dati — la direzione del bus dati e’ stata risolta; D0–D7 devono essere pilotati o campionati.
IRQ 2 T1 rilevato — il fronte di salita di T1 nel ciclo corrente. Utilizzato per sincronizzare le operazioni interne con il clock host.
IRQ 3 Evento RESET — la linea RESET dell’host e’ stata asserita. Il Core 1 deve reinizializzare lo stato di emulazione.
IRQ 4 NMI rilevato — linea NMI dell’host asserita.
IRQ 6 BUSRQ attivo — l’host ha asserito BUSREQ; il PIO sta rilasciando il bus.

Generazione Wait State

Il programma PIO z80_wait in PIO 2 SM 0 inserisce wait state T-cycle configurabili sul bus host asserendo /WAIT. Il numero di wait state aggiuntivi e' controllato per ogni blocco di memoria o I/O tramite il parametro tcycwait in config.json.
I wait state sono necessari quando l'RP2350 necessita di tempo aggiuntivo per completare un accesso alla PSRAM o una chiamata a funzione di dispositivo virtuale prima di presentare i dati al bus host. Il parametro tcycsync abilita la sincronizzazione T1 (z80_sync in PIO 2 SM 1), che blocca la finestra di accesso alla PSRAM sul fronte di salita T1 di ogni ciclo bus, prevenendo derive temporali nelle applicazioni che dipendono dal clock host per temporizzazioni precise (cassetta, bit-banging seriale).

Architettura PIO — Come Vengono Ricreati i Cicli Bus

Il sottosistema Programmable I/O (PIO) dell'RP2350 e' la tecnologia chiave che permette al picoZ80 di ricreare la temporizzazione del bus Z80 con precisione al ciclo. Comprendere come le macchine a stati PIO lavorano insieme e' essenziale per chiunque modifichi l'interfaccia bus o esegua il debug di problemi di temporizzazione.

Fondamenti PIO dell'RP2350
Ogni blocco PIO contiene quattro macchine a stati (SM) indipendenti che eseguono piccoli programmi da una memoria di istruzioni condivisa di 32 posizioni. Le macchine a stati funzionano indipendentemente dai core Cortex-M33 alla frequenza del clock di sistema (fino a 300 MHz). Risorse PIO chiave utilizzate dal picoZ80:
  • TX FIFO — una coda a 4 elementi dalla CPU alla macchina a stati. Il codice C sul Core 1 inserisce dati (indirizzi, parole di controllo, istruzioni iniettate) nel FIFO; il programma PIO li preleva usando out o pull.
  • RX FIFO — una coda a 4 elementi dalla macchina a stati alla CPU. Il PIO inserisce i campioni del bus dati nel FIFO usando in; il Core 1 li legge dopo il completamento di ogni ciclo bus.
  • Flag IRQ — 8 flag (IRQ 0–7) condivisi tra tutte le macchine a stati all'interno di un blocco PIO. I flag possono anche essere visti tra blocchi PIO diversi (IRQ 0–3 in un blocco corrispondono a IRQ 4–7 nei blocchi adiacenti). Le macchine a stati usano irq set / irq wait / irq clear per sincronizzarsi tra loro e con il codice C.
  • Registri scratch X e Y — due registri a 32 bit per SM utilizzati per contatori di loop e valori temporanei.
  • out exec — un'istruzione speciale che preleva un valore dal TX FIFO e lo esegue come istruzione PIO. Questo e' il meccanismo con cui il codice C controlla dinamicamente le sequenze dei cicli bus (vedi sotto).
  • set pins / out pins — pilotano direttamente i pin GPIO. set usa un valore immediato a 5 bit; out trasferisce dati dall'output shift register (OSR) ai pin.
  • in pins — campiona i pin GPIO nell'input shift register (ISR), poi esegue auto-push nell'RX FIFO.
  • wait gpio — blocca la SM finche' un pin GPIO specifico raggiunge un livello specificato. Utilizzato estensivamente per sincronizzarsi con il segnale clock dello Z80 host.
  • Side-set — permette di pilotare uno o due pin GPIO come effetto collaterale di qualsiasi istruzione, senza utilizzare un ciclo di istruzione. Il picoZ80 usa side-set a 2 bit per controllare /RD e /WR simultaneamente con altre operazioni.
  • JMP PIN — salto condizionale basato sul livello di un pin GPIO designato. Utilizzato per verificare /WAIT, BUSREQ, /NMI e /RESET.

Il Meccanismo out exec — Iniezione Dinamica di Istruzioni
La caratteristica piu' distintiva del design PIO del picoZ80 e' l'uso di out exec, 16 nella macchina a stati orchestratrice z80_cycle. Questa istruzione preleva un valore a 16 bit dal TX FIFO e lo esegue immediatamente come istruzione PIO — il valore non e' un dato, e' la prossima istruzione che la macchina a stati eseguira'.
Questo meccanismo permette al codice C sul Core 1 di controllare la sequenza dei cicli bus in tempo reale. Anziche' caricare un programma PIO fisso per ogni tipo di ciclo, il Core 1 inserisce una sequenza di istruzioni PIO pre-codificate nel TX FIFO, e la SM del ciclo le esegue una per una:
// z80_cycle SM (PIO 0 SM 2) — the orchestrator
//
// .program z80_cycle
// .side_set 2 opt
// public start_cycle:
//     wait 0 irq 6             ; Pause if BUSACK is active (bus relinquished).
//     irq set 0                ; Signal "ready for new cycle".
//     wait 0 irq 0             ; Wait until C code clears IRQ 0 (address loaded).
//     wait 1 gpio Z80_PIN_CLK  ; Sync to T1 rising edge of host clock.
// cycle_exec:
//     out exec, 16             ; ← Pull next instruction from TX FIFO and execute it.
//     jmp cycle_exec           ; Loop: keep executing injected instructions.
//
// The C code pushes a sequence of encoded PIO instructions into the FIFO.
// Each instruction controls one step of the bus cycle (assert /MREQ, wait for
// clock edge, read data bus, etc.). The sequence ends with a JMP back to
// start_cycle, which restarts the orchestrator for the next bus transaction.
Il codice C pre-calcola queste sequenze di istruzioni all'avvio per ogni tipo di ciclo (fetch, lettura memoria, scrittura memoria, lettura I/O, scrittura I/O, refresh, acknowledge interrupt). Durante l'esecuzione, il Core 1 seleziona la sequenza pre-costruita appropriata e la inserisce nel FIFO. Questo approccio ha due vantaggi critici:
  • Efficienza dello spazio programma — ogni blocco PIO ha solo 32 slot di istruzioni. Iniettando le istruzioni dinamicamente, la SM del ciclo necessita di soli 7 istruzioni di memoria programma per orchestrare tutti i tipi di ciclo. I programmi effettivi dei tipi di ciclo (fetch, lettura, scrittura, ecc.) esistono come array C di istruzioni codificate, non come programmi PIO residenti.
  • Flessibilita' — il codice C puo' modificare la sequenza di istruzioni iniettate a runtime per gestire casi speciali (ad es. inserimento di wait state aggiuntivi, salto della fase di refresh, o generazione di un ciclo non standard per il debug).

Coordinamento delle Macchine a Stati
Le 12 macchine a stati lavorano come una pipeline coordinata. Il diagramma seguente mostra il flusso di un tipico ciclo di lettura memoria:
                  Core 1 (C code)               PIO State Machines
                  ─────────────                 ──────────────────
    1. Resolve address                          z80_cycle: IRQ 0 set
       from memory map                           (waiting for work)
                  │
    2. Push addr → TX FIFO ──────────────────→ z80_addr: receives addr
       Clear IRQ 0                               outputs A0–A15 on pins
                  │
    3. Push cycle instructions ──────────────→ z80_cycle: out exec, 16
       (e.g. mem_read sequence)                   executes: set /MREQ low
       into cycle SM TX FIFO                      executes: set /RD low
                  │                               executes: wait CLK edges
    4. Wait for RX FIFO ←────────────────────  z80_data: samples D0–D7
       (data byte from bus)                       pushes to RX FIFO
                  │
    5. Read data from                          z80_cycle: JMP start_cycle
       RX FIFO                                    (ready for next cycle)
                  │
    6. Dispatch to PSRAM
       or driver handler
L'handshake basato su IRQ garantisce che il bus indirizzi sia stabile prima che i segnali di controllo vengano asseriti, e che i dati vengano campionati nel punto corretto del ciclo bus. Le macchine a stati non effettuano mai polling — utilizzano wait 0 irq N per sospendersi finche' l'evento rilevante si verifica, consumando zero cicli CPU durante l'attesa.

Ciclo di Fetch Z80 (Ciclo M1) — Passo per Passo
Il fetch dell'opcode e' il ciclo bus Z80 piu' complesso — combina una lettura memoria con un ciclo di refresh. Il programma z80_fetch viene eseguito su 4 T-cycle del clock host:
Host CLK:  ──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
             │  │  │  │  │  │  │  │
             └──┘  └──┘  └──┘  └──┘
              T1    T2    T3    T4

A0–A15:    ══╤═══ PC address ══════╤═══ Refresh addr ══╗
             │                     │                    ║
/M1:       ──┘                     └────────────────────╜── (low during T1–T2, high T3–T4)
/MREQ:     ────┘              ┌────┘              ┌──── (low T1↓–T3↑, then T3↓–T4↓ for refresh)
/RD:       ────┘              ┌─────────────────────── (low T1↓–T3↑)
/RFSH:     ────────────────────┘                   ┌── (low T3↑–T4↓)
D0–D7:     ═══════════════╤═══╗                        (sampled at T3↑)
                          │   ║
                       opcode read
Il programma PIO implementa questo come segue:
  1. Fronte di salita T1 — la SM z80_addr emette il valore del PC su A0–A15. z80_fetch asserisce /M1 a livello basso tramite set pins.
  2. Fronte di discesa T1/MREQ e /RD vengono asseriti a livello basso (tramite set pins e side-set). L'indirizzo e' ora valido e il sistema di memoria puo' iniziare a rispondere.
  3. T2 — la SM entra in un loop di wait-state: attende il fronte di salita e poi di discesa del CLK, quindi controlla il pin /WAIT tramite jmp pin. Se /WAIT e' basso, la SM ripete il loop (aggiungendo cicli Tw). Se e' alto, procede a T3.
  4. Fronte di salita T3in pins, 8 campiona D0–D7 (il byte dell'opcode) e lo inserisce nell'RX FIFO. L'IRQ 1 viene attivato per segnalare a z80_data/z80_addr che l'indirizzo di refresh deve ora essere emesso. /M1, /MREQ e /RD vengono deasseriti; /RFSH viene asserito a livello basso.
  5. Fronte di discesa T3/MREQ viene asserito nuovamente (per lo strobe di riga del refresh).
  6. T4 — il refresh continua. Alla fine di T4, /MREQ e /RFSH vengono deasseriti. La SM del ciclo ritorna a start_cycle pronta per la transazione bus successiva.
Il Core 1 legge l'opcode dall'RX FIFO e lo utilizza per decodificare l'istruzione, determinare quanti cicli di memoria o I/O successivi sono necessari e inserire le sequenze di istruzioni appropriate.

Cicli di Lettura e Scrittura Memoria
I cicli di lettura e scrittura memoria sono piu' semplici del fetch — si estendono su 3 T-cycle senza fase di refresh.
Memory Read:
Host CLK:  ──┐  ┌──┐  ┌──┐  ┌──
             │  │  │  │  │  │
             └──┘  └──┘  └──┘
              T1    T2    T3

A0–A15:    ══╤═══ address ═══════╗
/MREQ:     ────┘              ┌──── (low T1↓–T3↓)
/RD:       ────┘              ┌──── (low T1↓–T3↓)
D0–D7:     ═══════════════╤═══╗     (sampled at T3↓)


Memory Write:
Host CLK:  ──┐  ┌──┐  ┌──┐  ┌──
             │  │  │  │  │  │
             └──┘  └──┘  └──┘
              T1    T2    T3

A0–A15:    ══╤═══ address ═══════╗
D0–D7:     ══════╤═══ data ═════╗   (driven from T2 onwards)
/MREQ:     ────┘              ┌──── (low T1↓–T3↓)
/WR:       ──────────┘        ┌──── (low T2↓–T3↓)
Per le letture, la SM z80_mem_read asserisce /MREQ e /RD al fronte di discesa T1, attende durante T2 (controllando /WAIT per i wait state), quindi campiona il bus dati al fronte di discesa T3 usando in pins, 8. Per le scritture, z80_mem_write asserisce /MREQ al fronte di discesa T1, quindi asserisce /WR al fronte di discesa T2 dopo che il bus dati e' stato pilotato da z80_data. Entrambi deasseriscono tutti i segnali di controllo alla fine di T3.

Cicli di Lettura e Scrittura I/O
I cicli I/O dello Z80 utilizzano /IORQ invece di /MREQ e includono sempre un wait state automatico (Tw) tra T2 e T3. Questa e' una caratteristica architetturale dello Z80 — il ciclo aggiuntivo da' ai dispositivi I/O piu' lenti il tempo di rispondere:
I/O Read:
Host CLK:  ──┐  ┌──┐  ┌──┐  ┌──┐  ┌──
             │  │  │  │  │  │  │  │
             └──┘  └──┘  └──┘  └──┘
              T1    T2    Tw    T3

A0–A15:    ══╤═══ port address ══════════╗
/IORQ:     ──────┘                    ┌──── (low T2↑–T3↓)
/RD:       ──────┘                    ┌──── (low T2↑–T3↓)
D0–D7:     ═══════════════════════╤═══╗     (sampled at T3↓)
La SM z80_io_read asserisce /IORQ e /RD al fronte di salita T2 (non T1 come per i cicli di memoria — questa e' la specifica dello Z80). Il wait state automatico Tw e' implementato dallo stesso pattern di loop jmp pin / wait utilizzato per i cicli di memoria. Le scritture I/O seguono lo stesso schema con /WR al posto di /RD.

Gestione BUSREQ / BUSACK
La SM z80_busrq (PIO 2 SM 0) monitora il pin di ingresso /BUSREQ dell'host. Quando /BUSREQ diventa attivo (basso), la SM:
  1. Attiva l'IRQ 6 per segnalare alla SM del ciclo che e' in sospeso una richiesta del bus.
  2. Attende il completamento del ciclo bus corrente (wait 1 irq 0).
  3. Preleva una parola di controllo a 32 bit dal TX FIFO che specifica le direzioni e i valori dei pin per lo stato di rilascio del bus — questo mette in tri-state i bus indirizzi e dati e asserisce /BUSACK a livello basso.
  4. Resta in loop su jmp pin finche' /BUSREQ diventa inattivo (alto).
  5. Preleva una seconda parola a 32 bit per ripristinare le direzioni normali dei pin e deasserire /BUSACK.
  6. Cancella l'IRQ 6, permettendo alla SM del ciclo di riprendere.
La SM del ciclo controlla l'IRQ 6 all'inizio di ogni ciclo tramite wait 0 irq 6 — se il flag e' attivato, la SM si blocca fino al completamento della richiesta del bus. Questo garantisce che il rilascio del bus avvenga in modo pulito tra i cicli, mai a meta' ciclo.

Sincronizzazione del Clock
Tutte le SM dei tipi di ciclo si sincronizzano con il clock dello Z80 host usando wait 1 gpio Z80_PIN_CLK (attesa fronte di salita) e wait 0 gpio Z80_PIN_CLK (attesa fronte di discesa). Questo significa:
  • I programmi PIO sono indipendenti dalla frequenza del clock — funzionano a qualsiasi velocita' di clock host, da DC alla velocita' massima che l'RP2350 puo' seguire (limitata dal clock di sistema PIO e dalla velocita' di campionamento GPIO).
  • Il clock PIO a 300 MHz dell'RP2350 fornisce circa 85 cicli PIO per T-state dello Z80 a 3,5 MHz, dando tempo piu' che sufficiente per eseguire istruzioni PIO, inserire/prelevare dai FIFO e controllare i flag IRQ tra i fronti del clock.
  • La SM z80_sync (PIO 2 SM 1) fornisce un IRQ di sincronizzazione T1 che il codice C utilizza per allineare gli accessi alla PSRAM con il clock host, prevenendo derive temporali nel software host sensibile al clock.
  • La SM z80_clk_sync (PIO 2 SM 2) rigenera il clock host su un GPIO separato, fornendo un'uscita clock pulita per il monitoraggio esterno o il trigger dell'analizzatore logico.

Ciclo di Acknowledge dell'Interrupt
La SM z80_int_ack (PIO 2 SM 3) implementa la sequenza di acknowledge dell'interrupt dello Z80. Quando il codice C rileva una condizione di interrupt, carica il programma int_ack. Questo ciclo e' simile a un fetch ma con differenze chiave:
  • /M1 viene asserito a T1 (come un fetch), ma /IORQ viene asserito invece di /MREQ al wait state (Tw1).
  • Vengono inseriti due wait state automatici (Tw1, Tw2) per dare al dispositivo che ha generato l'interrupt il tempo di posizionare un vettore sul bus dati.
  • Il byte del vettore viene letto da D0–D7 e inserito nell'RX FIFO.
  • Segue un ciclo di refresh, identico alla fase di refresh del fetch.

Modello di Memoria

Gli accessi alla memoria vengono risolti attraverso tre livelli a latenza crescente. Il design a tre livelli garantisce che il caso comune (RAM/ROM supportata da PSRAM) sia veloce, consentendo al contempo la massima flessibilita' per i dispositivi virtuali e il pass-through verso l'host fisico.

Livello 1 — Tabella di Dispatch SRAM dell'RP2350

Un array di 128 valori membankPtr a 32 bit, residente nella SRAM on-chip da 512KB dell'RP2350, fornisce un lookup O(1) del tipo di blocco per ogni transazione bus. Ogni voce copre ciascun blocco da 512 byte dello spazio di indirizzamento Z80 a 64KB (128 × 512 = 65.536 byte). Ogni voce codifica:
  • Il tipo di blocco (PHYSICAL, RAM, ROM, FUNC, ecc.).
  • Per i blocchi supportati da PSRAM: il numero del banco PSRAM e l'offset.
  • Per i blocchi FUNC: un indice nella tabella dei puntatori a funzione dei dispositivi virtuali.
Questo e' il percorso piu' veloce — il Core 1 legge la voce della tabella di dispatch per l'indirizzo corrente in un singolo accesso SRAM (zero wait state a 300MHz) prima di decidere cosa fare dopo.

Livello 2 — PSRAM Esterna

La PSRAM da 8MB e' organizzata come:
  • 64 banchi × 64KB — dati di immagini RAM o ROM per lo spazio di indirizzamento Z80.
  • 64KB memPtr — array di puntatori di redirect per byte per i blocchi di tipo PTR.
  • 64KB memioPtr — array di puntatori a funzione per dispositivi FUNC mappati in memoria.
  • 64KB ioPtr — array di puntatori a funzione per dispositivi FUNC su porte I/O.
La PSRAM viene acceduta tramite la periferica SPI dedicata dell'RP2350 con DMA. La latenza di accesso e' deterministica e gestita dal generatore di wait-state per evitare violazioni del bus.

Livello 3 — Flash SPI da 16MB

Le immagini ROM vengono caricate dalla Flash (o dalla scheda SD, tramite l'ESP32) nella PSRAM all'avvio. A runtime la Flash non viene acceduta per le transazioni bus — tutti i dati ROM vengono serviti dalla PSRAM. La Flash viene utilizzata per:
  • Bootloader e firmware applicativo.
  • config.json minificato (memorizzato nella cache dalla scheda SD ad ogni avvio).
  • Immagini ROM nelle partizioni App Config (utilizzate quando non e' presente la scheda SD).

Tipi di Blocchi Memoria

Tipo Descrizione
PHYSICAL Pass-through — l’RP2350 rilascia il bus e la memoria fisica dell’host risponde. Utilizzato per la ROM e la RAM native dell’host.
PHYSICAL_VRAM Come PHYSICAL ma con wait state aggiuntivi per la temporizzazione della video RAM dell’host. Adatto per le regioni VRAM di MZ-700/MZ-80A.
PHYSICAL_HW Pass-through per i registri hardware dell’host (dispositivi mappati in I/O nello spazio di memoria).
RAM Lettura/scrittura — supportato da un banco PSRAM. L’RP2350 gestisce letture e scritture da/verso la PSRAM.
ROM Sola lettura — supportato da un banco PSRAM. I cicli di scrittura vengono ignorati silenziosamente (l’host vede una temporizzazione bus normale ma nessun dato viene memorizzato).
VRAM Video RAM supportata da PSRAM. I cicli di scrittura vengono replicati contemporaneamente sia nella PSRAM che nella VRAM fisica dell’host.
FUNC Dispositivo virtuale — ogni accesso attiva una chiamata a funzione C tramite la tabella dei puntatori a funzione memioPtr o ioPtr, abilitando l’emulazione arbitraria di I/O.
PTR Redirect per byte — ogni byte del blocco da 512 byte puo’ puntare indipendentemente a qualsiasi altro tipo di blocco o posizione PSRAM.

Riferimento Configurazione

Tutto il comportamento del picoZ80 e' controllato da config.json sulla scheda SD. L'RP2350 legge e minifica questo file all'avvio, memorizzando il risultato nella Flash. Gli avvii successivi utilizzano la copia nella Flash se non e' presente la scheda SD.
La struttura JSON di livello superiore e':
{
  "esp32": {
    "core":  { ... },
    "wifi":  { ... }
  },
  "rp2350": {
    "core":  { ... },
    "z80":   [ { "memory": [...], "io": [...], "drivers": [...] } ]
  }
}

esp32.core

Chiave Tipo Descrizione
device string Personalita’ CPU — "Z80" per picoZ80, "6502" per pico6502, "6512" per pico6512.
mode integer Modalita’ WiFi di avvio predefinita: 0 = client (station), 1 = Access Point.

esp32.wifi

Chiave Tipo Descrizione
override 0/1 Interruttore principale: 1 = applica tutte le impostazioni seguenti; 0 = usa le impostazioni NVS persistenti.
wifimode string "ap" = modalita’ Access Point; "client" = modalita’ Station/client.
ssid string Nome della rete WiFi da creare (AP) o a cui connettersi (client).
password string Passphrase WiFi.
ip string Indirizzo IP fisso (ad es. "192.168.1.192").
netmask string Maschera di sottorete (ad es. "255.255.255.0").
gateway string Gateway predefinito (ad es. "192.168.1.1").
dhcp 0/1 Modalita’ client: 1 = DHCP; 0 = usa le impostazioni IP fisse.
webfs string Directory root del filesystem web sulla scheda SD (predefinito "webfs").
persist 0/1 1 = scrive le impostazioni risolte nel NVS per la persistenza tra i riavvii.

rp2350.core

Chiave Tipo Descrizione
cpufreq integer Clock di sistema dell’RP2350 in Hz (ad es. 300000000). La frequenza massima stabile dipende dalla frequenza PSRAM e dalla tensione del core.
psramfreq integer Clock SPI della PSRAM in Hz (ad es. 133000000).
voltage float Tensione del core dell’RP2350 in volt (ad es. 1.10). Velocita’ di clock piu’ elevate richiedono tensioni piu’ alte.
addrDrive integer (0–3) Capacita’ di pilotaggio GPIO del bus indirizzi: 0=2mA, 1=4mA, 2=8mA, 3=12mA. Predefinito 0.
addrSlew integer (0–1) Slew rate GPIO del bus indirizzi: 0=lento (predefinito), 1=veloce.
dataDrive integer (0–3) Capacita’ di pilotaggio GPIO del bus dati. Stessa codifica di addrDrive. Predefinito 0.
dataSlew integer (0–1) Slew rate GPIO del bus dati. Stessa codifica di addrSlew. Predefinito 0.
ctrlDrive integer (0–3) Capacita’ di pilotaggio GPIO dei segnali di controllo. Stessa codifica di addrDrive. Predefinito 0.
ctrlSlew integer (0–1) Slew rate GPIO dei segnali di controllo. Stessa codifica di addrSlew. Predefinito 0.
addrSchmitt / dataSchmitt / ctrlSchmitt 0/1 Abilita l’ingresso Schmitt-trigger per il gruppo di bus indirizzo / dati / controllo. 1 = abilitato (predefinito), 0 = disabilitato. Si applica ai pin configurati come ingressi.
addrPull / dataPull / ctrlPull integer (0–2) Resistenza di pull per il gruppo di bus indirizzo / dati / controllo: 0 = nessuna, 1 = pull-down, 2 = pull-up.
refresh integer Generazione del refresh DRAM Z80: 0 = off (nessun ciclo di refresh), 1 = un ciclo di refresh a ogni fetch di opcode, N = un ciclo di refresh ogni N fetch. Riduce l’overhead del bus sugli host la cui DRAM non richiede un refresh per fetch.
pinOverrides array Override GPIO per singolo pin. Ogni elemento: { "pin": N, "drive": D, "slew": S, "schmitt": 0/1, "pull": P }. Sovrascrive i valori predefiniti a livello di bus per i singoli pin GPIO quando un hardware specifico richiede caratteristiche elettriche diverse.

z80[].memory — Voci della Mappa di Memoria

L'array memory definisce la mappa di memoria dello Z80. Le voci devono essere ordinate per indirizzo. Le regioni devono essere allineate a e dimensionate come multipli di 512 byte. I vuoti tra le voci vengono trattati come pass-through PHYSICAL.
Chiave Tipo Descrizione
enable 0/1 Se questa voce e’ attiva. Le voci disabilitate vengono ignorate all’avvio.
addr hex string Indirizzo di partenza nello spazio di indirizzamento Z80 (ad es. "0x0000"). Deve essere allineato a 512 byte.
size hex string Dimensione della regione in byte (ad es. "0x2000" per 8KB). Deve essere un multiplo di 512.
type string Tipo di blocco — vedi Tipi di Blocchi Memoria.
bank integer Numero del banco PSRAM (0–63) per i tipi RAM/ROM/VRAM/FUNC.
tcycwait integer Wait state T-cycle aggiuntivi da inserire su ogni accesso a questa regione.
tcycsync 0/1 Abilita la sincronizzazione T1 per questa regione. Necessario per le regioni sensibili alla temporizzazione.
task string Identificatore di task opzionale per i blocchi di tipo FUNC (stringa di binding del driver).
file string Percorso sulla scheda SD di un’immagine ROM da precaricare nel banco PSRAM all’avvio (ad es. "/ROM/mz700.rom").
fileofs integer Offset in byte nel file dell’immagine ROM da cui iniziare la lettura.

z80[].io — Voci della Mappa Porte I/O

L'array io mappa gli intervalli di porte I/O dello Z80 ai tipi di blocco. Solo i tipi PHYSICAL e FUNC sono significativi per le voci I/O.
Chiave Tipo Descrizione
enable 0/1 Se questa voce I/O e’ attiva.
addr hex string Indirizzo di partenza della porta I/O (ad es. "0xE0").
size hex string Numero di porte consecutive (ad es. "0x04" per le porte E0–E3).
type string PHYSICAL = passa all’host; FUNC = chiama la funzione handler C.
task string Stringa di binding del driver per le voci di tipo FUNC.

z80[].drivers — Istanze dei Driver

L'array drivers istanzia i driver dei dispositivi virtuali e li lega alle regioni di memoria o I/O. Ogni driver ha un tipo (il modulo driver C), un nome (identificatore dell'istanza) e uno o piu' oggetti interfaccia che definiscono le immagini ROM, le mappe degli indirizzi, le mappe I/O e i parametri per quell'istanza del driver.
"drivers": [
  {
    "enable": 1,
    "name":   "MZ700",
    "type":   "PHYSICAL",
    "if": [
      {
        "enable": 1,
        "name":   "main",
        "type":   "PHYSICAL",
        "rom": [
          {
            "enable":   1,
            "file":     "/MZ700/mz700.rom",
            "loadaddr": [
              {
                "enable":   1,
                "position": 0,
                "addr":     "0x0000",
                "bank":     0,
                "size":     "0x1000",
                "tcycwait": 0,
                "tcycsync": 0
              }
            ]
          }
        ],
        "addrmap": [
          { "enable":1, "srcaddr":"0x0000", "size":"0x1000",
            "dstaddr":"0x0000" }
        ],
        "iomap": [
          { "enable":1, "srcaddr":"0xE0", "size":"0x08",
            "dstaddr":"0xE0", "16bit":0 }
        ],
        "param": [
          { "enable":1, "file":"/config/mz700.cfg" }
        ]
      }
    ]
  },
  {
    "enable": 1,
    "name":   "MZ-1E05",
    "type":   "PHYSICAL",
    "if": [
      {
        "enable": 1,
        "name":   "fdc0",
        "type":   "PHYSICAL",
        "rom":    [],
        "addrmap": [],
        "iomap": [
          { "enable":1, "srcaddr":"0xD8", "size":"0x04",
            "dstaddr":"0xD8", "16bit":0 }
        ],
        "param": [
          { "enable":1, "file":"/DSK/MZ700/disk0.dsk" }
        ]
      }
    ]
  }
]
Ogni voce driver ha un "name" di livello superiore (il modulo driver C da istanziare), "type" (PHYSICAL o VIRTUAL) e un array "if" (interfaccia) contenente uno o piu' oggetti interfaccia. Ogni oggetto interfaccia descrive un sotto-driver o una scheda periferica e contiene questi campi:
Chiave Tipo Descrizione
enable 0/1 Se questa interfaccia e’ attiva (0 = saltata durante l’inizializzazione).
name string Identificatore dell’istanza — deve corrispondere a un nome nell’interfaceFuncMap[] della persona.
type string PHYSICAL o VIRTUAL.
rom array Immagini ROM da caricare nella PSRAM (vedi sotto).
addrmap array Voci di rimappatura indirizzi di memoria (srcaddr/dstaddr/size).
iomap array Voci di rimappatura porte I/O (srcaddr/dstaddr/size/16bit).
param array Parametri specifici del driver — tipicamente { "enable":1, "file":"/path/to/image" } per immagini disco, { "name":"key", "value":"val" } per parametri nominati, o { "ip":"a.b.c.d:port", "enable":1 } per l’indirizzo del file server di rete Celestite.

Porte base delle interfacce riposizionabili. Affinche’ le schede indipendenti dalla macchina possano essere utilizzate su schede personalizzate / sperimentali (vedi OpenZ80), diversi driver di interfaccia leggono la loro porta I/O base dal dstaddr della relativa voce iomap (con srcaddr impostato sulla porta autentica della scheda), utilizzando come predefinita la loro porta originale quando non e’ presente alcuna voce iomap. Le schede riposizionabili e le porte base predefinite sono MZ-1R12 (0xF8/3), MZ-1R18 (0xEA/2), MZ-1R23 (0xB8/2), MZ-1R37 (0xAC/2), PIO-3034 (0x00/4), MZ-8BIO3 / MZ-1E24 (0xB0/4), MZ-1E05 (0xD8/7) e Celestite (0x60/16). Le chiavi JSON sono in minuscolo (srcaddr / dstaddr) e i loro valori vengono interpretati come numeri. Il campo Base I/O Port nella pagina di configurazione GUI scrive automaticamente la voce iomap corretta.

rom[].loadaddr[] — Indirizzi di Caricamento ROM

Ogni voce file ROM contiene un array loadaddr che specifica dove i dati ROM vengono caricati nella PSRAM. Piu' voci loadaddr permettono a un singolo file ROM di essere suddiviso su intervalli di indirizzi non contigui o banchi PSRAM diversi.
Chiave Tipo Descrizione
enable 0/1 Se questo indirizzo di caricamento e’ attivo.
position integer Offset in byte all’interno del file ROM da cui iniziare la lettura.
addr hex string Indirizzo Z80 di destinazione nella mappa di memoria (ad es. "0x0000").
bank integer Numero del banco PSRAM in cui caricare.
size hex string Numero di byte da caricare (ad es. "0x1000" per 4KB).
tcycwait integer Wait state T-cycle aggiuntivi per questa regione.
tcycsync integer Valore di sincronizzazione T-cycle per questa regione.

Compatibilita' Persona–Interfaccia

Non tutti i driver di interfaccia sono disponibili per ogni persona. La tabella seguente mostra la compatibilita' attuale delle interfacce per le serie Sharp MZ / X1. La persona Amstrad PCW-9512 e' un driver autonomo con un FDC uPD765 integrato (nessun driver di interfaccia separato). La persona Tatung Einstein TC-01 e' un driver autonomo con un FDC WD1770 integrato e una sotto-interfaccia EinsteinFDC. La colonna Open mostra le schede indipendenti dalla macchina accettate dalla persona sperimentale OpenZ80.
La tabella mostra quali interfacce possono essere utilizzate con ogni persona macchina di livello superiore tramite l'array "if". Il valore "name" dell'interfaccia nel JSON deve corrispondere a una delle voci supportate per la persona scelta.
Interfaccia MZ-700 MZ-1500 MZ-80K MZ-800 MZ-80A MZ-2000 MZ-2200 MZ-80B MZ-2500 Open
RFS Si’ Si’ Si’ Si’ Si’ Si’
TZFS Si’
MZ-1E05 Si’ Si’ Si’ Si’
MZ80FIO Si’ Si’
MZ80AFI Si’ Si’ Si’
MZ-8BFI / E0054PA Si’ Si’ Si’ Si’ Si’
MZ-1E14 Si’ Si’ Si’ Si’ Si’ Si’
MZ-1E19 Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’
MZ-1R12 Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’
MZ-1R18 Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’ Si’
MZ-1R23 Si’ Si’ Si’ Si’ Si’
MZ-1R37 Si’ Si’ Si’ Si’ Si’ Si’
PIO-3034 Si’ Si’ Si’ Si’ Si’ Si’
Celestite Si’ Si’ Si’ Si’ Si’
MZ-8BIO3 Si’ Si’ Si’ Si’ Si’
MZ-1E24 Si’ Si’ Si’ Si’ Si’
MZ-1E30 Si’ Si’

Driver Integrati

Il firmware supporta un sistema di compilazione mirato con cinque target di modello: BaseZ80 (tutti i driver), SharpZ80 (solo Sharp), AmstradZ80 (solo Amstrad), TatungZ80 (solo Tatung) e OpenZ80 (la persona sperimentale indipendente dalla macchina). Le define a tempo di compilazione INCLUDE_SHARP_DRIVERS, INCLUDE_AMSTRAD_DRIVERS, INCLUDE_TATUNG_DRIVERS e INCLUDE_OPEN_DRIVERS controllano quali moduli driver vengono compilati. Le tabelle seguenti elencano tutti i driver disponibili.
Serie Sharp MZ (INCLUDE_SHARP_DRIVERS)
Quando il firmware viene compilato con INCLUDE_SHARP_DRIVERS, i seguenti moduli driver vengono compilati e possono essere istanziati tramite l'array drivers:
Driver Stringa Tipo Descrizione
MZ700.c MZ700 Sharp MZ-700 commutazione banchi, video, I/O tastiera
MZ80A.c MZ80A Sharp MZ-80A — ROM monitor (SA-1510), VRAM, emulazione Intel 8253 PIT, 8255 PPI, scambio memoria MEMSW/MEMSWR (inclusa commutazione banchi CP/M), supporto modalita’ mista fisica+virtuale e supporto per le sotto-interfacce RFS, MZ80AFI, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18
MZ2000.c MZ2000 Sharp MZ-2000 — commutazione modalita’ memoria BST/NST, overlay VRAM caratteri + grafica, 8253 PIT, 8255 PPI, Z80 PIO, MB8866 FDC. Supporta sia la modalita’ fisica (sostituzione drop-in dello Z80 con rilevamento automatico modalita’ boot/normale) sia la modalita’ virtuale (emulazione completa basata su PSRAM con mirroring della ROM IPL)
MZ2200.c MZ2200 Sharp MZ-2200 — commutazione modalita’ memoria BST/NST, overlay VRAM, 8253 PIT, 8255 PPI, Z80 PIO, MB8866 FDC, CRT a colori
MZ80B.c MZ80B Sharp MZ-80B — ROM IPL 2K, BST/NST, display monocromatico, doppia pagina GRPH, 8253 PIT, 8255 PPI, Z80 PIO
MZ2500.c MZ2500 Sharp MZ-2500 (SuperMZ) — MMU a 8 pagine (64 blocchi), modalita’ compatibilita’ MZ-2000/MZ-80B, YM2203, G-CRTC, MB8876 FDC, palette, controllore interrupt. La modalita’ virtuale supporta software guidato da interrupt tramite handler personalizzati fetchByte/RETI (cicli bus M1 fisici per il clocking del gate array), formato disco nativo D88 con auto-rilevamento sparse/contiguo, soppressione interrupt one-shot durante l’inizializzazione
MZ1500.c MZ1500 Sharp MZ-1500 — superset del MZ-700 con unita’ Quick Disk integrata, PCG, suono stereo PSG (SN76489AN), interfaccia stampante Z80 PIO, 8253 PIT, selezione modalita’ MZ-700/MZ-1500 tramite DIP switch. Sotto-interfacce: RFS, MZ-1E05, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18, MZ-1R23, MZ-1R37, PIO-3034, Celestite
MZ80K.c MZ80K Sharp MZ-80K — ROM monitor SP-1002 (0x0000–0x0FFF), VRAM 2KB (0xD000–0xD7FF), tastiera 8255 PPI / 8253 PIT / LS367 (0xE000–0xE7FF), boot ROM MZ-80FD nativa (0xF000–0xF3FF), scambio memoria MEMSW/MEMSWR per CP/M. Modalita’ fisica + virtuale (il CP/M in modalita’ fisica usa il remap degli accessi Z80 per driver; la modalita’ virtuale e’ richiesta per il CP/M standard). Due percorsi floppy: MZ80FIO nativo (T3444M) — interfaccia MZ-80FD originale, fa il boot e legge tutti i dischi MZ-80K; e MZ80AFI (FDC MZ-80A) — usato per CP/M, fa il boot del CP/M MZ-80K e legge i dischi CP/M MZ-80K all’interno del CP/M (C:/D:). Solo un’interfaccia floppy e’ attiva alla volta; MZ80FIO ha la precedenza se entrambe sono presenti. Sotto-interfacce: RFS, MZ80FIO, MZ80AFI, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18, MZ-1R37, PIO-3034
MZ800.c MZ800 Sharp MZ-800 — driver a doppia modalita’ (compatibilita’ MZ-700 + MZ-800 nativa). Intercetta il registro Display-Mode del GDG (porta 0xCE) per commutare modalita’ al volo: la modalita’ nativa aggiunge grafica 320×200 / 640×200 (piani VRAM 0x8000–0xBFFF), palette a 4/16 colori, I/O GDG mappato su porte (0xCC–0xCF, palette 0xF0), interrupt vettorizzati IM2 tramite la daisy-chain dello Z80-PIO; la modalita’ MZ-700 usa l’8255/8253 mappati in memoria (0xE000–0xE7FF) e la VRAM testo (0xD000). PSG SN76489 (0xF2), FDC WD1773 (0xD8–0xDF), QuickDisk (0xF4–0xF7), porte di banking memoria 0xE0–0xE6. La modalita’ virtuale riproduce un RETI fisico sul bus reale per servire il latch in-service del PIO.
MZ80AFI.c MZ80AFI Interfaccia floppy Sharp MZ-80A — emula il controller floppy disk AFI del MZ-80A
MZ80FIO.c MZ80FIO Interfaccia floppy Sharp MZ-80FD/MZ-80FIO (MZ-80K) — boot ROM FDIF a 0xF000–0xF3FF, porte T3444M 0xF8–0xFB, fino a 4 unita’, cambio disco a runtime
T3444M.c (usato da MZ80FIO) FDC Toshiba T3444M/T3444A — floppy nativo MZ-80K. DSK esteso CPC, 35 tracce, 2 testine, 16 settori/traccia, settori FM da 128 byte; parser DSK Track-Info robusto; 4 immagini di unita’ simultanee
WD1773.c WD1773 FDC WD1773 — 80 tracce, 2 testine, 8 settori, immagini DSK/RAW/D88
QDDrive.c QDDRIVE Unita’ Sharp QuickDisk — emulazione completa Z80 SIO/2 con dati a traccia spirale, controllo motore e I/O asincrono da scheda SD
RFS.c RFS ROM Filing System — caricamento MZF, CP/M, BASIC da scheda SD
TZFS.c TZFS TranZPUter Filing System — monitor multi-bank + file system CP/M funzionante, selezionabile sulla persona MZ-700. Modalita’ di memoria tranZPUter via porta 0x60, processore di servizio virtuale K64F via OUT (0x68), I/O settori CP/M tramite l’ESP32. ROM roms/tzfs.bin da TZFS/asm/tzfs.asm
MZ-1E05.c MZ1E05 Unita’ interfaccia floppy disk Sharp MZ-1E05 (basata su WD1773)
MZ8BFI.c MZ8BFI / E0054PA Interfaccia floppy disk MZ-2000 — FDC MB8866 senza ROM driver (codice nell’IPL). Supporto formato D88.
MZ-1E14.c MZ1E14 Controller QuickDisk MZ-1E14 con BIOS ROM (MZ-700/MZ-800)
MZ-1E19.c MZ1E19 Controller QuickDisk MZ-1E19 senza BIOS ROM
MZ-1R12.c MZ1R12 Scheda RAM 32KB con batteria tampone (persistente su scheda SD)
MZ-1R18.c MZ1R18 Scheda di espansione RAM 64KB
MZ-1R23.c MZ1R23 ROM Kanji MZ-1R23 128KB (pattern JIS 16×16) e ROM Dizionario MZ-1R24 256KB. File ROM caricati dalla scheda SD. Porte I/O B8h–B9h con lettura auto-incrementante
MZ-1R37.c MZ1R37 EMM (Expanded Memory Manager) MZ-1R37 640KB — spazio di indirizzamento a 20 bit con latching indirizzo tramite porta I/O
PIO-3034.c PIO3034 EMM IO DATA PIO-3034 320KB — contatore di indirizzi a 19 bit con porta dati auto-incrementante
Celestite.c Celestite Scheda composita Celestite — controller Ethernet Wiznet W5100 (emulazione registri), controllore interrupt, UFM, RAM CMOS MZ-1R12 32KB integrata (espandibile a 64KB), EMM MZ-1R37 640KB opzionale. Porte I/O 60h–6Fh. Il parametro ip nell’array JSON param configura l’indirizzo del file server netfs.py (ad es. "192.168.1.210:6800"). Fase 2: networking TCP/IP reale tramite bridge ESP32 — comandi socket W5100 inoltrati all’ESP32 per operazioni BSD socket effettive. IPC inter-core per NET_CFG, NET_SOCK, NET_SEND, NET_RECV, NET_PING
MZ8BIO3.c MZ-8BIO3 Scheda seriale RS-232C (connettore BI), Z80 SIO emulato alle porte 0xB0–0xB3 (base configurabile). Canali A/B collegati alle porte seriali USB CDC 2 e 3. Nessuna ROM.
MZ1E24.c MZ-1E24 Scheda seriale RS-232C (connettore Sharp ST); come MZ-8BIO3 ma con cablaggio del connettore diverso.
Z80SIO.c (usato da MZ-8BIO3 / MZ-1E24) Zilog Z80 SIO/2 register-accurate: WR0–WR7, RR0–RR2, interrupt vettorizzati Z80 mode-2, daisy-chain in-service a 4 livelli, status-affects-vector. Ring SPSC lock-free collegano il core Z80 (core 1) e il servizio USB CDC (core 0).
SASI.c + MZ1E30.c MZ-1E30 Controller hard disk SASI MZ-1E30 — emula il controller hard disk SASI (Shugart Associates System Interface) Sharp MZ-1E30 per MZ-2500/MZ-80B. Fino a 4 target disco (~21,4 MB ciascuno, blocchi da 256 byte), ROM IPL 32KB (acceduta via I/O tramite porte 0xA8–0xA9), I/O settori on-demand da immagini disco su scheda SD. Comandi SASI: TEST_UNIT_READY, REQUEST_SENSE, READ(6), WRITE(6), SEEK(6), INQUIRY. Porte I/O 0xA4–0xA5 (dati/controllo SASI)
PIT8253.c PIT8253 Emulazione standalone Intel 8253 PIT — tutte e sei le modalita’ contatore, BCD/binario, latch, lettura/caricamento LSB/MSB
PPI8255.c PPI8255 Emulazione standalone Intel 8255 PPI — I/O Modo 0, set/reset bit, callback di output, iniezione di input
Serie Amstrad PCW (INCLUDE_AMSTRAD_DRIVERS)
Quando il firmware viene compilato con INCLUDE_AMSTRAD_DRIVERS, i seguenti moduli driver vengono compilati:
Driver Stringa Tipo Descrizione
PCW9512.c PCW9512 Amstrad PCW-9512 — Z80A @ 4MHz, 512KB RAM con commutazione a 4 banchi di pagine da 16KB (porte F0–F3), gate array (ASIC) per routing video/clock di sistema/FDC/controllo motore (porta F8), controller stampante daisy wheel 8041 (porte FC–FD), emulazione sequenza bootstrap. Modalita’ virtuale e fisica supportate
uPD765.c Emulazione FDC NEC uPD765 — supporto formato CPC DSK (porte 00–01). Comandi gate array: fine bootstrap, riavvio, routing INT FDC (NMI/INT/ignora), conteggio terminale, motore on/off. Imaging disco fisico tramite codice Z80 iniettato. Modulo FDC riutilizzabile (analogo a WD1773.c per Sharp)
Serie Tatung Einstein (INCLUDE_TATUNG_DRIVERS)
Quando il firmware viene compilato con INCLUDE_TATUNG_DRIVERS, i seguenti moduli driver vengono compilati:
Driver Stringa Tipo Descrizione
EinsteinTC01.c EinsteinTC01 Tatung Einstein TC-01 — Z80A @ 4MHz, 64KB RAM + 8KB ROM commutabile (X-TAL MOS), commutazione ROM/RAM tramite porta 0x24, VDP TMS9129 con applicazione temporizzazione inter-accesso (~2us di intervallo), PSG AY-3-8910 (porte 0x02-0x03), Z80 CTC (porte 0x28-0x2B), Z80 PIO (porte 0x30-0x33), interfaccia tastiera (porta 0x20). Modalita’ virtuale e fisica supportate
EinsteinFDC.c Sotto-interfaccia FDC Einstein — 2 unita’, supporto formato DSK/D88. Imaging disco fisico: lettura floppy fisico verso DSK, scrittura DSK verso floppy fisico
WD1770.c Emulazione FDC WD1770 — supporto formato Extended CPC DSK, D88 e DSK standard. 40 tracce, 1 testina, 10 settori, 512 byte (dischi da 200KB). Modulo FDC riutilizzabile per macchine basate su WD1770 (separato da WD1773.c utilizzato da Sharp)

TZFS — Modello Monitor + CP/M (persona MZ-700)
TZFS.c implementa un monitor a basso livello multi-bank e file system funzionante — un insieme di miglioramenti rispetto al MONITOR 1Z-013A originale (accesso SD, ROM banking, un assembler / disassembler e strumenti) — modellato sul TZFS del tranZPUter SW e sul suo processore I/O virtuale K64F. E' offerto come interfaccia selezionabile solo sulla persona MZ-700 (registrato in MZ700.c insieme a RFS, e in pratica mutuamente esclusivo con esso), non come persona di primo livello. Il CP/M viene eseguito sotto il monitor.
Emulazione delle modalita' di memoria (porta 0x60)
La scrittura di una modalita' di memoria tranZPUter sulla porta I/O 0x60 ri-punta i puntatori di bank. Le modalita' sono TZMM_ORIG, TZMM_BOOT, TZMM_TZFS, TZMM_TZFS2, TZMM_TZFS3, TZMM_TZFS4, TZMM_CPM, TZMM_CPM2 e TZMM_COMPAT. Il layout CP/M CPM2 usa un paging del blocco 0 a granularita' di byte — 0x00000x003F mappano il blocco dei vettori e 0x00400x01FF l'inizio della TPA.
Processore di servizio virtuale K64F (porta 0x68)
Lo Z80 richiede i servizi eseguendo OUT (0x68), che accoda un messaggio MSG_TZFS_SVCREQ al Core 0; il Core 0 esegue TZFS_processServiceRequest. I servizi di file system sono READDIR / NEXTDIR (blocchi directory a 16 voci in cache), READFILE / NEXTREADFILE, LOADFILE (consapevole dell'header MZF e degli oggetti bank), CHANGEDIR e CLOSE. I servizi CP/M sono LOADBDOS (ricaricamento CCP + BDOS al warm-boot), ADDSDDRIVE, READSDDRIVE e WRITESDDRIVE, piu' i servizi di frequenza CPU. Poiche' picoZ80 non ha accesso diretto alla SD, i settori CP/M da 512 byte vengono letti e scritti attraverso l'ESP32 (ESP_readSector / ESP_writeSector) su file immagine interi; i percorsi immagine per drive provengono dalle voci param[].file del JSON dell'interfaccia, con template di fallback CPM/SDC16M/RAW/CPMDSK<nn>.RAW. La ROM TZFS e' roms/tzfs.bin sulla scheda SD, assemblata da TZFS/asm/tzfs.asm (il suo BIOS CP/M da TZFS/asm/cbios.asm / cpm22.asm). Viene fornita in config_MZ-700_MZ-700.json con "enable": 0 ed e' attivata nel JSON o dalla pagina Configurazione della GUI web.

OpenZ80 — Persona Sperimentale (INCLUDE_OPEN_DRIVERS)
Il target OpenZ80 (TARGET_MODEL_OPENINCLUDE_OPEN_DRIVERS) compila una persona Z80 "vanilla" deliberatamente essenziale per gli sperimentatori che inseriscono il picoZ80 in una scheda di propria progettazione o in una macchina priva di un driver dedicato. In modalita' PHYSICAL l'intero spazio di memoria e I/O da 64K passa attraverso alla scheda reale (le schede di interfaccia sovrappongono le loro porte I/O); in modalita' VIRTUAL presenta una RAM piatta da 64K in cui le immagini ROM a livello di driver vengono caricate in sequenza a partire da 0x0000. Non contiene alcun hardware macchina e riutilizza i moduli delle schede di interfaccia Sharp verbatim (non contengono stato specifico della persona), esponendo solo le schede indipendenti dalla macchina elencate di seguito — ognuna delle quali supporta la riposizionamento della porta I/O base.
Driver Stringa Tipo Descrizione
Open.c Open Persona Z80 vanilla / sperimentale — nessun hardware macchina. Passthrough fisico o RAM virtuale piatta da 64K con caricamento ROM a livello di driver da 0x0000
MZ-1R12.c MZ1R12 Scheda RAM-file MZ-1R12 da 32K (base predefinita 0xF8, riposizionabile)
MZ-1R18.c MZ1R18 Scheda RAM MZ-1R18 da 64K (base predefinita 0xEA, riposizionabile)
MZ-1R23.c MZ1R23 Scheda ROM Kanji MZ-1R23 / dizionario MZ-1R24 (base predefinita 0xB8, riposizionabile)
MZ-1R37.c MZ1R37 EMM MZ-1R37 da 640K (base predefinita 0xAC, riposizionabile)
PIO-3034.c PIO3034 EMM parallelo / I/O parallelo PIO-3034 (base predefinita 0x00, riposizionabile)
MZ8BIO3.c / MZ1E24.c MZ8BIO3 / MZ1E24 Doppie schede seriali RS-232C (Z80 SIO, base predefinita 0xB0, riposizionabile; canali A/B su USB CDC 2/3)
MZ-1E05.c MZ1E05 Interfaccia floppy WD1773 (base predefinita 0xD8, riposizionabile; richiede una boot ROM FDC)
Celestite.c Celestite Scheda LAN ESP32 Celestite (base predefinita 0x60, riposizionabile)
Compilare con build_tzpuPico.sh open. Per adattare il picoZ80 a una nuova macchina, prendere come base uno dei driver di persona in src/drivers/{Sharp,Amstrad,Tatung,Other}/ e abbinarlo al sorgente della ROM monitor / IPL / BIOS CP/M / boot floppy corrispondente nelle directory asm/ dei progetti RFS e TZFS (ad es. RFS/asm/sa1510.asm, RFS/asm/cbios.asm, TZFS/asm/mz2000_ipl.asm, RFS/asm/mz80afi.asm). Consultare la Guida dello Sviluppatore per la procedura passo per passo.

Framework Dispositivi Virtuali

Il tipo di blocco FUNC abilita l'emulazione arbitraria di I/O chiamando funzioni handler C su ogni accesso al bus. Qualsiasi blocco di 512 byte di memoria o intervallo di porte I/O puo' essere supportato da una funzione.

Firme delle Funzioni Handler

Gli handler FUNC di memoria sono memorizzati nella tabella memioPtr nella PSRAM. Gli handler FUNC I/O sono memorizzati nella tabella ioPtr. Le firme delle funzioni sono:
/* Memory read handler */
uint8_t mem_read_handler(uint16_t addr, void *ctx);

/* Memory write handler */
void mem_write_handler(uint16_t addr, uint8_t data, void *ctx);

/* I/O read handler */
uint8_t io_read_handler(uint8_t port, void *ctx);

/* I/O write handler */
void io_write_handler(uint8_t port, uint8_t data, void *ctx);
Le funzioni handler vengono chiamate direttamente dall'hot loop del Core 1. Devono completarsi prima che i wait state del ciclo bus corrente scadano — mantenere gli handler brevi ed evitare qualsiasi operazione bloccante (I/O file, UART, ecc.). Se un handler deve attivare un'operazione piu' lunga (ad es. caricare un settore del disco), deve inviare un messaggio al Core 0 tramite la coda inter-core e ritornare immediatamente con un byte di stato, delegando l'I/O effettivo al Core 0.

Scrivere un Nuovo Driver

Per aggiungere il supporto per una nuova periferica o macchina host:
  1. Creare un nuovo file .c / .h nella directory src/drivers/.
  2. Implementare le funzioni handler di lettura e scrittura corrispondenti alle firme sopra indicate.
  3. Registrare i puntatori alle funzioni handler nelle tabelle memioPtr o ioPtr durante l'inizializzazione del driver.
  4. Aggiungere il driver al target di compilazione CMakeLists.txt.
  5. Aggiungere una voce di stringa tipo in modo che il parser della configurazione JSON possa istanziare il driver per nome.
  6. Documentare le chiavi param del driver nel file header del driver.
La funzione di inizializzazione del driver viene chiamata una volta all'avvio, dopo che config.json e' stato analizzato. Il driver riceve un puntatore al suo blocco di configurazione dell'interfaccia e deve configurare qualsiasi stato interno e registrare i suoi handler in questo momento.

ICE (Shell di Debug)

Il picoZ80 include una shell di debug ICE (In-Circuit Emulator) integrata sul Canale 1 USB CDC (la seconda porta seriale enumerata quando la scheda e' collegata via USB). La shell viene eseguita sul Core 0 e comunica con il loop di emulazione del Core 1 tramite flag condivisi nella struttura di contesto Z80CPU. La shell di debug e' disponibile solo nella variante firmware DBGSH, compilata con la define INCLUDE_DBGSH.

Canali Seriali USB CDC

Il picoZ80 enumera diverse porte seriali USB CDC quando e' collegato a un host. CDC 0 e CDC 1 servono le UART fisiche / il bridge ESP32 e la shell di debug ICE (CDC 1, varianti DBGSH). CDC 2 e CDC 3 sono i due canali (A e B) di una scheda seriale RS-232C virtuale — il driver MZ-8BIO3 o MZ-1E24 — quando ne e' configurata una nel config.json. Queste due porte non hanno alcuna UART fisica dietro di se': sono bridge a ring buffer verso lo Z80 SIO emulato, cosi' che i dati scritti su CDC 2/3 sull'host appaiano sul canale A/B dello Z80 SIO visto dal guest, e viceversa. Se nessuna scheda seriale e' configurata, CDC 2 e CDC 3 non vengono enumerate.

Architettura

  • Input/Output: Canale 1 USB CDC a 115200 baud. Il prompt della shell e' dbg> . Sono supportati la cronologia dei comandi (16 voci) e l'echo dei caratteri.
  • Breakpoint: Fino a 8 breakpoint simultanei memorizzati in cpu->dbgBpAddr[]. Il Core 1 controlla l'array dei breakpoint prima di ogni fetch dell'opcode; su una corrispondenza, imposta cpu->hold = true e segnala il Core 0 tramite dbgBpHit.
  • Single-step: Il comando step imposta cpu->dbgStepCount. Il Core 1 decrementa questo contatore dopo ogni istruzione, fermandosi automaticamente quando raggiunge lo zero. Lo stato dei registri prima/dopo e l'istruzione disassemblata vengono visualizzati per ogni passo.
  • Trace di esecuzione: Un buffer circolare a 512 voci (cpu->dbgTrace[]) registra PC, opcode e registro flag per ogni istruzione eseguita quando il tracing e' abilitato. Ogni voce a 32 bit impacchetta [31:16]=PC, [15:8]=opcode, [7:0]=registro F.
  • Accesso alla memoria: L'accesso alla memoria fisica (dm p, wm p) esegue cicli bus Z80 reali tramite le macchine a stati PIO. L'accesso virtuale (dm v, wm v) legge/scrive direttamente nella PSRAM. La modalita' auto (wm senza qualificatore) segue la mappa di memoria. L'accesso RP2350 (dm r) legge lo spazio di indirizzamento del microcontrollore host con validazione dell'intervallo.
  • Hold/Release: Il comando hold imposta cpu->hold = true. Il Core 1 conferma tramite cpu->holdAck, garantendo che la CPU sia quiescente prima che la shell acceda allo stato condiviso.
  • Break: Il comando break mette in hold il Core 1 e poi riporta il PC corrente, l'istruzione in procinto di essere eseguita (disassemblata) e l'intero set di registri — il modo piu' rapido per vedere dove si trova un programma in esecuzione, prima di eseguire lo step o l'ispezione. go/cont riprende.
  • Tasti rapidi e abbreviazioni: Per ridurre la digitazione durante il debug, i comandi piu' comuni hanno tasti rapidi a lettera singola — c=cont, s=step, g=go, b=break, r=regs, h=hold — che vengono risolti prima della corrispondenza per prefisso, quindi non sono mai trattati come ambigui. Qualsiasi altro comando puo' essere inserito come il suo prefisso univoco piu' corto (ad es. ste=step, sta=status, dis=disassemble); un prefisso ambiguo elenca i candidati, e un nome digitato per intero ha sempre la precedenza.

Riferimento Comandi

Comando Sintassi Descrizione
help help Elenca tutti i comandi
regs regs Dump di tutti i registri Z80, flag e conteggio cicli
dm dm <p|f|v|r> <addr> [len] Dump memoria (fisica / fetch / virtuale / RP2350)
search search [p|v] <start> <end> <hex..>|"text" Cerca nella memoria un pattern di byte o una stringa di testo ASCII. p = bus fisico, v = PSRAM virtuale, omettere per mappato. Le corrispondenze vengono visualizzate con 8 byte di contesto. Arresta automaticamente la CPU per l’accesso fisico/mappato. Pattern fino a 32 byte
cmp cmp [f] <phys> <virt> <len> Confronta la memoria del bus fisico con la PSRAM virtuale
dis dis [p|v] [addr] [count] Disassembla codice Z80
asm asm [addr] Assemblatore Z80 interattivo
memmap memmap [block] Mostra la tabella dei puntatori dei banchi di memoria
memptr memptr [addr] Mostra la tabella memPtr della PSRAM
iomap iomap [port] Mostra la tabella degli handler delle porte I/O
status status Stato del sistema (frequenza CPU, PSRAM, uptime)
ver ver Versione firmware e informazioni sulla partizione
drivers drivers Elenca i driver e le interfacce attive
hold hold Mette in pausa l’emulazione della CPU
release release Riprende l’emulazione della CPU
break break Arresta lo Z80 in esecuzione e riporta dove si e’ fermato — PC, l’istruzione (byte + disassemblaggio) in procinto di essere eseguita e un dump completo dei registri. A differenza di hold (che mette in pausa silenziosamente), break mostra lo stato in modo da poter vedere esattamente dove si trova l’esecuzione (ad es. quando bloccato in un loop). Riemettere break rimostra lo stato. Riprendere con go/cont o eseguire il single-step con step. Va in timeout (~3 s) se lo Z80 e’ tenuto in reset o il suo clock e’ disattivato
go go Continua (rilascia hold, breakpoint attivi)
cont cont Alias per go. Continua l’esecuzione (rilascia hold, breakpoint attivi)
step step [n] Single-step di n istruzioni
bp bp <addr> Imposta un breakpoint (max 8)
bc bc <n|*> Cancella il breakpoint n o tutti
bl bl Elenca i breakpoint
wm wm [p|v] <addr> <byte>... Scrive in memoria (fisica/virtuale/auto)
fill fill [p|v] <addr> <len> [w|d] <val> Riempie la memoria con un valore costante
copy copy <pv|fp|vp> <src> <len> <dst> Copia memoria tra fisica e virtuale
memtest memtest <addr> <len> [pattern] Testa la memoria fisica (scrittura+lettura, scrittura+fetch, interlacciato)
in in <port> Legge una porta I/O Z80
out out <port> <byte> Scrive su una porta I/O Z80
trace trace <on|off|dump [n]|clear|rt|byte ...> Controllo trace di esecuzione; rt abilita l’output trace in tempo reale; byte abilita il tracing a livello di byte
verify verify <on|off> Attiva/disattiva la verifica completa del fetch degli opcode
fwait fwait <0-4> Forza wait state aggiuntivi per M1 (fetch opcode); 0 = disattivato (predefinito)
iowait iowait <0-8> Forza wait state aggiuntivi per cicli I/O; 0 = disattivato (predefinito)
corrupt corrupt [clear] Visualizza o cancella le corruzioni di fetch rilevate
fdctrace fdctrace <on|off|dump> Abilita/disabilita il trace I/O FDC; dump mostra le ultime 64 operazioni
qdtrace qdtrace <on|off|dump> Abilita/disabilita il trace I/O Quick Disk; dump mostra le ultime 64 operazioni
piodbg piodbg [clear] Visualizza la diagnostica hardware PIO dell’RP2350 (FDEBUG, FSTAT, FIFO, PC, GPIO); clear resetta i flag persistenti
load load <p|v> <file> <addr> [len] [ofs] Carica un file dalla scheda SD dell’ESP32 nella memoria Z80. p = bus fisico, v = banco 0 PSRAM virtuale. file relativo a /sdcard/. Se len e’ omesso viene caricato l’intero file (fino a 64KB); se specificato, max 1MB. ofs opzionale per offset nel file. Arresta automaticamente la CPU per le scritture fisiche. Utilizza il banco PSRAM 63 come buffer temporaneo
save save <p|pf|v> <file> <addr> <len> Salva la memoria Z80 in un file sulla scheda SD dell’ESP32. p = bus fisico, pf = fetch fisico (M1), v = banco 0 PSRAM virtuale. file relativo a /sdcard/. Max 64KB. Arresta automaticamente la CPU per le letture fisiche. Refresh DRAM periodico durante le letture fisiche
dir dir [path] Elenca i file sulla scheda SD dell’ESP32. Il percorso opzionale e’ relativo a /sdcard/. Mostra nomi file e dimensioni
echo echo [on|off] Attiva/disattiva l’echo del terminale
reset reset Forza il reset dello Z80
set set <reg|flags|memmap|memptr|iomap> <idx> <val> Modifica registro Z80, flag, mappa memoria, memPtr o voce mappa I/O a runtime
hist hist [n] Visualizza la cronologia dei comandi (preservata tra le sessioni tramite NVS dell’ESP32)
savehst savehst Forza il salvataggio della cronologia dei comandi nel NVS dell’ESP32
ipl ipl Esegue un reset IPL (modalita’ BST) commutando il bit 3 della Porta C del PPI 8255. Resetta alla modalita’ boot senza un reset Z80 completo
mmutrace mmutrace Dump delle informazioni di trace specifiche della macchina (stato MMU, snapshot dei registri I/O). L’output varia per persona tramite l’handler di trace registrato
intcount intcount Mostra il conteggio degli acknowledge degli interrupt e lo stato corrente degli interrupt
psync psync [start end] Sincronizza la memoria fisica con la PSRAM. Intervallo di indirizzi opzionale; predefinito sull’intero spazio di indirizzamento
dskimage dskimage read <filename> [cylinders] [heads] / dskimage write <filename> Crea un’immagine di un floppy fisico in un file DSK sulla scheda SD (read), o scrive un file DSK dalla scheda SD su un floppy fisico (write). dskimage <filename> predefinito a lettura (compatibilita’ all’indietro). Rileva automaticamente la geometria se omessa
busdiag busdiag Visualizza la diagnostica del bus (stato PIO, livelli dei segnali, contesa del bus)
fdcimage fdcimage Visualizza lo stato e il progresso dell’imaging FDC
fdcdiag fdcdiag Visualizza le informazioni diagnostiche del FDC (stato del controller, dump dei registri)
gadiag gadiag Visualizza le informazioni diagnostiche del gate array (stato dei comandi, routing degli interrupt)
Tasti rapidi e abbreviazioni. I comandi non devono essere digitati per intero. I sei comandi piu' usati hanno tasti rapidi a lettera singola — c (cont), s (step), g (go), b (break), r (regs) e h (hold) — e ogni altro comando puo' essere inserito come il suo prefisso univoco piu' corto (ad esempio ste per step, sta per status, dis per disassemble). Un nome di comando digitato per intero ha sempre la precedenza, e un prefisso ambiguo stampa l'elenco dei comandi corrispondenti.

Coprocessore ESP32

Il modulo ESP32-S3-PICO-1 funge da coprocessore gestendo tutte le funzioni di rete e archiviazione. Comunica con l'RP2350 tramite due interfacce:
  • FSPI (50MHz, SPI a 4 fili) — Protocollo IPC Binario v1.1 — trasferimento dati bulk ad alta velocita' (immagini ROM, letture/scritture settori disco, download file di configurazione). Il protocollo utilizza un header di frame binario fisso da 64 byte con verifica di integrita' CRC32 (in sostituzione del precedente checksum XOR). I canali DMA sono pre-allocati all'inizializzazione e mai rilasciati, eliminando l'overhead di claim/unclaim per trasferimento e le condizioni di gara. I trasferimenti burst di settori permettono fino a 16 × 512 byte settori (8KB) in una singola transazione SPI, migliorando significativamente i tempi di caricamento delle immagini floppy e QuickDisk. Il canale DMA RX e' elevato a PRIORITA' ALTA per prevenire l'overflow del FIFO causato dalla contesa del bus QMI PSRAM del Core 1.
  • UART (460,8kbaud) — protocollo comando/risposta per messaggi di controllo, query di stato e brevi scambi di dati.

Modalita' di Rete

Il firmware dell'ESP32 supporta tre modalita' di rete, selezionate a tempo di compilazione tramite file sdkconfig pre-costruiti:
Modalita’ File di Configurazione WiFi USB NCM Console FCC/RED Richiesto
Solo WiFi sdkconfig.mode_wifi_only Si’ No USB Serial/JTAG Si’
WiFi + NCM sdkconfig.mode_wifi_and_ncm Si’ Si’ TinyUSB CDC-ACM Si’
Solo NCM sdkconfig.mode_ncm_only No Si’ TinyUSB CDC-ACM No
USB NCM (Network Control Model) presenta un adattatore Ethernet CDC-NCM sulla porta USB OTG dell'ESP32-S3 (GPIO 19/20). Un dispositivo USB composito espone sia una porta seriale CDC-ACM (per il logging di debug) che l'interfaccia di rete NCM. Il server DHCP integrato assegna all'host un indirizzo IP dalla sottorete 192.168.7.0/24, con il picoZ80 accessibile a 192.168.7.1. Il tempo di lease e' di 120 minuti.
In modalita' WiFi+NCM, il server HTTP si collega a INADDR_ANY:80 e serve entrambe le interfacce simultaneamente. Il WiFi si connette in modo asincrono cosi' l'interfaccia USB NCM e' disponibile immediatamente all'accensione.
Quando e' abilitato solo NCM, la radio WiFi e' completamente disabilitata, la pagina WiFi Manager viene rimossa dall'interfaccia web e il titolo del pannello di stato della Dashboard cambia da "WiFi Configuration" a "Network Configuration" (mostrando lo stato USB NCM invece dei dettagli SSID/WiFi). La rete di adattamento dell'antenna dell'ESP32-S3 non deve essere popolata sulla PCB.

Interfaccia Scheda SD

L'ESP32 gestisce la scheda SD tramite la sua interfaccia SPI. La scheda SD viene montata come FAT32 e tutto l'accesso ai file dall'RP2350 e' mediato dall'ESP32 — l'RP2350 invia comandi di I/O file tramite il collegamento FSPI/UART e l'ESP32 esegue le operazioni effettive di lettura/scrittura FAT32.
La scheda SD e' anche direttamente accessibile al web server dell'ESP32, che serve i file dalla directory webfs/ e permette al File Manager di navigare e modificare i contenuti della scheda tramite HTTP.

Web Server

L'ESP32 esegue un server HTTP sulla porta 80 (nessun TLS — solo per uso su rete locale). Tutte le risorse web (HTML, CSS, JavaScript) vengono servite dalla directory webfs/ sulla scheda SD, permettendo di aggiornare l'interfaccia web senza riflashare il firmware dell'ESP32. Il web server gestisce:
  • Servizio di risorse web statiche dalla directory webfs/ della scheda SD.
  • Endpoint API REST per dati JSON (stato del sistema, lettura/scrittura configurazione, operazioni sui file).
  • Endpoint di upload firmware OTA sia per l'RP2350 che per l'ESP32.
  • Connessione WebSocket per aggiornamenti di stato della Dashboard in tempo reale.

Protocollo di Comando RP2350 ↔ ESP32

L'RP2350 (Core 0) comunica con l'ESP32 utilizzando un semplice protocollo comando/risposta sul collegamento UART. I comandi sono opcode a singolo byte con byte di payload opzionali. L'ESP32 conferma ogni comando con un byte di stato seguito da eventuali dati di risposta.
Categorie di comandi comuni:
  • I/O File — apertura, lettura, scrittura, chiusura, elenco directory, stat file.
  • Configurazione — richiesta contenuto config.json, scrittura configurazione aggiornata, richiesta di ricaricamento.
  • Disco — mount/unmount immagine disco, lettura/scrittura settore (inoltrato dall'emulazione WD1773 e QDDrive). I nomi file delle immagini floppy e QuickDisk attualmente montate vengono tracciati dall'ESP32 e visualizzati nel menu Actions dell'interfaccia web.
  • Sistema — query versione, richiesta di riavvio, lettura/scrittura NVS.
L'interfaccia FSPI viene utilizzata per i trasferimenti bulk dove il payload e' troppo grande per la UART (upload di immagini ROM, dati di settori disco), mentre la UART gestisce tutti i comandi di controllo.

Comandi IPC di Rete

L'implementazione del networking Celestite Fase 2 aggiunge cinque comandi IPC inter-core che l'RP2350 utilizza per richiedere operazioni di rete dall'ESP32. Questi comandi vengono inoltrati tramite il collegamento FSPI/UART e l'ESP32 esegue le corrispondenti operazioni BSD socket. Le connessioni non bloccanti utilizzano select() con un timeout, e flag pending per socket tracciano le operazioni in corso.
Comando Opcode Descrizione
IPCF_CMD_NET_CFG 0x10 Ottieni la configurazione di rete dell’ESP32 — restituisce indirizzo IP, gateway, maschera di sottorete e indirizzo MAC
IPCF_CMD_NET_SOCK 0x11 Operazione ciclo di vita socket — apertura, connessione, ascolto, chiusura o disconnessione di un socket
IPCF_CMD_NET_SEND 0x12 Invia dati a un socket aperto
IPCF_CMD_NET_RECV 0x13 Ricevi dati da un socket aperto
IPCF_CMD_NET_PING 0x14 Richiesta ICMP echo (ping)
I comandi socket W5100 supportati tramite questo livello IPC sono: OPEN, CONNECT, LISTEN, SEND, RECV, CLOSE e DISCON. L'ESP32 li traduce in chiamate API BSD socket standard (socket(), connect(), listen(), send(), recv(), close(), shutdown()), permettendo alla scheda Celestite di comunicare con servizi di rete come il file server netfs.py.

Watchdog e Diagnostica di Avvio

Il firmware dell'RP2350 utilizza un timer watchdog hardware per rilevare e recuperare da blocchi durante l'avvio e stalli del loop principale. Il watchdog viene abilitato nella fase iniziale della sequenza di avvio con un timeout di 30 secondi e viene rinnovato (watchdog_update()) ad ogni milestone importante. Se qualsiasi fase di avvio o iterazione del loop principale impiega piu' tempo del timeout, il watchdog resetta l'RP2350 automaticamente.

Tracciamento del Progresso di Avvio

Il progresso dell'avvio viene tracciato utilizzando i registri scratch del watchdog dell'RP2350, che sopravvivono ai reset del watchdog (ma non ai reset all'accensione). Questo permette al firmware di determinare, dopo un reset del watchdog, esattamente quale fase di avvio era stata raggiunta prima del blocco.
Registro Scratch Nome Contenuti
scratch[0–3] Cronologia avvio Ultimi quattro tentativi di reset — ogni voce codifica (attempt_count << 24) | (stage << 16) | (resetCause & 0xFFFF). Le voci si spostano ad ogni reset del watchdog: [0]←[1]←[2]←[3]←corrente.
scratch[4] Diagnostica SPI Contatori diagnostici impacchettati per il collegamento FSPI: breadcrumb, tipo di messaggio, contatori timeout T1/T3, conteggio frame errati e conteggio OK.
scratch[5] Marcatore magico Impostato a 0xB00710BE per indicare che i registri scratch contengono dati validi di progresso dell’avvio.
scratch[6] Fase corrente Il codice della fase di avvio piu’ recente (vedi tabella sotto).
scratch[7] Causa del reset Il codice della causa del reset dal controller hardware di reset.
I codici delle fasi di avvio progrediscono da 0x01 (avvio) fino a 0x10 (ingresso nel loop principale). Le sotto-fasi all'interno del loop principale (0x11–0x17) e l'elaborazione dei comandi inter-core (0x20–0x27) forniscono un tracciamento a grana fine:
Codice Fase Descrizione
0x01 BOOTP_START Punto di ingresso raggiunto
0x02 BOOTP_CLK_SET Clock di sistema configurato
0x03 BOOTP_PSRAM_INIT Inizializzazione PSRAM avviata
0x04 BOOTP_PSRAM_OK PSRAM inizializzata con successo
0x05 BOOTP_STDIO_INIT USB stdio inizializzato
0x06 BOOTP_PIO_INIT Macchine a stati PIO caricate
0x07 BOOTP_Z80_INIT Contesto CPU Z80 inizializzato
0x08 BOOTP_USB_INIT Bridge USB inizializzato
0x0A BOOTP_ESP_HS_SYNC Sincronizzazione handshake SPI ESP32
0x0B BOOTP_CORE1_LAUNCH Core 1 avviato
0x0D BOOTP_FSPI_INIT IPC binario FSPI inizializzato
0x0E BOOTP_ESP_INIT Comunicazione ESP32 pronta
0x10 BOOTP_MAIN_LOOP Ingresso nel loop principale
0x11–0x17 Sotto-fasi loop principale Poll USB, inter-core, SPI NOP/CMD, task
0x20–0x27 Comandi inter-core Caricamento floppy, caricamento QD, caricamento RAMFILE, I/O file

Log Persistente PSRAM (plogf)

Gli ultimi 4KB della PSRAM da 8MB (indirizzo 0x117FF000) sono riservati per un log di debug persistente che sopravvive ai reset del watchdog. La macro plogf() scrive messaggi in stile printf in questo buffer durante l'avvio, prima che l'USB sia disponibile per il normale output debugf(). Al successivo avvio riuscito, la funzione dump_plog() emette i messaggi catturati sulla console di debug e poi cancella il buffer. Il log utilizza una struttura semplice: un marcatore magico di 4 byte (0x504C4F47 = "PLOG"), un contatore di lunghezza di 4 byte e un buffer di testo circolare di 3840 byte.

Diagnostica dei Fault

Il firmware installa handler di fault Cortex-M33 per hard fault, fault di gestione memoria, bus fault e usage fault. Quando si verifica un fault, l'handler salva uno snapshot diagnostico completo negli ultimi 256 byte della PSRAM (indirizzo 0x117FFF00) con un marcatore magico (0xFA017000), il tipo di fault, tutti i registri rilevanti (PC, LR, SP, R0–R3, R12, PSR), il Configurable Fault Status Register (CFSR), l'Hard Fault Status Register (HFSR), il Bus Fault Address Register (BFAR), il Memory Management Fault Address Register (MMFAR) e l'ID del core. L'handler entra quindi in un loop infinito, permettendo al watchdog di attivare un reset. All'avvio successivo, il firmware verifica la presenza di una diagnostica di fault valida e emette le informazioni catturate tramite debugf(), abilitando l'analisi post-mortem senza richiedere una sessione di debugger dal vivo.

Cancellazione della Configurazione Flash

Il meccanismo di aggiornamento OTA dell'RP2350 supporta due operazioni aggiuntive oltre al caricamento del firmware:
  • Cancella App Config (FW_CFGCLEAR_ID = 0xB1D7E5FA) — cancella la partizione App Config (immagini ROM e JSON minificato) associata allo slot firmware di destinazione. Questo forza il firmware a rileggere config.json dalla scheda SD al prossimo avvio, che e' necessario quando lo schema di configurazione e' cambiato tra le versioni firmware.
  • Cancella Header Flash (FW_HDRCLEAR_ID = 0xC2E8F6AB) — resetta l'header della partizione flash ai valori di fabbrica. La configurazione del bootloader (partizione 0) viene preservata, ma tutti i metadati delle partizioni applicative vengono ricostruiti da zero. Utilizzare questo quando la tabella delle partizioni e' diventata corrotta o quando si esegue il downgrade a una versione firmware precedente che si aspetta un layout diverso delle partizioni.
Entrambe le operazioni vengono attivate dalle checkbox della pagina web OTA dell'RP2350 e vengono eseguite dal bootloader durante il processo di aggiornamento firmware.

Debug SWD — RP2350

L'RP2350 supporta il debug completo a livello sorgente tramite ARM Serial Wire Debug (SWD). Collegare una sonda compatibile CMSIS-DAP (Raspberry Pi Debug Probe, Black Magic Probe o simile) ai Pin 1 (SWCLK), 2 (SWDIO) e 5 (GND) dell'header di debug.

Configurazione OpenOCD

Il picoZ80 richiede una piccola modifica allo script target OpenOCD standard dell'RP2350 per abilitare il debug SMP con porte GDB separate per core:
sudo cp /usr/local/share/openocd/scripts/target/rp2350.cfg \
        /usr/local/share/openocd/scripts/target/rp2350_tzpu.cfg
Modificare rp2350_tzpu.cfg — trovare la riga target smp all'interno del blocco if {[string compare $_USE_CORE SMP] == 0} e rimuovere il # iniziale:
# Before:
    #target smp $_TARGETNAME_0 $_TARGETNAME_1

# After:
    target smp $_TARGETNAME_0 $_TARGETNAME_1
Questa singola modifica fa si' che OpenOCD registri il Core 0 sulla porta GDB 3333 e il Core 1 sulla porta GDB 3334, permettendo sessioni GDB indipendenti per core. Avviare OpenOCD prima di avviare GDB:
openocd -f interface/cmsis-dap.cfg -f target/rp2350_tzpu.cfg -c "adapter speed 5000"

Configurazione GDB

Aggiungere quanto segue a ~/.gdbinit (con percorsi assoluti corrispondenti alla posizione del proprio progetto) per permettere il caricamento automatico dei file .gdbinit per directory:
set history save on
set history filename ~/.gdb_history
set history size 65536
add-auto-load-safe-path /path/to/project/build/bin/model/BaseZ80/.gdbinit
add-auto-load-safe-path /path/to/project/build/bin/model/Bootloader/.gdbinit
Debug del Bootloader
# Terminal 1 — Core 0 (port 3333)
cd build/bin/model/Bootloader
cp ../../../../.gdbinit.bootloader.3333 .gdbinit
gdb-multiarch Bootloader.elf

# Terminal 2 — Core 1 (port 3334)
cd build/bin/model/Bootloader
cp ../../../../.gdbinit.bootloader.3334 .gdbinit
gdb-multiarch Bootloader.elf
Debug del Firmware Principale
# Terminal 1 — Core 0 (port 3333)
cd build/bin/model/BaseZ80
cp ../../../../.gdbinit.3333 .gdbinit
gdb-multiarch BaseZ80_0x10020000.elf

# Terminal 2 — Core 1 (port 3334)
cd build/bin/model/BaseZ80
cp ../../../../.gdbinit.3334 .gdbinit
gdb-multiarch BaseZ80_0x10020000.elf

# Memory dump (from GDB prompt) — hex + ASCII:
(gdb) xac 0x20000000 64
Il comando GDB xac <address> <count> e' definito nei file .gdbinit.3333 / .gdbinit.3334. Esegue un dump della memoria come output esadecimale e ASCII combinato ed e' utile per ispezionare i contenuti dei banchi PSRAM e lo stato dei dispositivi mappati in memoria.

Debug USB dell'ESP32

Il coprocessore ESP32-S3 dispone di un'interfaccia USB-JTAG integrata — non e' richiesta una sonda di debug esterna. Collegare un cavo USB dal PC host direttamente alla porta USB dell'ESP32 sulla scheda picoZ80.
# Start OpenOCD for ESP32-S3
openocd -f board/esp32s3-builtin.cfg

# In a second terminal — launch Xtensa GDB
xtensa-esp32s3-elf-gdb esp32/build/main.elf
(gdb) target extended-remote :3333
Assicurarsi che l'ELF sia stato compilato dalla stessa revisione sorgente del firmware in esecuzione sul dispositivo, in modo che i simboli e gli indirizzi corrispondano correttamente.

Sistema di Compilazione

Il firmware del picoZ80 utilizza CMake con il Raspberry Pi Pico SDK 2.x. Il sistema di compilazione produce il firmware Bootloader e il firmware Applicazione. L'applicazione viene compilata in quattro varianti — due partizioni (Partizione 1 a 0x10020000, Partizione 2 a 0x10520000) ciascuna in configurazione standard e DBGSH. Le varianti DBGSH aggiungono INCLUDE_DBGSH ai flag di compilazione, abilitando la shell di debug completa sul Canale 1 USB CDC. Il firmware dell'ESP32 viene compilato separatamente utilizzando ESP-IDF v5.4, gestito tramite Docker.
Il modo piu rapido per ottenere un ambiente funzionante e lo script automatizzato setup_picoZ80 (macOS/Linux e Windows), che installa l'SDK e tutte le dipendenze e crea script di build pronti all'uso — consultare il README e la Guida dello Sviluppatore. I target CMake, i flag e i comandi qui sotto documentano la build sottostante che lo script automatizza, per chi preferisce configurarla manualmente.

Target di Compilazione CMake

Target Output Indirizzo Flash Note
Bootloader Bootloader.elf, Bootloader.uf2 0x10000000  
BaseZ80_0x10020000 BaseZ80_0x10020000.elf, .bin 0x10020000 (Slot 1) Standard (senza shell di debug)
BaseZ80_0x10520000 BaseZ80_0x10520000.elf, .bin 0x10520000 (Slot 2) Standard (senza shell di debug)
BaseZ80_DBGSH_0x10020000 BaseZ80_DBGSH_0x10020000.elf, .bin 0x10020000 (Slot 1) DBGSH — include la shell di debug ICE
BaseZ80_DBGSH_0x10520000 BaseZ80_DBGSH_0x10520000.elf, .bin 0x10520000 (Slot 2) DBGSH — include la shell di debug ICE
I modelli SharpZ80, AmstradZ80, TatungZ80 e OpenZ80 seguono lo stesso schema slot / DBGSH, ad es. OpenZ80_0x10020000, OpenZ80_0x10020000_DBGSH, OpenZ80_0x10520000 e OpenZ80_0x10520000_DBGSH (ciascuno emette .elf, .bin, .hex e .map; gli slot applicativi usano .bin semplice, non UF2). Compilare un singolo modello con il filtro build_tzpuPico.sh, ad es. build_tzpuPico.sh open.

Flag di Compilazione CMake Principali

Flag Effetto
INCLUDE_SHARP_DRIVERS Compila tutti i driver periferici Sharp MZ (MZ700, MZ80K, MZ800, MZ80A, MZ80B, MZ2000, MZ2200, MZ2500, MZ1500, WD1773, T3444M, QDDrive, RFS, TZFS, MZ-1E05, MZ80AFI, MZ80FIO, MZ8BFI, MZ8BIO3, MZ1E24, Z80SIO, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18, MZ-1R23, MZ-1R37, PIO-3034, Celestite, MZ-1E30).
INCLUDE_AMSTRAD_DRIVERS Compila i driver periferici Amstrad PCW (PCW9512, uPD765).
INCLUDE_TATUNG_DRIVERS Compila i driver periferici Tatung Einstein (EinsteinTC01, EinsteinFDC, WD1770).
INCLUDE_OPEN_DRIVERS Compila la persona sperimentale OpenZ80 (Open.c) e le schede di interfaccia indipendenti dalla macchina (MZ-1R12/1R18/1R23/1R37, PIO-3034, MZ8BIO3, MZ1E24, Z80SIO, MZ-1E05, WD1773, Celestite).
TARGET_MODEL_TATUNG Imposta Tatung Einstein come modello target esclusivo (utilizzato nella build TatungZ80).
TARGET_MODEL_OPEN Imposta la persona sperimentale OpenZ80 come modello target esclusivo (utilizzato nella build OpenZ80; abilita INCLUDE_OPEN_DRIVERS).
INCLUDE_DBGSH Compila la shell di debug ICE sul Canale 1 USB CDC. Presente solo nelle varianti di build DBGSH.
CMAKE_BUILD_TYPE=Debug Abilita i simboli di debug e disabilita l’ottimizzazione. Necessario per il debug a livello sorgente con GDB.
CMAKE_BUILD_TYPE=Release Ottimizzazione completa (-O3). Utilizzato per il firmware di produzione.

Comandi di Compilazione

# First time: clone and build the SDK
./get_and_build_sdk.sh

# Standard release build (RP2350 only)
./build_tzpuPico.sh

# Debug build
./build_tzpuPico.sh DEBUG

# Full build: RP2350 + ESP32 (ESP32 built via Docker)
./build_tzpuPico.sh ALL

# ESP32 only, using the Docker idf54 alias
cd projects/tzpuPico/esp32
idf54 build
Lo script build_tzpuPico.sh incrementa automaticamente il numero di versione dopo una compilazione riuscita e copia i file di output versionati in fw/uf2/ (UF2 del bootloader) e fw/bin/ (binario applicativo per OTA). L'UF2 del Bootloader viene utilizzato solo per il flashing iniziale tramite mass-storage USB. I binari degli slot applicativi utilizzano il formato binario semplice (non UF2) perche' risiedono a indirizzi flash non standard.

Selezione della Modalita' di Rete ESP32

Per cambiare modalita' di rete, copiare il file di configurazione pre-costruito appropriato come sdkconfig prima della compilazione:
cd esp32/
cp sdkconfig.mode_ncm_only sdkconfig    # NCM only (FCC/RED safe)
# or: cp sdkconfig.mode_wifi_only sdkconfig
# or: cp sdkconfig.mode_wifi_and_ncm sdkconfig
idf.py build
idf.py flash

Siti di Riferimento

Risorsa Link
Pagina progetto picoZ80 /it/picoz80/
picoZ80 User Manual /it/picoz80-usermanual/
Pagina progetto pico6502 /it/pico6502/
Datasheet RP2350 datasheets.raspberrypi.com
Riferimento PIO RP2350 datasheets.raspberrypi.com — Appendix B
Documentazione Pico SDK raspberrypi.github.io/pico-sdk-doxygen
Riferimento Tecnico ESP32-S3 docs.espressif.com
Guida alla Programmazione ESP-IDF docs.espressif.com/esp-idf
Manuale Utente CPU Zilog Z80 zilog.com
Documentazione OpenOCD openocd.org
Anteprima progetto su X (Twitter) engineerswork1

Avviso Normativo sulle Telecomunicazioni Wireless

Questo dispositivo incorpora un modulo wireless ESP32-S3-PICO-1 in grado di trasmettere nella banda ISM a 2,4 GHz, rendendolo un radiatore intenzionale ai sensi delle normative sulle radiofrequenze a livello mondiale (incluso FCC Part 15 Subpart C negli Stati Uniti e la Direttiva sulle Apparecchiature Radio 2014/53/UE nell'Unione Europea) quando e' installato il firmware WiFi.
Configurazione di Fabbrica
Come fornito, la scheda picoZ80 e' flashata con il firmware solo NCM (sdkconfig.mode_ncm_only). In questa configurazione la radio WiFi e' completamente disabilitata e i componenti della rete di adattamento dell'antenna dell'ESP32-S3 non sono popolati sulla PCB. Poiche' non avviene alcuna trasmissione RF, il dispositivo non e' un radiatore intenzionale e non richiede la certificazione FCC, CE/RED o equivalente. Puo' essere venduto, distribuito o regalato senza autorizzazione normativa.
Aggiunta del WiFi
Gli utenti finali possono popolare la rete di adattamento dell'antenna e flashare il firmware abilitato WiFi (sdkconfig.mode_wifi_only o sdkconfig.mode_wifi_and_ncm) per uso personale, sperimentale o educativo. Una volta abilitato il WiFi, il dispositivo diventa un radiatore intenzionale e si applicano le seguenti regole:
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 ai singoli hobbisti 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 con firmware WiFi non devono essere venduti, offerti in vendita, regalati o altrimenti distribuiti a terzi a meno che il prodotto finito non sia stato testato in modo indipendente e abbia ottenuto la propria autorizzazione per l'apparecchiatura (ad es. FCC ID, marcatura CE con valutazione di un Organismo Notificato) nella giurisdizione pertinente.
  • La costruzione di questo progetto con WiFi abilitato per uso personale in quantita' limitate e' generalmente consentita ai sensi delle disposizioni per hobbisti e uso sperimentale (ad es. FCC § 15.23), a condizione che il dispositivo non causi interferenze dannose.
  • La vendita commerciale con WiFi abilitato richiede la certificazione completa FCC/RED (o equivalente) a livello di prodotto.
  • I requisiti normativi variano per 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' esclusiva responsabilita' del costruttore assicurarsi che qualsiasi dispositivo realizzato a partire 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 a partire da essi soddisfi i requisiti normativi per la distribuzione commerciale.