picoZ80 Guide Technique
picoZ80 Guide Technique
Ce guide documente l'architecture matérielle du picoZ80, l'interface bus PIO du RP2350, le modèle mémoire, la référence de configuration JSON, le framework de périphériques virtuels et les procédures de débogage. Il est destiné aux développeurs souhaitant comprendre les mécanismes internes, écrire de nouveaux pilotes, porter le firmware sur une nouvelle machine hôte ou déboguer des problèmes au niveau firmware.
Pour la configuration utilisateur et l'utilisation de l'interface web, consultez le
Manuel Utilisateur picoZ80. Pour la présentation du projet et les instructions de compilation, consultez la
page du projet picoZ80.
Architecture Matérielle
Le picoZ80 intègre cinq sous-systèmes sur un unique PCB compact, conçu pour s'inscrire dans l'empreinte d'un boîtier DIP-40. Toute la logique fonctionne en 3,3V ; l'interface bus Z80 gère la conversion de niveaux et l'amplification de courant pour le bus hôte 5V.
Schéma Bloc du Système
┌─────────────────────────────────────────────────────────────────────────┐
│ 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│ │
│ └────────┬────────┘ │
│ │ 5V bus (A0–A15, D0–D7, MREQ, IORQ, RD, WR...) │
└────────────────┼────────────────────────────────────────────────────────┘
│
┌───────┴───────┐
│ Host Z80 │
│ DIP-40 socket│
│ (legacy │
│ computer) │
└───────────────┘
Composants Principaux
| Composant |
Référence |
Rôle |
| MCU principal | RP2350B (QFN-80) | Dual Cortex-M33, 150MHz (jusqu'à 300MHz en OC), 512KB SRAM, 12 machines d'état PIO, 48 broches GPIO |
| Flash | W25Q128 (16MB SPI) | Bootloader, double slot firmware, partitions de configuration |
| PSRAM | 8MB SPI PSRAM | 64 × 64KB banques RAM/ROM pour l'espace d'adressage Z80 |
| Coprocesseur | ESP32-S3-PICO-1 | WiFi, carte SD, serveur web, OTA |
| Hub USB | CH334F | Hub USB, pont pour mise à jour firmware |
| Alimentation | TLV62590BV | Convertisseur buck synchrone 5V → 3,3V |
Attribution GPIO du RP2350B
Le boîtier QFN-80 du RP2350B offre 48 broches GPIO. Le picoZ80 utilise la quasi-totalité de ces broches. L'attribution est fixée dans la conception de la carte et reflétée dans les programmes PIO :
| Plage GPIO |
Signaux |
Direction |
| GPIO 0–15 |
A0–A15 (Bus d’Adresses Z80) |
Sortie (pilotée par PIO) |
| GPIO 16–23 |
D0–D7 (Bus de Données Z80) |
Bidirectionnel (trois-états PIO) |
| GPIO 24 |
MREQ |
Sortie |
| GPIO 25 |
IORQ |
Sortie |
| GPIO 26 |
RD |
Sortie |
| GPIO 27 |
WR |
Sortie |
| GPIO 28 |
M1 |
Sortie |
| GPIO 29 |
RFSH |
Sortie |
| GPIO 30 |
BUSREQ |
Entrée |
| GPIO 31 |
BUSACK |
Sortie |
| GPIO 32 |
HALT |
Sortie |
| GPIO 33 |
INT |
Entrée |
| GPIO 34 |
NMI |
Entrée |
| GPIO 35 |
WAIT |
Sortie |
| GPIO 36 |
CLK |
Entrée (horloge hôte) |
| GPIO 37 |
RESET |
Entrée |
| 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 |
Architecture Firmware
Le firmware du RP2350 est compilé avec le Raspberry Pi Pico SDK 2.x ciblant la plateforme RP2350-arm-s. Le firmware est divisé en deux exécutables indépendants : le Bootloader et l'Application.
Organisation de la Mémoire Flash
| Partition |
Plage d’Adresses |
Taille |
Contenu |
| Bootloader |
0x10000000 – 0x1001FFFF |
128KB |
Pont USB, mise à jour firmware, sélecteur de partition |
| App Slot 1 |
0x10020000 – 0x1051FFFF |
5MB |
Firmware Z80 — application active (slot 1) |
| App Slot 2 |
0x10520000 – 0x10A1FFFF |
5MB |
Firmware Z80 — application active (slot 2) |
| App Config 1 |
0x10A20000 – 0x10C9FFFF |
2.5MB |
Images ROM + config JSON minifiée (slot 1) |
| App Config 2 |
0x10CA0000 – 0x10F1FFFF |
2.5MB |
Images ROM + config JSON minifiée (slot 2) |
| General Config |
0x10F20000 – 0x10FFEFFF |
892KB |
Paramètres du cœur, espace de travail |
| Partition Table |
0x10FFF000 – 0x11000000 |
4KB |
Numéro de slot actif, sommes de contrôle, métadonnées |
Responsabilités Dual-Core
Les deux cœurs Cortex-M33 se voient attribuer des responsabilités entièrement séparées et communiquent via une file de messages inter-cœurs (queue_t). Cette séparation garantit que le travail non temps réel sur le Core 0 n'introduit jamais de gigue dans les transactions bus Z80 sur le Core 1.
| Core |
Responsabilités |
| Core 0 |
Pont série USB CDC ; coordination de la mise à jour firmware ; E/S fichiers (relayées à l'ESP32 via UART) ; dispatch de commandes ESP32 (changements d'images disque, rechargements de configuration, requêtes de version) ; gestion des partitions ; dispatch des messages inter-cœurs. |
| Core 1 |
Boucle chaude d'émulation du bus Z80 — s'exécute exclusivement. Alimente les FIFO PIO, résout chaque transaction bus par rapport à la carte mémoire, et dispatch vers : le matériel hôte physique (PHYSICAL), la PSRAM (RAM/ROM), ou le handler de périphérique virtuel (FUNC). La boucle interne est placée en SRAM. |
Interface Bus PIO
L'interface bus Z80 est implémentée entièrement en assembleur PIO du RP2350 (
z80.pio). Le RP2350 fournit trois blocs PIO (PIO 0, PIO 1, PIO 2) contenant chacun quatre machines d'état — douze machines d'état au total, toutes utilisées par le firmware Z80.
Les programmes PIO s'exécutent indépendamment des cœurs Cortex-M33. L'interface bus continue de répondre de manière déterministe même lorsque le Core 1 est occupé par des accès PSRAM ou des appels de fonctions de périphériques virtuels. Les machines d'état communiquent via des drapeaux IRQ PIO plutôt que par scrutation, éliminant la latence inter-machines.
Tableau des Programmes PIO
| PIO |
Machine d’État |
Programme |
Fonction |
| 0 |
SM 0 |
z80_addr |
Émet l’adresse 16 bits (A0–A15) sur le bus et signale le début du cycle au SM 2. |
| 0 |
SM 1 |
z80_data |
Pilote ou échantillonne D0–D7 avec contrôle trois-états ; relâché pendant BUSRQ. |
| 0 |
SM 2 |
z80_cycle |
Séquenceur de cycle bus de haut niveau — orchestre les cycles de fetch, lecture, écriture, E/S et rafraîchissement DRAM. |
| 0 |
SM 3 |
z80_fetch |
Cycle de fetch d’opcode (M1 + MREQ + RD). |
| 1 |
SM 0 |
z80_mem_read |
Cycle de lecture mémoire (MREQ + RD). |
| 1 |
SM 1 |
z80_mem_write |
Cycle d’écriture mémoire (MREQ + WR). |
| 1 |
SM 2 |
z80_io_read |
Cycle de lecture E/S (IORQ + RD). |
| 1 |
SM 3 |
z80_io_write |
Cycle d’écriture E/S (IORQ + WR). |
| 2 |
SM 0 |
z80_busrq |
Gère BUSREQ/BUSACK ; relâche /IORQ, /MREQ, /RFSH, /M1, /HALT, /WR, /RD. |
| 2 |
SM 1 |
z80_nmi |
Détecte l’assertion NMI et signale le Core 1. |
| 2 |
SM 2 |
z80_clk_sync |
Synchronise les machines d’état PIO sur le signal CLK du Z80 hôte. |
| 2 |
SM 3 |
z80_int_ack |
Gère les cycles d’acquittement d’interruption (M1 + IORQ). |
Conventions de Signaux IRQ PIO
La communication inter-machines d'état utilise les drapeaux IRQ PIO. Le Core 1 surveille ces drapeaux dans la boucle chaude pour agir sur chaque événement bus :
| IRQ |
Événement |
| IRQ 0 |
Adresse valide / début de cycle — un nouveau cycle bus a commencé et A0–A15 sont stables. |
| IRQ 1 |
Phase données — la direction du bus de données a été résolue ; D0–D7 doit être piloté ou échantillonné. |
| IRQ 2 |
T1 détecté — le front montant de T1 sur le cycle courant. Utilisé pour synchroniser les opérations internes avec l’horloge hôte. |
| IRQ 3 |
Événement RESET — la ligne RESET de l’hôte a été activée. Le Core 1 doit réinitialiser l’état d’émulation. |
| IRQ 4 |
NMI détecté — la ligne NMI de l’hôte a été activée. |
| IRQ 6 |
BUSRQ actif — l’hôte a activé BUSREQ ; le PIO relâche le bus. |
Génération de Wait States
Le programme PIO
z80_wait dans PIO 2 SM 0 insère des wait states de T-cycle configurables sur le bus hôte en activant
/WAIT. Le nombre de wait states supplémentaires est contrôlé par bloc mémoire ou E/S via le paramètre
tcycwait dans
config.json.
Les wait states sont nécessaires lorsque le RP2350 a besoin de temps supplémentaire pour terminer un accès PSRAM ou un appel de fonction de périphérique virtuel avant de présenter les données au bus hôte. Le paramètre
tcycsync active la synchronisation T1 (
z80_sync dans PIO 2 SM 1), qui verrouille la fenêtre d'accès PSRAM sur le front montant T1 de chaque cycle bus, empêchant la dérive temporelle dans les applications qui dépendent de l'horloge hôte pour un timing précis (cassette, bit-banging série).
Le sous-système d'E/S Programmable (PIO) du RP2350 est la technologie clé qui permet au picoZ80 de recréer un timing de bus Z80 précis au cycle près. Comprendre comment les machines d'état PIO fonctionnent ensemble est essentiel pour quiconque souhaite modifier l'interface bus ou déboguer des problèmes de timing.
Fondamentaux du PIO RP2350
Chaque bloc PIO contient quatre machines d'état (SM) indépendantes qui exécutent de petits programmes à partir d'une mémoire partagée de 32 instructions. Les machines d'état fonctionnent indépendamment des cœurs Cortex-M33 à la fréquence d'horloge système (jusqu'à 300 MHz). Ressources PIO clés utilisées par le picoZ80 :
- TX FIFO — une file de 4 entrées du CPU vers la machine d'état. Le code C sur le Core 1 pousse des données (adresses, mots de contrôle, instructions injectées) dans la FIFO ; le programme PIO les extrait avec
out ou pull.
- RX FIFO — une file de 4 entrées de la machine d'état vers le CPU. Le PIO pousse les échantillons du bus de données dans la FIFO avec
in ; le Core 1 les lit après la fin de chaque cycle bus.
- Drapeaux IRQ — 8 drapeaux (IRQ 0–7) partagés entre toutes les machines d'état au sein d'un bloc PIO. Les drapeaux sont également visibles entre blocs PIO (IRQ 0–3 d'un bloc correspondent à IRQ 4–7 des blocs adjacents). Les machines d'état utilisent
irq set / irq wait / irq clear pour se synchroniser entre elles et avec le code C.
- Registres scratch X et Y — deux registres 32 bits par SM utilisés pour les compteurs de boucle et les valeurs temporaires.
out exec — une instruction spéciale qui extrait une valeur de la TX FIFO et l'exécute comme instruction PIO. C'est le mécanisme par lequel le code C contrôle dynamiquement les séquences de cycles bus (voir ci-dessous).
set pins / out pins — pilotent directement les broches GPIO. set utilise une valeur immédiate de 5 bits ; out décale les données du registre de décalage de sortie (OSR) vers les broches.
in pins — échantillonne les broches GPIO dans le registre de décalage d'entrée (ISR), puis pousse automatiquement vers la RX FIFO.
wait gpio — bloque le SM jusqu'à ce qu'une broche GPIO spécifique atteigne un niveau spécifié. Utilisé intensivement pour se synchroniser avec le signal d'horloge du Z80 hôte.
- Side-set — permet de piloter une ou deux broches GPIO comme effet de bord de toute instruction, sans utiliser un cycle d'instruction. Le picoZ80 utilise un side-set de 2 bits pour contrôler
/RD et /WR simultanément avec d'autres opérations.
- JMP PIN — saut conditionnel basé sur le niveau d'une broche GPIO désignée. Utilisé pour tester
/WAIT, BUSREQ, /NMI et /RESET.
Le Mécanisme out exec — Injection Dynamique d'Instructions
La caractéristique la plus distinctive de la conception PIO du picoZ80 est l'utilisation de
out exec, 16 dans la machine d'état orchestratrice
z80_cycle. Cette instruction extrait une valeur de 16 bits de la TX FIFO et l'exécute immédiatement comme instruction PIO — la valeur n'est pas une donnée, elle
est la prochaine instruction que la machine d'état exécutera.
Ce mécanisme permet au code C sur le Core 1 de contrôler la séquence de cycles bus en temps réel. Plutôt que de charger un programme PIO fixe pour chaque type de cycle, le Core 1 pousse une séquence d'instructions PIO pré-encodées dans la TX FIFO, et le SM de cycle les exécute une par une :
// 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.
Le code C pré-calcule ces séquences d'instructions au démarrage pour chaque type de cycle (fetch, lecture mémoire, écriture mémoire, lecture E/S, écriture E/S, rafraîchissement, acquittement d'interruption). Pendant l'exécution, le Core 1 sélectionne la séquence pré-construite appropriée et la pousse dans la FIFO. Cette approche offre deux avantages critiques :
- Efficacité de l'espace programme — chaque bloc PIO ne dispose que de 32 emplacements d'instructions. En injectant les instructions dynamiquement, le SM de cycle n'a besoin que de 7 instructions de mémoire programme pour orchestrer tous les types de cycles. Les programmes de type cycle réels (fetch, lecture, écriture, etc.) existent sous forme de tableaux C d'instructions encodées, et non comme programmes PIO résidents.
- Flexibilité — le code C peut modifier la séquence d'instructions injectées à l'exécution pour gérer des cas particuliers (par ex. insertion de wait states supplémentaires, omission de la phase de rafraîchissement, ou génération d'un cycle non standard pour le débogage).
Coordination des Machines d'État
Les 12 machines d'état fonctionnent comme un pipeline coordonné. Le diagramme suivant montre le flux d'un cycle de lecture mémoire typique :
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
Le handshake basé sur les IRQ garantit que le bus d'adresses est stable avant que les signaux de contrôle ne soient activés, et que les données sont échantillonnées au point correct du cycle bus. Les machines d'état ne scrutent jamais — elles utilisent
wait 0 irq N pour se mettre en veille jusqu'à ce que l'événement pertinent se produise, ne consommant aucun cycle CPU pendant l'attente.
Cycle de Fetch Z80 (Cycle M1) — Étape par Étape
Le fetch d'opcode est le cycle bus Z80 le plus complexe — il combine une lecture mémoire avec un cycle de rafraîchissement. Le programme z80_fetch s'exécute sur 4 T-cycles de l'horloge hôte :
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
Le programme PIO implémente ceci comme suit :
- Front montant T1 — le SM
z80_addr place la valeur PC sur A0–A15. z80_fetch active /M1 à l'état bas via set pins.
- Front descendant T1 —
/MREQ et /RD sont activés à l'état bas (via set pins et side-set). L'adresse est maintenant valide et le système mémoire peut commencer à répondre.
- T2 — le SM entre dans une boucle de wait state : il attend le front montant puis descendant du CLK, puis vérifie la broche
/WAIT via jmp pin. Si /WAIT est bas, le SM boucle (ajoutant des cycles Tw). S'il est haut, il passe à T3.
- Front montant T3 —
in pins, 8 échantillonne D0–D7 (l'octet d'opcode) et le pousse dans la RX FIFO. IRQ 1 est activé pour signaler à z80_data/z80_addr que l'adresse de rafraîchissement doit maintenant être émise. /M1, /MREQ et /RD sont désactivés ; /RFSH est activé à l'état bas.
- Front descendant T3 —
/MREQ est de nouveau activé (pour le strobe de ligne de rafraîchissement).
- T4 — le rafraîchissement continue. À la fin de T4,
/MREQ et /RFSH sont désactivés. Le SM de cycle retourne à start_cycle, prêt pour la prochaine transaction bus.
Le Core 1 lit l'opcode depuis la RX FIFO et l'utilise pour décoder l'instruction, déterminer combien de cycles mémoire ou E/S subséquents sont nécessaires, et pousser les séquences d'instructions appropriées.
Cycles de Lecture et Écriture Mémoire
Les cycles de lecture et d'écriture mémoire sont plus simples que le fetch — ils s'étendent sur 3 T-cycles sans phase de rafraîchissement.
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↓)
Pour les lectures, le SM
z80_mem_read active
/MREQ et
/RD au front descendant T1, attend pendant T2 (vérifiant
/WAIT pour les wait states), puis échantillonne le bus de données au front descendant T3 avec
in pins, 8. Pour les écritures,
z80_mem_write active
/MREQ au front descendant T1, puis active
/WR au front descendant T2 après que le bus de données est piloté par
z80_data. Les deux désactivent tous les signaux de contrôle à la fin de T3.
Cycles de Lecture et Écriture E/S
Les cycles E/S du Z80 utilisent /IORQ au lieu de /MREQ et incluent toujours un wait state automatique (Tw) entre T2 et T3. C'est une caractéristique architecturale du Z80 — le cycle supplémentaire donne aux périphériques E/S plus lents le temps de répondre :
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↓)
Le SM
z80_io_read active
/IORQ et
/RD au front montant T2 (et non T1 comme pour les cycles mémoire — c'est la spécification du Z80). Le wait state automatique Tw est implémenté par le même schéma de boucle
jmp pin /
wait utilisé pour les cycles mémoire. Les écritures E/S suivent le même schéma avec
/WR remplaçant
/RD.
Gestion BUSREQ / BUSACK
Le SM
z80_busrq (PIO 2 SM 0) surveille la broche d'entrée
/BUSREQ de l'hôte. Quand
/BUSREQ passe à l'état actif (bas), le SM :
- Active IRQ 6 pour signaler au SM de cycle qu'une requête bus est en attente.
- Attend la fin du cycle bus courant (
wait 1 irq 0).
- Extrait un mot de contrôle de 32 bits de la TX FIFO qui spécifie les directions et valeurs des broches pour l'état de relâchement du bus — ceci met en haute impédance les bus d'adresses et de données et active
/BUSACK à l'état bas.
- Boucle sur
jmp pin jusqu'à ce que /BUSREQ devienne inactif (haut).
- Extrait un second mot de 32 bits pour restaurer les directions normales des broches et désactiver
/BUSACK.
- Efface IRQ 6, permettant au SM de cycle de reprendre.
Le SM de cycle vérifie IRQ 6 au début de chaque cycle via
wait 0 irq 6 — si le drapeau est activé, le SM se bloque jusqu'à ce que la requête bus soit terminée. Ceci garantit que le relâchement du bus se fait proprement entre les cycles, jamais en milieu de cycle.
Synchronisation d'Horloge
Tous les SM de type cycle se synchronisent sur l'horloge Z80 hôte via
wait 1 gpio Z80_PIN_CLK (attendre le front montant) et
wait 0 gpio Z80_PIN_CLK (attendre le front descendant). Cela signifie :
- Les programmes PIO sont indépendants de la fréquence d'horloge — ils fonctionnent à n'importe quelle vitesse d'horloge hôte, du DC à la vitesse maximale que le RP2350 peut suivre (limitée par l'horloge système PIO et la fréquence d'échantillonnage GPIO).
- L'horloge PIO du RP2350 à 300 MHz fournit environ 85 cycles PIO par T-state du Z80 à 3,5 MHz, offrant largement assez de temps pour exécuter les instructions PIO, pousser/extraire les FIFO et vérifier les drapeaux IRQ entre les fronts d'horloge.
- Le SM
z80_sync (PIO 2 SM 1) fournit une IRQ de synchronisation T1 que le code C utilise pour aligner les accès PSRAM avec l'horloge hôte, empêchant la dérive temporelle dans les logiciels hôte sensibles au timing.
- Le SM
z80_clk_sync (PIO 2 SM 2) régénère l'horloge hôte sur un GPIO séparé, fournissant une sortie d'horloge propre pour la surveillance externe ou le déclenchement d'un analyseur logique.
Cycle d'Acquittement d'Interruption
Le SM
z80_int_ack (PIO 2 SM 3) implémente la séquence d'acquittement d'interruption du Z80. Lorsque le code C détecte une condition d'interruption, il charge le programme int_ack. Ce cycle est similaire à un fetch mais avec des différences clés :
/M1 est activé à T1 (comme un fetch), mais /IORQ est activé au lieu de /MREQ au wait state (Tw1).
- Deux wait states automatiques (Tw1, Tw2) sont insérés pour donner au périphérique interrompant le temps de placer un vecteur sur le bus de données.
- L'octet de vecteur est lu depuis D0–D7 et poussé dans la RX FIFO.
- Un cycle de rafraîchissement suit, identique à la phase de rafraîchissement du fetch.
Modèle Mémoire
Les accès mémoire sont résolus à travers trois niveaux de latence croissante. La conception à trois niveaux garantit que le cas courant (RAM/ROM sauvegardée en PSRAM) est rapide tout en permettant une flexibilité maximale pour les périphériques virtuels et le pass-through matériel hôte physique.
Niveau 1 — Table de Dispatch en SRAM RP2350
Un tableau de 128 entrées de valeurs
membankPtr sur 32 bits, résidant dans les 512KB de SRAM embarquée du RP2350, fournit une recherche de type de bloc en O(1) pour chaque transaction bus. Une entrée couvre chaque bloc de 512 octets de l'espace d'adressage Z80 de 64KB (128 × 512 = 65 536 octets). Chaque entrée encode :
- Le type de bloc (PHYSICAL, RAM, ROM, FUNC, etc.).
- Pour les blocs sauvegardés en PSRAM : le numéro de banque PSRAM et l'offset.
- Pour les blocs FUNC : un index dans la table de pointeurs de fonctions des périphériques virtuels.
C'est le chemin le plus rapide — le Core 1 lit l'entrée de la table de dispatch pour l'adresse courante en un seul accès SRAM (zéro wait state à 300MHz) avant de décider de la suite.
Niveau 2 — PSRAM Externe
Les 8MB de PSRAM sont organisés comme suit :
- 64 banques × 64KB — données d'images RAM ou ROM pour l'espace d'adressage Z80.
- 64KB
memPtr — tableau de pointeurs de redirection par octet pour les blocs de type PTR.
- 64KB
memioPtr — tableau de pointeurs de fonctions pour les périphériques FUNC mappés en mémoire.
- 64KB
ioPtr — tableau de pointeurs de fonctions pour les périphériques FUNC de port E/S.
La PSRAM est accédée via le périphérique SPI dédié du RP2350 avec DMA. La latence d'accès est déterministe et gérée par le générateur de wait states pour éviter les violations de bus.
Niveau 3 — Flash SPI 16MB
Les images ROM sont chargées depuis la Flash (ou la carte SD, via l'ESP32) dans la PSRAM au démarrage. À l'exécution, la Flash n'est pas accédée pour les transactions bus — toutes les données ROM sont servies depuis la PSRAM. La Flash est utilisée pour :
- Le bootloader et le firmware applicatif.
- Le
config.json minifié (mis en cache depuis la carte SD à chaque démarrage).
- Les images ROM dans les partitions App Config (utilisées lorsqu'aucune carte SD n'est présente).
Types de Blocs Mémoire
| Type |
Description |
PHYSICAL |
Pass-through — le RP2350 relâche le bus et la mémoire physique de l’hôte répond. Utilisé pour la ROM et la RAM natives de l’hôte. |
PHYSICAL_VRAM |
Comme PHYSICAL mais avec des wait states supplémentaires pour le timing de la VRAM hôte. Adapté aux régions VRAM du MZ-700/MZ-80A. |
PHYSICAL_HW |
Pass-through pour les registres matériels de l’hôte (périphériques mappés en E/S dans l’espace mémoire). |
RAM |
Lecture/écriture — sauvegardé par une banque PSRAM. Le RP2350 dessert les lectures et écritures depuis/vers la PSRAM. |
ROM |
Lecture seule — sauvegardé par une banque PSRAM. Les cycles d’écriture sont silencieusement ignorés (l’hôte voit un timing bus normal mais aucune donnée n’est stockée). |
VRAM |
RAM vidéo sauvegardée en PSRAM. Les cycles d’écriture sont dupliqués simultanément vers la PSRAM et la VRAM physique de l’hôte. |
FUNC |
Périphérique virtuel — chaque accès déclenche un appel de fonction C via la table de pointeurs de fonctions memioPtr ou ioPtr, permettant une émulation E/S arbitraire. |
PTR |
Redirection par octet — chaque octet du bloc de 512 octets peut pointer indépendamment vers tout autre type de bloc ou emplacement PSRAM. |
Référence de Configuration
Tout le comportement du picoZ80 est contrôlé par
config.json sur la carte SD. Le RP2350 lit et minifie ce fichier au démarrage, stockant le résultat en Flash. Les démarrages suivants utilisent la copie Flash si aucune carte SD n'est présente.
La structure JSON de haut niveau est :
{
"esp32": {
"core": { ... },
"wifi": { ... }
},
"rp2350": {
"core": { ... },
"z80": [ { "memory": [...], "io": [...], "drivers": [...] } ]
}
}
esp32.core
| Clé |
Type |
Description |
device |
string |
Personnalité CPU — "Z80" pour picoZ80, "6502" pour pico6502, "6512" pour pico6512. |
mode |
integer |
Mode WiFi par défaut au démarrage : 0 = client (station), 1 = Point d’Accès. |
esp32.wifi
| Clé |
Type |
Description |
override |
0/1 |
Commutateur principal : 1 = appliquer tous les paramètres ci-dessous ; 0 = utiliser les paramètres NVS persistants. |
wifimode |
string |
"ap" = mode Point d’Accès ; "client" = mode Station/client. |
ssid |
string |
Nom du réseau WiFi à créer (AP) ou rejoindre (client). |
password |
string |
Phrase secrète WiFi. |
ip |
string |
Adresse IP fixe (par ex. "192.168.1.192"). |
netmask |
string |
Masque de sous-réseau (par ex. "255.255.255.0"). |
gateway |
string |
Passerelle par défaut (par ex. "192.168.1.1"). |
dhcp |
0/1 |
Mode client : 1 = DHCP ; 0 = utiliser les paramètres IP fixes. |
webfs |
string |
Répertoire racine du système de fichiers web sur la carte SD (par défaut "webfs"). |
persist |
0/1 |
1 = écrire les paramètres résolus en NVS pour la persistance entre les redémarrages. |
rp2350.core
| Clé |
Type |
Description |
cpufreq |
integer |
Horloge système du RP2350 en Hz (par ex. 300000000). La fréquence stable maximale dépend de la fréquence PSRAM et de la tension du cœur. |
psramfreq |
integer |
Horloge SPI de la PSRAM en Hz (par ex. 133000000). |
voltage |
float |
Tension du cœur du RP2350 en volts (par ex. 1.10). Des vitesses d’horloge plus élevées nécessitent une tension plus élevée. |
addrDrive |
integer (0–3) |
Force de pilotage GPIO du bus d’adresses : 0=2mA, 1=4mA, 2=8mA, 3=12mA. Par défaut 0. |
addrSlew |
integer (0–1) |
Vitesse de transition GPIO du bus d’adresses : 0=lente (par défaut), 1=rapide. |
dataDrive |
integer (0–3) |
Force de pilotage GPIO du bus de données. Même encodage que addrDrive. Par défaut 0. |
dataSlew |
integer (0–1) |
Vitesse de transition GPIO du bus de données. Même encodage que addrSlew. Par défaut 0. |
ctrlDrive |
integer (0–3) |
Force de pilotage GPIO des signaux de contrôle. Même encodage que addrDrive. Par défaut 0. |
ctrlSlew |
integer (0–1) |
Vitesse de transition GPIO des signaux de contrôle. Même encodage que addrSlew. Par défaut 0. |
addrSchmitt / dataSchmitt / ctrlSchmitt |
0/1 |
Active le trigger de Schmitt en entrée pour le groupe de bus d’adresses / données / contrôle. 1 = activé (par défaut), 0 = désactivé. S’applique aux broches configurées en entrée. |
addrPull / dataPull / ctrlPull |
integer (0–2) |
Résistance de tirage pour le groupe de bus d’adresses / données / contrôle : 0 = aucune, 1 = tirage vers le bas (pull-down), 2 = tirage vers le haut (pull-up). |
refresh |
integer |
Génération du rafraîchissement DRAM Z80 : 0 = désactivé (aucun cycle de rafraîchissement), 1 = un cycle de rafraîchissement à chaque fetch d’opcode, N = un cycle de rafraîchissement tous les N fetchs. Réduit la charge sur le bus pour les hôtes dont la DRAM ne nécessite pas de rafraîchissement à chaque fetch. |
pinOverrides |
array |
Surcharges GPIO par broche. Chaque élément : { "pin": N, "drive": D, "slew": S, "schmitt": 0/1, "pull": P }. Surcharge les paramètres par défaut au niveau bus pour des broches GPIO individuelles lorsque du matériel spécifique nécessite des caractéristiques électriques différentes. |
z80[].memory — Entrées de Carte Mémoire
Le tableau memory définit la carte mémoire Z80. Les entrées doivent être ordonnées par adresse. Les régions doivent être alignées et dimensionnées en multiples de 512 octets. Les espaces entre les entrées sont traités comme du pass-through PHYSICAL.
| Clé |
Type |
Description |
enable |
0/1 |
Indique si cette entrée est active. Les entrées désactivées sont ignorées au démarrage. |
addr |
hex string |
Adresse de début dans l’espace d’adressage Z80 (par ex. "0x0000"). Doit être alignée sur 512 octets. |
size |
hex string |
Taille de la région en octets (par ex. "0x2000" pour 8KB). Doit être un multiple de 512. |
type |
string |
Type de bloc — voir Types de Blocs Mémoire. |
bank |
integer |
Numéro de banque PSRAM (0–63) pour les types RAM/ROM/VRAM/FUNC. |
tcycwait |
integer |
Wait states de T-cycle supplémentaires à insérer à chaque accès à cette région. |
tcycsync |
0/1 |
Activer la synchronisation T1 pour cette région. Requis pour les régions sensibles au timing. |
task |
string |
Identifiant de tâche optionnel pour les blocs de type FUNC (chaîne de liaison au pilote). |
file |
string |
Chemin sur la carte SD vers une image ROM à précharger dans la banque PSRAM au démarrage (par ex. "/ROM/mz700.rom"). |
fileofs |
integer |
Offset en octets dans le fichier image ROM à partir duquel commencer la lecture. |
z80[].io — Entrées de Carte de Ports E/S
Le tableau io mappe les plages de ports E/S Z80 vers des types de blocs. Seuls les types PHYSICAL et FUNC sont pertinents pour les entrées E/S.
| Clé |
Type |
Description |
enable |
0/1 |
Indique si cette entrée E/S est active. |
addr |
hex string |
Adresse de port E/S de début (par ex. "0xE0"). |
size |
hex string |
Nombre de ports consécutifs (par ex. "0x04" pour les ports E0–E3). |
type |
string |
PHYSICAL = passer à l’hôte ; FUNC = appeler la fonction handler C. |
task |
string |
Chaîne de liaison au pilote pour les entrées de type FUNC. |
z80[].drivers — Instances de Pilotes
Le tableau drivers instancie les pilotes de périphériques virtuels et les lie aux régions mémoire ou E/S. Chaque pilote a un type (le module pilote C), un nom (identifiant d'instance), et un ou plusieurs objets interface qui définissent les images ROM, les cartes d'adresses, les cartes E/S et les paramètres pour cette instance de pilote.
"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" }
]
}
]
}
]
Chaque entrée de pilote a un "name" de haut niveau (le module pilote C à instancier), un "type" (PHYSICAL ou VIRTUAL), et un tableau "if" (interface) contenant un ou plusieurs objets interface. Chaque objet interface décrit un sous-pilote ou une carte périphérique et contient ces champs :
| Clé |
Type |
Description |
enable |
0/1 |
Indique si cette interface est active (0 = ignorée pendant l’initialisation). |
name |
string |
Identifiant d’instance — doit correspondre à un nom dans le tableau interfaceFuncMap[] du persona. |
type |
string |
PHYSICAL ou VIRTUAL. |
rom |
array |
Images ROM à charger en PSRAM (voir ci-dessous). |
addrmap |
array |
Entrées de remappage d’adresses mémoire (srcaddr/dstaddr/size). |
iomap |
array |
Entrées de remappage de ports E/S (srcaddr/dstaddr/size/16bit). |
param |
array |
Paramètres spécifiques au pilote — typiquement { "enable":1, "file":"/path/to/image" } pour les images disque, { "name":"key", "value":"val" } pour les paramètres nommés, ou { "ip":"a.b.c.d:port", "enable":1 } pour l’adresse du serveur de fichiers réseau Celestite. |
Ports de base d’interface relocalisables. Afin que les cartes indépendantes de la machine puissent être utilisées sur des cartes personnalisées / d’expérimentation (voir OpenZ80), plusieurs pilotes d’interface lisent leur port d’E/S de base depuis le dstaddr de leur entrée iomap (avec srcaddr réglé sur le port authentique de la carte), revenant à leur port d’origine lorsqu’aucune entrée iomap n’est présente. Les cartes relocalisables et leurs bases par défaut sont 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) et Celestite (0x60/16). Les clés JSON sont en minuscules (srcaddr / dstaddr) et leurs valeurs sont interprétées comme des nombres. Le champ Base I/O Port de la page Configuration GUI écrit automatiquement l’entrée iomap correcte.
rom[].loadaddr[] — Adresses de Chargement ROM
Chaque entrée de fichier ROM contient un tableau loadaddr spécifiant où les données ROM sont chargées en PSRAM. Plusieurs entrées loadaddr permettent de répartir un seul fichier ROM sur des plages d'adresses non contiguës ou des banques PSRAM différentes.
| Clé |
Type |
Description |
enable |
0/1 |
Indique si cette adresse de chargement est active. |
position |
integer |
Offset en octets dans le fichier ROM à partir duquel commencer la lecture. |
addr |
hex string |
Adresse Z80 cible dans la carte mémoire (par ex. "0x0000"). |
bank |
integer |
Numéro de banque PSRAM dans laquelle charger. |
size |
hex string |
Nombre d’octets à charger (par ex. "0x1000" pour 4KB). |
tcycwait |
integer |
Wait states de T-cycle supplémentaires pour cette région. |
tcycsync |
integer |
Valeur de synchronisation de T-cycle pour cette région. |
Compatibilité Persona–Interface
Tous les pilotes d'interface ne sont pas disponibles pour chaque persona. Le tableau ci-dessous montre la compatibilité actuelle des interfaces pour les séries Sharp MZ / X1. Le persona Amstrad PCW-9512 est un pilote autonome avec un FDC uPD765 intégré (pas de pilotes d'interface séparés). Le persona Tatung Einstein TC-01 est un pilote autonome avec un FDC WD1770 intégré et une sous-interface EinsteinFDC. La colonne
Open montre les cartes indépendantes de la machine acceptées par le persona expérimentateur
OpenZ80.
Le tableau montre quelles interfaces peuvent être utilisées avec chaque persona machine de haut niveau via le tableau "if". La valeur "name" de l'interface dans le JSON doit correspondre à l'une des entrées supportées pour le persona choisi.
| Interface |
MZ-700 |
MZ-1500 |
MZ-80K |
MZ-800 |
MZ-80A |
MZ-2000 |
MZ-2200 |
MZ-80B |
MZ-2500 |
Open |
| RFS |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
— |
— |
— |
— |
| TZFS |
Yes |
— |
— |
— |
— |
— |
— |
— |
— |
— |
| MZ-1E05 |
Yes |
Yes |
— |
Yes |
— |
— |
— |
— |
— |
Yes |
| MZ80FIO |
— |
— |
Yes |
Yes |
— |
— |
— |
— |
— |
— |
| MZ80AFI |
— |
— |
Yes |
Yes |
Yes |
— |
— |
— |
— |
— |
| MZ-8BFI / E0054PA |
— |
— |
— |
Yes |
— |
Yes |
Yes |
Yes |
Yes |
— |
| MZ-1E14 |
Yes |
Yes |
Yes |
Yes |
— |
— |
— |
Yes |
Yes |
— |
| MZ-1E19 |
Yes |
Yes |
Yes |
Yes |
— |
Yes |
Yes |
Yes |
Yes |
— |
| MZ-1R12 |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
| MZ-1R18 |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
Yes |
| MZ-1R23 |
— |
Yes |
— |
Yes |
— |
— |
— |
Yes |
Yes |
Yes |
| MZ-1R37 |
— |
Yes |
Yes |
Yes |
— |
— |
— |
Yes |
Yes |
Yes |
| PIO-3034 |
— |
Yes |
Yes |
Yes |
— |
— |
— |
Yes |
Yes |
Yes |
| Celestite |
— |
Yes |
— |
Yes |
— |
— |
— |
Yes |
Yes |
Yes |
| MZ-8BIO3 |
Yes |
Yes |
— |
Yes |
— |
— |
— |
Yes |
— |
Yes |
| MZ-1E24 |
Yes |
Yes |
— |
Yes |
— |
— |
— |
Yes |
— |
Yes |
| MZ-1E30 |
— |
— |
— |
— |
— |
— |
— |
Yes |
Yes |
— |
Pilotes Intégrés
Le firmware supporte un système de compilation ciblé avec cinq cibles de modèle : BaseZ80 (tous les pilotes), SharpZ80 (Sharp uniquement), AmstradZ80 (Amstrad uniquement), TatungZ80 (Tatung uniquement) et OpenZ80 (le persona expérimentateur indépendant de la machine). Les defines de compilation INCLUDE_SHARP_DRIVERS, INCLUDE_AMSTRAD_DRIVERS, INCLUDE_TATUNG_DRIVERS et INCLUDE_OPEN_DRIVERS contrôlent quels modules pilotes sont compilés. Les tableaux ci-dessous listent tous les pilotes disponibles.
Série Sharp MZ (INCLUDE_SHARP_DRIVERS)
Lorsque le firmware est compilé avec
INCLUDE_SHARP_DRIVERS, les modules pilotes suivants sont inclus et peuvent être instanciés via le tableau
drivers :
| Pilote |
Chaîne de Type |
Description |
MZ700.c |
MZ700 |
Sharp MZ-700 bank switching, vidéo, E/S clavier |
MZ80A.c |
MZ80A |
Sharp MZ-80A — ROM moniteur (SA-1510), VRAM, émulation Intel 8253 PIT, 8255 PPI, échange mémoire MEMSW/MEMSWR (y compris bank switching CP/M), prise en charge du mode mixte physique+virtuel, et support des sous-interfaces RFS, MZ80AFI, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18 |
MZ2000.c |
MZ2000 |
Sharp MZ-2000 — commutation de mode mémoire BST/NST, overlay VRAM caractères + graphiques, 8253 PIT, 8255 PPI, Z80 PIO, MB8866 FDC. Prend en charge à la fois le mode physique (remplacement Z80 avec détection automatique du mode boot/normal) et le mode virtuel (émulation complète basée sur PSRAM avec mirroring de la ROM IPL) |
MZ2200.c |
MZ2200 |
Sharp MZ-2200 — commutation de mode mémoire BST/NST, overlay VRAM, 8253 PIT, 8255 PPI, Z80 PIO, MB8866 FDC, CRT couleur |
MZ80B.c |
MZ80B |
Sharp MZ-80B — ROM IPL 2K, BST/NST, affichage monochrome, doubles pages GRPH, 8253 PIT, 8255 PPI, Z80 PIO |
MZ2500.c |
MZ2500 |
Sharp MZ-2500 (SuperMZ) — MMU à 8 pages (64 blocs), modes de compatibilité MZ-2000/MZ-80B, YM2203, G-CRTC, MB8876 FDC, palette, contrôleur d’interruption. Le mode virtuel prend en charge les logiciels pilotés par interruption via des handlers fetchByte/RETI personnalisés (cycles bus M1 physiques pour le cadençage du gate array), format de disque natif D88 avec détection automatique sparse/contiguë, suppression d’interruption ponctuelle pendant l’initialisation |
MZ1500.c |
MZ1500 |
Sharp MZ-1500 — surensemble du MZ-700 avec lecteur Quick Disk intégré, PCG, son PSG stéréo (SN76489AN), interface imprimante Z80 PIO, 8253 PIT, sélection de mode MZ-700/MZ-1500 par commutateur DIP. Sous-interfaces : 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 moniteur SP-1002 (0x0000–0x0FFF), 2KB VRAM (0xD000–0xD7FF), clavier 8255 PPI / 8253 PIT / LS367 (0xE000–0xE7FF), ROM de boot native MZ-80FD (0xF000–0xF3FF), échange mémoire MEMSW/MEMSWR pour CP/M. Modes physique + virtuel (le CP/M en mode physique utilise le remap d’accès Z80 propre au pilote ; le mode virtuel est requis pour le CP/M d’origine). Deux chemins floppy : MZ80FIO natif (T3444M) — interface MZ-80FD d’origine, boote/lit tous les disques MZ-80K ; et MZ80AFI (FDC MZ-80A) — utilisé pour CP/M, boote le CP/M MZ-80K et lit les disques CP/M MZ-80K depuis CP/M (C:/D:). Une seule interface floppy est active à la fois ; MZ80FIO l’emporte si les deux sont présentes. Sous-interfaces : RFS, MZ80FIO, MZ80AFI, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18, MZ-1R37, PIO-3034 |
MZ800.c |
MZ800 |
Sharp MZ-800 — pilote à double mode (compatibilité MZ-700 + MZ-800 natif). Espionne le registre de mode d’affichage du GDG (port 0xCE) pour basculer de mode à la volée : le mode natif ajoute les graphiques 320×200 / 640×200 (plans VRAM 0x8000–0xBFFF), une palette 4/16 couleurs, une E/S GDG mappée sur ports (0xCC–0xCF, palette 0xF0), des interruptions vectorisées IM2 via la chaîne daisy-chain du Z80-PIO ; le mode MZ-700 utilise les 8255/8253 mappés en mémoire (0xE000–0xE7FF) et la VRAM texte (0xD000). PSG SN76489 (0xF2), WD1773 FDC (0xD8–0xDF), QuickDisk (0xF4–0xF7), ports de banking mémoire 0xE0–0xE6. Le mode virtuel rejoue un RETI physique sur le bus réel pour servir le verrou in-service du PIO. |
MZ80AFI.c |
MZ80AFI |
Interface floppy Sharp MZ-80A — émule le contrôleur de disquette AFI du MZ-80A |
MZ80FIO.c |
MZ80FIO |
Interface floppy Sharp MZ-80FD/MZ-80FIO (MZ-80K) — ROM de boot FDIF à 0xF000–0xF3FF, ports T3444M 0xF8–0xFB, jusqu’à 4 lecteurs, changement de disque à l’exécution |
T3444M.c |
(utilisé par MZ80FIO) |
Toshiba T3444M/T3444A FDC — floppy natif MZ-80K. CPC extended DSK, 35 pistes, 2 têtes, 16 secteurs/piste, secteurs FM de 128 octets ; analyseur DSK Track-Info robuste ; 4 images de lecteur simultanées |
WD1773.c |
WD1773 |
WD1773 FDC — images DSK/RAW/D88 80 pistes, 2 têtes, 8 secteurs |
QDDrive.c |
QDDRIVE |
Lecteur Sharp QuickDisk — émulation complète Z80 SIO/2 avec données de piste en spirale, contrôle moteur et E/S carte SD asynchrone |
RFS.c |
RFS |
ROM Filing System — chargement MZF, CP/M, BASIC depuis carte SD |
TZFS.c |
TZFS |
TranZPUter Filing System — moniteur multi-bancs fonctionnel + système de fichiers CP/M, sélectionnable sur le persona MZ-700. Modes mémoire tranZPUter via le port 0x60, processeur de service K64F virtuel via OUT (0x68), E/S secteur CP/M via l’ESP32. ROM roms/tzfs.bin depuis TZFS/asm/tzfs.asm |
MZ-1E05.c |
MZ1E05 |
Unité d’interface de disquette Sharp MZ-1E05 (basée sur WD1773) |
MZ8BFI.c |
MZ8BFI / E0054PA |
Interface de disquette MZ-2000 — MB8866 FDC sans ROM pilote (code dans l’IPL). Prise en charge du format D88. |
MZ-1E14.c |
MZ1E14 |
Contrôleur QuickDisk MZ-1E14 avec ROM BIOS (MZ-700/MZ-800) |
MZ-1E19.c |
MZ1E19 |
Contrôleur QuickDisk MZ-1E19 sans ROM BIOS |
MZ-1R12.c |
MZ1R12 |
Carte RAM 32KB sauvegardée par batterie (persistée sur carte SD) |
MZ-1R18.c |
MZ1R18 |
Carte d’extension RAM 64KB |
MZ-1R23.c |
MZ1R23 |
ROM Kanji 128KB MZ-1R23 (motifs JIS 16×16) et ROM Dictionnaire 256KB MZ-1R24. Fichiers ROM chargés depuis la carte SD. Ports E/S B8h–B9h avec lecture à auto-incrément |
MZ-1R37.c |
MZ1R37 |
MZ-1R37 640KB EMM (Expanded Memory Manager) — espace d’adressage 20 bits avec verrouillage d’adresse par port E/S |
PIO-3034.c |
PIO3034 |
IO DATA PIO-3034 320KB EMM — compteur d’adresses 19 bits avec port de données à auto-incrément |
Celestite.c |
Celestite |
Carte composite Celestite — contrôleur Ethernet Wiznet W5100 (émulation de registres), contrôleur d’interruption, UFM, RAM CMOS 32KB MZ-1R12 intégrée (extensible à 64KB), MZ-1R37 640KB EMM optionnel. Ports E/S 60h–6Fh. Le paramètre ip dans le tableau JSON param configure l’adresse du serveur de fichiers netfs.py (par ex. "192.168.1.210:6800"). Phase 2 : réseau TCP/IP réel via le pont ESP32 — les commandes socket W5100 sont transmises à l’ESP32 pour les opérations BSD socket réelles. IPC inter-cœurs pour NET_CFG, NET_SOCK, NET_SEND, NET_RECV, NET_PING |
MZ8BIO3.c |
MZ-8BIO3 |
Carte série RS-232C (connecteur BI), Z80 SIO émulé aux ports 0xB0–0xB3 (base configurable). Canaux A/B pontés vers les ports série USB CDC 2 et 3. Pas de ROM. |
MZ1E24.c |
MZ-1E24 |
Carte série RS-232C (connecteur Sharp ST) ; identique au MZ-8BIO3 avec un câblage de connecteur différent. |
Z80SIO.c |
(utilisé par MZ-8BIO3 / MZ-1E24) |
Zilog Z80 SIO/2 fidèle au niveau des registres : WR0–WR7, RR0–RR2, interruptions vectorisées Z80 mode-2, daisy-chain in-service à 4 niveaux, status-affects-vector. Des anneaux SPSC sans verrou relient le cœur Z80 (core 1) et le service USB CDC (core 0). |
SASI.c + MZ1E30.c |
MZ-1E30 |
Contrôleur de disque dur SASI MZ-1E30 — émule le contrôleur de disque dur SASI (Shugart Associates System Interface) Sharp MZ-1E30 pour MZ-2500/MZ-80B. Jusqu’à 4 cibles de disque (~21,4 Mo chacune, blocs de 256 octets), ROM IPL 32KB (accès E/S via les ports 0xA8–0xA9), E/S secteur à la demande depuis les images disque de la carte SD. Commandes SASI : TEST_UNIT_READY, REQUEST_SENSE, READ(6), WRITE(6), SEEK(6), INQUIRY. Ports E/S 0xA4–0xA5 (données/contrôle SASI) |
PIT8253.c |
PIT8253 |
Émulation autonome Intel 8253 PIT — les six modes de compteur, BCD/binaire, latch, lecture/chargement LSB/MSB |
PPI8255.c |
PPI8255 |
Émulation autonome Intel 8255 PPI — E/S Mode 0, set/reset de bit, callbacks de sortie, injection d’entrée |
Série Amstrad PCW (INCLUDE_AMSTRAD_DRIVERS)
Lorsque le firmware est compilé avec
INCLUDE_AMSTRAD_DRIVERS, les modules pilotes suivants sont inclus :
| Pilote |
Chaîne de Type |
Description |
PCW9512.c |
PCW9512 |
Amstrad PCW-9512 — Z80A @ 4MHz, 512KB RAM avec commutation de pages 16KB à 4 banques (ports F0–F3), gate array (ASIC) pour vidéo/horloge système/routage FDC/contrôle moteur (port F8), contrôleur d’imprimante à marguerite 8041 (ports FC–FD), émulation de la séquence bootstrap. Modes virtuel et physique pris en charge |
uPD765.c |
— |
Émulation NEC uPD765 FDC — prise en charge du format CPC DSK (ports 00–01). Commandes du gate array : fin du bootstrap, redémarrage, routage INT FDC (NMI/INT/ignorer), terminal count, moteur marche/arrêt. Imagerie de disque physique via code Z80 injecté. Module FDC réutilisable (analogue à WD1773.c pour Sharp) |
Série Tatung Einstein (INCLUDE_TATUNG_DRIVERS)
Lorsque le firmware est compilé avec
INCLUDE_TATUNG_DRIVERS, les modules pilotes suivants sont inclus :
| Pilote |
Chaîne de Type |
Description |
EinsteinTC01.c |
EinsteinTC01 |
Tatung Einstein TC-01 — Z80A @ 4MHz, 64KB RAM + 8KB ROM commutable (X-TAL MOS), bascule ROM/RAM via le port 0x24, TMS9129 VDP avec imposition d’un timing inter-accès (intervalle ~2us), AY-3-8910 PSG (ports 0x02-0x03), Z80 CTC (ports 0x28-0x2B), Z80 PIO (ports 0x30-0x33), interface clavier (port 0x20). Modes virtuel et physique pris en charge |
EinsteinFDC.c |
— |
Sous-interface Einstein FDC — 2 lecteurs, prise en charge des formats DSK/D88. Imagerie de disque physique : lecture d’une disquette physique vers DSK, écriture d’un DSK vers une disquette physique |
WD1770.c |
— |
Émulation WD1770 FDC — prise en charge des formats Extended CPC DSK, D88 et DSK standard. 40 pistes, 1 tête, 10 secteurs, 512 octets (disquettes 200KB). Module FDC réutilisable pour les machines basées sur WD1770 (distinct de WD1773.c utilisé par Sharp) |
TZFS — Modèle Moniteur + CP/M (persona MZ-700)
TZFS.c implémente un moniteur bas niveau multi-bancs fonctionnel et un système de fichiers — un ensemble d'améliorations par rapport au MONITOR 1Z-013A d'origine (accès SD, commutation de bancs ROM, un assembleur / désassembleur et des outils) — modelé sur le TZFS du tranZPUter SW et son processeur d'E/S virtuel K64F. Il est proposé comme
interface sélectionnable sur le persona MZ-700 uniquement (enregistré dans
MZ700.c aux côtés de RFS, et en pratique mutuellement exclusif avec lui), et non comme un persona de premier niveau. CP/M s'exécute sous le moniteur.
Émulation des modes mémoire (port 0x60)
L'écriture d'un mode mémoire tranZPUter sur le port d'E/S
0x60 redirige les pointeurs de banc. Les modes sont
TZMM_ORIG,
TZMM_BOOT,
TZMM_TZFS,
TZMM_TZFS2,
TZMM_TZFS3,
TZMM_TZFS4,
TZMM_CPM,
TZMM_CPM2 et
TZMM_COMPAT. La disposition CP/M
CPM2 utilise une pagination du bloc 0 à granularité octet —
0x0000–
0x003F correspondent au bloc de vecteurs et
0x0040–
0x01FF au début de la TPA.
Processeur de service K64F virtuel (port 0x68)
Le Z80 demande des services en exécutant
OUT (0x68), ce qui met en file un message
MSG_TZFS_SVCREQ vers le Core 0 ; le Core 0 exécute
TZFS_processServiceRequest. Les services du système de fichiers sont READDIR / NEXTDIR (blocs de répertoire de 16 entrées mis en cache), READFILE / NEXTREADFILE, LOADFILE (compatible en-tête MZF et objet-banc), CHANGEDIR et CLOSE. Les services CP/M sont LOADBDOS (rechargement CCP + BDOS au démarrage à chaud), ADDSDDRIVE, READSDDRIVE et WRITESDDRIVE, ainsi que des services de fréquence CPU. Comme le picoZ80 n'a pas d'accès SD direct, les secteurs CP/M de 512 octets sont lus et écrits via l'
ESP32 (
ESP_readSector /
ESP_writeSector) sur des fichiers d'image complète ; les chemins d'image par lecteur proviennent des entrées
param[].file du JSON d'interface, avec le modèle de repli
CPM/SDC16M/RAW/CPMDSK<nn>.RAW. La ROM TZFS est
roms/tzfs.bin sur la carte SD, assemblée depuis
TZFS/asm/tzfs.asm (son BIOS CP/M depuis
TZFS/asm/cbios.asm /
cpm22.asm). Elle est livrée dans
config_MZ-700_MZ-700.json avec
"enable": 0 et est activée dans le JSON ou depuis la page Configuration de l'interface web GUI.
OpenZ80 — Persona Expérimentateur (INCLUDE_OPEN_DRIVERS)
La cible
OpenZ80 (
TARGET_MODEL_OPEN →
INCLUDE_OPEN_DRIVERS) compile un persona Z80 « vanilla » délibérément nu, destiné aux expérimentateurs qui intègrent le picoZ80 dans une carte de leur propre conception ou dans une machine sans pilote dédié. En mode
PHYSICAL, l'ensemble de l'espace mémoire et d'E/S 64K est transmis à la carte réelle (les cartes d'interface superposent leurs ports d'E/S) ; en mode
VIRTUAL, il présente une RAM 64K plate dans laquelle les images ROM au niveau du pilote sont chargées séquentiellement à partir de 0x0000. Il ne comporte aucun matériel machine et réutilise tels quels les modules de cartes d'interface Sharp (ils ne conservent aucun état spécifique à un persona), n'exposant que les cartes indépendantes de la machine ci-dessous — chacune prenant en charge la
relocalisation du port d'E/S de base.
| Driver |
Type String |
Description |
Open.c |
Open |
Persona Z80 vanilla / expérimentateur — aucun matériel machine. Passage direct physique ou RAM virtuelle 64K plate avec chargement de ROM au niveau du pilote depuis 0x0000 |
MZ-1R12.c |
MZ1R12 |
Carte fichier-RAM 32K MZ-1R12 (base par défaut 0xF8, relocalisable) |
MZ-1R18.c |
MZ1R18 |
Carte RAM 64K MZ-1R18 (base par défaut 0xEA, relocalisable) |
MZ-1R23.c |
MZ1R23 |
Carte ROM Kanji MZ-1R23 / dictionnaire MZ-1R24 (base par défaut 0xB8, relocalisable) |
MZ-1R37.c |
MZ1R37 |
EMM 640K MZ-1R37 (base par défaut 0xAC, relocalisable) |
PIO-3034.c |
PIO3034 |
EMM parallèle / E/S parallèle PIO-3034 (base par défaut 0x00, relocalisable) |
MZ8BIO3.c / MZ1E24.c |
MZ8BIO3 / MZ1E24 |
Cartes série RS-232C doubles (Z80 SIO, base par défaut 0xB0, relocalisable ; canaux A/B sur USB CDC 2/3) |
MZ-1E05.c |
MZ1E05 |
Interface disquette WD1773 (base par défaut 0xD8, relocalisable ; nécessite une ROM d’amorçage FDC) |
Celestite.c |
Celestite |
Carte LAN ESP32 Celestite (base par défaut 0x60, relocalisable) |
Compilez avec
build_tzpuPico.sh open. Pour adapter le picoZ80 à une nouvelle machine, prenez comme base l'un des pilotes de persona situés sous
src/drivers/{Sharp,Amstrad,Tatung,Other}/ et associez-le à la source ROM de moniteur / IPL / BIOS CP/M / amorçage disquette correspondante dans les répertoires
asm/ des projets RFS et TZFS (p. ex.
RFS/asm/sa1510.asm,
RFS/asm/cbios.asm,
TZFS/asm/mz2000_ipl.asm,
RFS/asm/mz80afi.asm). Consultez le
Guide du Développeur pour la procédure pas à pas.
Framework de Périphériques Virtuels
Le type de bloc FUNC permet une émulation E/S arbitraire en appelant des fonctions handler C à chaque accès bus. N'importe quel bloc de 512 octets de mémoire ou plage de ports E/S peut être soutenu par une fonction.
Signatures des Fonctions Handler
Les handlers FUNC mémoire sont stockés dans la table memioPtr en PSRAM. Les handlers FUNC E/S sont stockés dans la table ioPtr. Les signatures de fonctions sont :
/* 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);
Les fonctions handler sont appelées directement depuis la boucle chaude du Core 1. Elles doivent se terminer avant que les wait states du cycle bus courant n'expirent — gardez les handlers courts et évitez toute opération bloquante (E/S fichier, UART, etc.). Si un handler doit déclencher une opération plus longue (par ex. charger un secteur de disque), il doit poster un message au Core 0 via la file inter-cœurs et retourner immédiatement avec un octet de statut, reportant l'E/S réelle au Core 0.
Écrire un Nouveau Pilote
Pour ajouter le support d'un nouveau périphérique ou d'une nouvelle machine hôte :
- Créez un nouveau fichier
.c / .h dans le répertoire src/drivers/.
- Implémentez les fonctions handler de lecture et d'écriture correspondant aux signatures ci-dessus.
- Enregistrez les pointeurs de fonctions handler dans les tables
memioPtr ou ioPtr pendant l'initialisation du pilote.
- Ajoutez le pilote à la cible de compilation CMakeLists.txt.
- Ajoutez une entrée de chaîne de type pour que l'analyseur de configuration JSON puisse instancier le pilote par nom.
- Documentez les clés
param du pilote dans le fichier d'en-tête de votre pilote.
La fonction d'initialisation du pilote est appelée une fois au démarrage, après l'analyse de
config.json. Le pilote reçoit un pointeur vers son bloc de configuration d'interface et doit configurer tout état interne et enregistrer ses handlers à ce moment.
ICE (Shell de Débogage)
Le picoZ80 inclut un shell de débogage ICE (In-Circuit Emulator) intégré sur le canal USB CDC 1 (le second port série énuméré lorsque la carte est connectée via USB). Le shell s'exécute sur le Core 0 et communique avec la boucle d'émulation du Core 1 via des drapeaux partagés dans la structure de contexte Z80CPU. Le shell de débogage n'est disponible que dans la variante firmware DBGSH, compilée avec le define INCLUDE_DBGSH.
Canaux série USB CDC
Le picoZ80 énumère plusieurs ports série USB CDC lorsqu'il est connecté à un hôte. CDC 0 et CDC 1 desservent les UART physiques / le pont ESP32 et le shell de débogage ICE (CDC 1, variantes DBGSH). CDC 2 et CDC 3 sont les deux canaux (A et B) d'une carte série RS-232C virtuelle — le pilote MZ-8BIO3 ou MZ-1E24 — lorsqu'une est configurée dans config.json. Ces deux ports n'ont aucun UART physique derrière eux : ce sont des ponts à tampon circulaire vers le Z80 SIO émulé, de sorte que les données écrites sur CDC 2/3 côté hôte apparaissent sur le canal A/B du Z80 SIO vu par l'invité, et vice versa. Si aucune carte série n'est configurée, CDC 2 et CDC 3 ne sont pas énumérés.
Architecture
- Entrée/Sortie : Canal USB CDC 1 à 115200 bauds. L'invite du shell est
dbg> . L'historique des commandes (16 entrées) et l'écho des caractères sont supportés.
- Points d'arrêt : Jusqu'à 8 points d'arrêt simultanés stockés dans
cpu->dbgBpAddr[]. Le Core 1 vérifie le tableau de points d'arrêt avant chaque fetch d'opcode ; en cas de correspondance, il met cpu->hold = true et signale le Core 0 via dbgBpHit.
- Pas à pas : La commande
step définit cpu->dbgStepCount. Le Core 1 décrémente ce compteur après chaque instruction, se mettant automatiquement en pause lorsqu'il atteint zéro. L'état des registres avant/après et l'instruction désassemblée sont affichés pour chaque pas.
- Trace d'exécution : Un tampon circulaire de 512 entrées (
cpu->dbgTrace[]) enregistre PC, opcode et registre de drapeaux pour chaque instruction exécutée lorsque le traçage est activé. Chaque entrée de 32 bits encode [31:16]=PC, [15:8]=opcode, [7:0]=registre F.
- Accès mémoire : L'accès mémoire physique (
dm p, wm p) effectue de vrais cycles bus Z80 via les machines d'état PIO. L'accès virtuel (dm v, wm v) lit/écrit directement la PSRAM. Le mode automatique (wm sans qualificatif) suit la carte mémoire. L'accès RP2350 (dm r) lit l'espace d'adressage du microcontrôleur hôte avec validation de plage.
- Hold/Release : La commande
hold met cpu->hold = true. Le Core 1 acquitte via cpu->holdAck, garantissant que le CPU est au repos avant que le shell n'accède à l'état partagé.
- Break : La commande
break met le Core 1 en pause puis affiche le PC courant, l'instruction sur le point d'être exécutée (désassemblée) et l'ensemble complet des registres — le moyen le plus rapide de voir où en est un programme en cours d'exécution, avant de passer en pas à pas ou d'inspecter. go/cont reprend l'exécution.
- Touches rapides et abréviations : Pour réduire la frappe pendant le débogage, les commandes les plus courantes disposent de touches rapides à une lettre —
c=cont, s=step, g=go, b=break, r=regs, h=hold — qui sont résolues avant la correspondance par préfixe, de sorte qu'elles ne sont jamais considérées comme ambiguës. Toute autre commande peut être saisie sous la forme de son plus court préfixe unique (par ex. ste=step, sta=status, dis=disassemble) ; un préfixe ambigu liste les candidats, et un nom entièrement saisi l'emporte toujours.
Référence des Commandes
| Commande |
Syntaxe |
Description |
help |
help |
Lister toutes les commandes |
regs |
regs |
Afficher tous les registres Z80, drapeaux et compteur de cycles |
dm |
dm <p|f|v|r> <addr> [len] |
Dump mémoire (physique / fetch / virtuel / RP2350) |
search |
search [p|v] <start> <end> <hex..>|"text" |
Rechercher en mémoire un motif d’octets ou une chaîne ASCII. p = bus physique, v = PSRAM virtuelle, omettre pour mappé. Les correspondances sont affichées avec 8 octets de contexte. Le CPU est automatiquement mis en pause pour les accès physiques/mappés. Motif jusqu’à 32 octets |
cmp |
cmp [f] <phys> <virt> <len> |
Comparer la mémoire bus physique avec la PSRAM virtuelle |
dis |
dis [p|v] [addr] [count] |
Désassembler du code Z80 |
asm |
asm [addr] |
Assembleur Z80 interactif |
memmap |
memmap [block] |
Afficher la table de pointeurs de banques mémoire |
memptr |
memptr [addr] |
Afficher la table memPtr en PSRAM |
iomap |
iomap [port] |
Afficher la table des handlers de ports E/S |
status |
status |
Statut système (fréquence CPU, PSRAM, uptime) |
ver |
ver |
Version firmware et informations de partition |
drivers |
drivers |
Lister les pilotes et interfaces actifs |
hold |
hold |
Mettre en pause l’émulation CPU |
release |
release |
Reprendre l’émulation CPU |
break |
break |
Arrêter le Z80 en cours d’exécution et indiquer où il s’est arrêté — PC, l’instruction (octets + désassemblage) sur le point d’être exécutée, et un dump complet des registres. Contrairement à hold (qui met en pause silencieusement), break affiche l’état pour que vous puissiez voir exactement où en est l’exécution (par ex. lorsqu’elle est bloquée dans une boucle). Réémettre break réaffiche l’état. Reprendre avec go/cont ou exécuter en pas à pas avec step. Expire (~3 s) si le Z80 est maintenu en reset ou si son horloge est coupée |
go |
go |
Continuer (relâcher le hold, points d’arrêt actifs) |
cont |
cont |
Alias pour go. Continuer l’exécution (relâcher le hold, points d’arrêt actifs) |
step |
step [n] |
Pas à pas de n instructions |
bp |
bp <addr> |
Définir un point d’arrêt (max 8) |
bc |
bc <n|*> |
Effacer le point d’arrêt n ou tous |
bl |
bl |
Lister les points d’arrêt |
wm |
wm [p|v] <addr> <byte>... |
Écrire en mémoire (physique/virtuelle/auto) |
fill |
fill [p|v] <addr> <len> [w|d] <val> |
Remplir la mémoire avec une valeur constante |
copy |
copy <pv|fp|vp> <src> <len> <dst> |
Copier la mémoire entre physique et virtuelle |
memtest |
memtest <addr> <len> [pattern] |
Tester la mémoire physique (écriture+lecture, écriture+fetch, entrelacé) |
in |
in <port> |
Lire un port E/S Z80 |
out |
out <port> <byte> |
Écrire sur un port E/S Z80 |
trace |
trace <on|off|dump [n]|clear|rt|byte ...> |
Contrôle de la trace d’exécution ; rt active la sortie de trace en temps réel ; byte active le traçage par octet |
verify |
verify <on|off> |
Activer/désactiver la vérification complète du fetch d’opcode |
fwait |
fwait <0-4> |
Forcer des wait states supplémentaires pour le fetch M1 ; 0 = désactivé (par défaut) |
iowait |
iowait <0-8> |
Forcer des wait states supplémentaires pour les cycles E/S ; 0 = désactivé (par défaut) |
corrupt |
corrupt [clear] |
Afficher ou effacer les corruptions de fetch détectées |
fdctrace |
fdctrace <on|off|dump> |
Activer/désactiver la trace E/S du FDC ; dump affiche les 64 dernières opérations |
qdtrace |
qdtrace <on|off|dump> |
Activer/désactiver la trace E/S du Quick Disk ; dump affiche les 64 dernières opérations |
piodbg |
piodbg [clear] |
Afficher les diagnostics matériels PIO du RP2350 (FDEBUG, FSTAT, FIFO, PCs, GPIO) ; clear réinitialise les drapeaux persistants |
load |
load <p|v> <file> <addr> [len] [ofs] |
Charger un fichier depuis la carte SD de l’ESP32 en mémoire Z80. p = bus physique, v = banque PSRAM virtuelle 0. file relatif à /sdcard/. Si len est omis, le fichier entier est chargé (jusqu’à 64KB) ; si spécifié, max 1MB. ofs optionnel pour l’offset fichier. Le CPU est automatiquement mis en pause pour les écritures physiques. Utilise la banque PSRAM 63 comme tampon de travail |
save |
save <p|pf|v> <file> <addr> <len> |
Sauvegarder la mémoire Z80 dans un fichier sur la carte SD de l’ESP32. p = bus physique, pf = fetch physique (M1), v = banque PSRAM virtuelle 0. file relatif à /sdcard/. Max 64KB. Le CPU est automatiquement mis en pause pour les lectures physiques. Rafraîchissement DRAM périodique pendant les lectures physiques |
dir |
dir [path] |
Lister les fichiers sur la carte SD de l’ESP32. Le chemin optionnel est relatif à /sdcard/. Affiche les noms de fichiers et tailles |
echo |
echo [on|off] |
Activer/désactiver l’écho terminal |
reset |
reset |
Forcer un reset Z80 |
set |
set <reg|flags|memmap|memptr|iomap> <idx> <val> |
Modifier un registre Z80, des drapeaux, une carte mémoire, un memPtr ou une entrée de carte E/S à l’exécution |
hist |
hist [n] |
Afficher l’historique des commandes (préservé entre les sessions via NVS de l’ESP32) |
savehst |
savehst |
Forcer la sauvegarde de l’historique des commandes en NVS de l’ESP32 |
ipl |
ipl |
Effectuer un reset IPL (mode BST) en basculant le bit 3 du Port C du 8255 PPI. Réinitialise en mode boot sans reset Z80 complet |
mmutrace |
mmutrace |
Dump des informations de trace spécifiques à la machine (état MMU, snapshots de registres E/S). La sortie varie selon le persona via le handler de trace enregistré |
intcount |
intcount |
Afficher le compteur d’acquittements d’interruption et l’état d’interruption courant |
psync |
psync [start end] |
Synchroniser la mémoire physique vers la PSRAM. Plage d’adresses optionnelle ; par défaut tout l’espace d’adressage |
dskimage |
dskimage read <filename> [cylinders] [heads] / dskimage write <filename> |
Imager une disquette physique vers un fichier DSK sur la carte SD (read), ou écrire un fichier DSK depuis la carte SD vers une disquette physique (write). dskimage <filename> effectue par défaut une lecture (rétrocompatible). Détection automatique de la géométrie si omise |
busdiag |
busdiag |
Afficher les diagnostics bus (état PIO, niveaux de signaux, contention bus) |
fdcimage |
fdcimage |
Afficher le statut et la progression de l’imagerie FDC |
fdcdiag |
fdcdiag |
Afficher les informations de diagnostic FDC (état du contrôleur, dump des registres) |
gadiag |
gadiag |
Afficher les informations de diagnostic du gate array (état des commandes, routage des interruptions) |
Touches rapides et abréviations. Les commandes n'ont pas besoin d'être saisies en entier. Les six commandes les plus utilisées disposent de touches rapides à une lettre — c (cont), s (step), g (go), b (break), r (regs) et h (hold) — et toute autre commande peut être saisie sous la forme de son plus court préfixe unique (par exemple ste pour step, sta pour status, dis pour disassemble). Un nom de commande entièrement saisi a toujours la priorité, et un préfixe ambigu affiche la liste des commandes correspondantes.
Coprocesseur ESP32
Le module ESP32-S3-PICO-1 agit comme coprocesseur gérant toutes les fonctions réseau et stockage. Il communique avec le RP2350 via deux interfaces :
- FSPI (50MHz, SPI 4 fils) — Protocole IPC Binaire v1.1 — transfert de données en masse à haute vitesse (images ROM, lectures/écritures de secteurs disque, téléchargement de fichier de configuration). Le protocole utilise un en-tête de trame binaire fixe de 64 octets avec vérification d'intégrité CRC32 (remplaçant l'ancien checksum XOR). Les canaux DMA sont pré-alloués à l'initialisation et jamais libérés, éliminant le surcoût de claim/unclaim par transfert et les conditions de course. Les transferts de secteurs en rafale permettent jusqu'à 16 × 512 octets (8KB) en une seule transaction SPI, améliorant significativement les temps de chargement d'images disquette et QuickDisk. Le canal DMA RX est élevé en HAUTE PRIORITÉ pour prévenir le débordement FIFO causé par la contention du bus QMI PSRAM du Core 1.
- UART (460,8 kbauds) — protocole commande/réponse pour les messages de contrôle, requêtes de statut et échanges de données courts.
Modes Réseau
Le firmware ESP32 supporte trois modes réseau, sélectionnés à la compilation via des fichiers sdkconfig pré-construits :
| Mode |
Fichier de config |
WiFi |
USB NCM |
Console |
FCC/RED requis |
| WiFi uniquement |
sdkconfig.mode_wifi_only |
Oui |
Non |
USB Serial/JTAG |
Oui |
| WiFi + NCM |
sdkconfig.mode_wifi_and_ncm |
Oui |
Oui |
TinyUSB CDC-ACM |
Oui |
| NCM uniquement |
sdkconfig.mode_ncm_only |
Non |
Oui |
TinyUSB CDC-ACM |
Non |
USB NCM (Network Control Model) présente un adaptateur Ethernet CDC-NCM sur le port USB OTG de l'ESP32-S3 (GPIO 19/20). Un périphérique USB composite expose à la fois un port série CDC-ACM (pour la journalisation de débogage) et l'interface réseau NCM. Le serveur DHCP intégré attribue à l'hôte une adresse IP depuis le sous-réseau
192.168.7.0/24, le picoZ80 étant accessible à
192.168.7.1. La durée du bail est de 120 minutes.
En mode WiFi+NCM, le serveur HTTP écoute sur
INADDR_ANY:80 et dessert les deux interfaces simultanément. Le WiFi se connecte de manière asynchrone, donc l'interface USB NCM est disponible immédiatement à la mise sous tension.
Lorsque seul le NCM est activé, la radio WiFi est complètement désactivée, la page WiFi Manager est supprimée de l'interface web, et le titre du panneau de statut du Dashboard passe de "WiFi Configuration" à "Network Configuration" (affichant le statut USB NCM au lieu des détails SSID/WiFi). Le réseau d'adaptation d'antenne de l'ESP32-S3 n'a pas besoin d'être assemblé sur le PCB.
Interface Carte SD
L'ESP32 gère la carte SD via son interface SPI. La carte SD est montée en FAT32 et tout accès fichier depuis le RP2350 est médié par l'ESP32 — le RP2350 envoie des commandes d'E/S fichier via le lien FSPI/UART et l'ESP32 effectue les opérations de lecture/écriture FAT32 réelles.
La carte SD est également directement accessible au serveur web de l'ESP32, qui sert les fichiers depuis le répertoire
webfs/ et permet au gestionnaire de fichiers de parcourir et modifier le contenu de la carte via HTTP.
Serveur Web
L'ESP32 exécute un serveur HTTP sur le port 80 (pas de TLS — usage réseau local uniquement). Tous les assets web (HTML, CSS, JavaScript) sont servis depuis le répertoire
webfs/ de la carte SD, permettant la mise à jour de l'interface web sans reflasher le firmware ESP32. Le serveur web gère :
- La diffusion d'assets web statiques depuis le répertoire
webfs/ de la carte SD.
- Les endpoints d'API REST pour les données JSON (statut système, lecture/écriture de configuration, opérations sur les fichiers).
- Les endpoints de téléchargement de firmware OTA pour le RP2350 et l'ESP32.
- La connexion WebSocket pour les mises à jour de statut du Dashboard en temps réel.
Protocole de Commande RP2350 ↔ ESP32
Le RP2350 (Core 0) communique avec l'ESP32 en utilisant un protocole commande/réponse simple via le lien UART. Les commandes sont des opcodes d'un seul octet avec des octets de charge utile optionnels. L'ESP32 acquitte chaque commande avec un octet de statut suivi de toute donnée de réponse.
Catégories de commandes courantes :
- E/S fichier — ouvrir, lire, écrire, fermer, listing de répertoire, stat fichier.
- Configuration — demander le contenu de config.json, écrire la configuration mise à jour, demande de rechargement.
- Disque — monter/démonter une image disque, lire/écrire un secteur (relayé depuis l'émulation WD1773 et QDDrive). Les noms de fichiers des images disquette et QuickDisk actuellement montées sont suivis par l'ESP32 et affichés dans le menu Actions de l'interface web.
- Système — requête de version, demande de redémarrage, lecture/écriture NVS.
L'interface FSPI est utilisée pour les transferts en masse dont la charge utile est trop volumineuse pour l'UART (chargements d'images ROM, données de secteurs disque), tandis que l'UART gère toutes les commandes de contrôle.
Commandes IPC Réseau
L'implémentation réseau Celestite Phase 2 ajoute cinq commandes IPC inter-cœurs que le RP2350 utilise pour demander des opérations réseau à l'ESP32. Ces commandes sont transmises via le lien FSPI/UART et l'ESP32 effectue les opérations BSD socket correspondantes. Les connexions non bloquantes utilisent select() avec un timeout, et des drapeaux en attente par socket suivent les opérations en cours.
| Commande |
Opcode |
Description |
IPCF_CMD_NET_CFG |
0x10 |
Obtenir la configuration réseau de l’ESP32 — retourne l’adresse IP, la passerelle, le masque de sous-réseau et l’adresse MAC |
IPCF_CMD_NET_SOCK |
0x11 |
Opération de cycle de vie socket — ouvrir, connecter, écouter, fermer ou déconnecter un socket |
IPCF_CMD_NET_SEND |
0x12 |
Envoyer des données sur un socket ouvert |
IPCF_CMD_NET_RECV |
0x13 |
Recevoir des données depuis un socket ouvert |
IPCF_CMD_NET_PING |
0x14 |
Requête ICMP echo (ping) |
Les commandes socket W5100 supportées à travers cette couche IPC sont : OPEN, CONNECT, LISTEN, SEND, RECV, CLOSE et DISCON. L'ESP32 les traduit en appels standard de l'API BSD socket (
socket(),
connect(),
listen(),
send(),
recv(),
close(),
shutdown()), permettant à la carte Celestite de communiquer avec des services réseau tels que le serveur de fichiers
netfs.py.
Watchdog et Diagnostics de Démarrage
Le firmware du RP2350 utilise un timer watchdog matériel pour détecter et récupérer des blocages au démarrage et des stalls de la boucle principale. Le watchdog est activé tôt dans la séquence de démarrage avec un timeout de 30 secondes et est relancé (watchdog_update()) à chaque jalon majeur. Si une étape de démarrage ou une itération de la boucle principale prend plus longtemps que le timeout, le watchdog réinitialise automatiquement le RP2350.
Suivi de la Progression du Démarrage
La progression du démarrage est suivie à l'aide des registres scratch du watchdog du RP2350, qui survivent aux resets watchdog (mais pas aux resets de mise sous tension). Cela permet au firmware de déterminer, après un reset watchdog, exactement quelle étape de démarrage a été atteinte avant le blocage.
| Registre Scratch |
Nom |
Contenu |
scratch[0–3] |
Historique de démarrage |
Les quatre dernières tentatives de reset — chaque entrée encode (attempt_count << 24) | (stage << 16) | (resetCause & 0xFFFF). Les entrées se décalent à chaque reset watchdog : [0]←[1]←[2]←[3]←courant. |
scratch[4] |
Diagnostics SPI |
Compteurs de diagnostic empaquetés pour le lien FSPI : breadcrumbs, type de message, compteurs de timeout T1/T3, compteur de trames invalides et compteur OK. |
scratch[5] |
Marqueur magique |
Défini à 0xB00710BE pour indiquer que les registres scratch contiennent des données de progression de démarrage valides. |
scratch[6] |
Étape courante |
Le code d’étape de démarrage le plus récent (voir le tableau ci-dessous). |
scratch[7] |
Cause du reset |
Le code de cause de reset du contrôleur de reset matériel. |
Les codes d'étape de démarrage progressent de
0x01 (début) jusqu'à
0x10 (boucle principale atteinte). Les sous-étapes au sein de la boucle principale (
0x11–0x17) et le traitement des commandes inter-cœurs (
0x20–0x27) fournissent un suivi fin :
| Code |
Étape |
Description |
0x01 |
BOOTP_START |
Point d’entrée atteint |
0x02 |
BOOTP_CLK_SET |
Horloge système configurée |
0x03 |
BOOTP_PSRAM_INIT |
Initialisation PSRAM démarrée |
0x04 |
BOOTP_PSRAM_OK |
PSRAM initialisée avec succès |
0x05 |
BOOTP_STDIO_INIT |
USB stdio initialisé |
0x06 |
BOOTP_PIO_INIT |
Machines d’état PIO chargées |
0x07 |
BOOTP_Z80_INIT |
Contexte CPU Z80 initialisé |
0x08 |
BOOTP_USB_INIT |
Pont USB initialisé |
0x0A |
BOOTP_ESP_HS_SYNC |
Synchronisation du handshake SPI ESP32 |
0x0B |
BOOTP_CORE1_LAUNCH |
Core 1 lancé |
0x0D |
BOOTP_FSPI_INIT |
IPC binaire FSPI initialisé |
0x0E |
BOOTP_ESP_INIT |
Communication ESP32 prête |
0x10 |
BOOTP_MAIN_LOOP |
Boucle principale atteinte |
0x11–0x17 |
Sous-étapes boucle principale |
USB poll, inter-cœurs, SPI NOP/CMD, tâches |
0x20–0x27 |
Commandes inter-cœurs |
Chargement disquette, chargement QD, chargement RAMFILE, E/S fichier |
Journal Persistant PSRAM (plogf)
Les derniers 4KB des 8MB de PSRAM (adresse 0x117FF000) sont réservés pour un journal de débogage persistant qui survit aux resets watchdog. La macro plogf() écrit des messages de type printf dans ce tampon pendant le démarrage, avant que l'USB ne soit disponible pour la sortie debugf() normale. Au prochain démarrage réussi, la fonction dump_plog() affiche les messages capturés sur la console de débogage puis efface le tampon. Le journal utilise une structure simple : un marqueur magique de 4 octets (0x504C4F47 = "PLOG"), un compteur de longueur de 4 octets et un tampon texte circulaire de 3840 octets.
Diagnostics de Fautes
Le firmware installe des handlers de fautes Cortex-M33 pour les fautes matérielles, les fautes de gestion mémoire, les fautes bus et les fautes d'utilisation. Lorsqu'une faute se produit, le handler sauvegarde un snapshot diagnostique complet dans les derniers 256 octets de la PSRAM (adresse 0x117FFF00) avec un marqueur magique (0xFA017000), le type de faute, tous les registres pertinents (PC, LR, SP, R0–R3, R12, PSR), le Configurable Fault Status Register (CFSR), le Hard Fault Status Register (HFSR), le Bus Fault Address Register (BFAR), le Memory Management Fault Address Register (MMFAR) et l'identifiant du cœur. Le handler entre ensuite dans une boucle infinie, permettant au watchdog de déclencher un reset. Au prochain démarrage, le firmware vérifie la présence d'un diagnostic de faute valide et affiche les informations capturées via debugf(), permettant une analyse post-mortem sans nécessiter une session de débogueur en direct.
Effacement de la Configuration Flash
Le mécanisme de mise à jour OTA du RP2350 supporte deux opérations supplémentaires au-delà du téléchargement de firmware :
- Effacer App Config (
FW_CFGCLEAR_ID = 0xB1D7E5FA) — efface la partition App Config (images ROM et JSON minifié) associée au slot firmware cible. Ceci force le firmware à relire config.json depuis la carte SD au prochain démarrage, ce qui est nécessaire lorsque le schéma de configuration a changé entre les versions de firmware.
- Effacer l'En-tête Flash (
FW_HDRCLEAR_ID = 0xC2E8F6AB) — réinitialise l'en-tête de partition flash aux valeurs d'usine. La configuration du bootloader (partition 0) est préservée, mais toutes les métadonnées des partitions applicatives sont reconstruites à partir de zéro. Utilisez ceci lorsque la table de partitions est corrompue ou lors d'un retour à une version antérieure du firmware qui attend une disposition de partitions différente.
Les deux opérations sont déclenchées depuis les cases à cocher de la page web OTA du RP2350 et sont exécutées par le bootloader pendant le processus de mise à jour du firmware.
Débogage SWD — RP2350
Le RP2350 supporte le débogage complet au niveau source via ARM Serial Wire Debug (SWD). Connectez une sonde compatible CMSIS-DAP (Raspberry Pi Debug Probe, Black Magic Probe ou similaire) aux broches 1 (SWCLK), 2 (SWDIO) et 5 (GND) du connecteur de débogage.
Configuration OpenOCD
Le picoZ80 nécessite une petite modification du script cible OpenOCD standard du RP2350 pour activer le débogage SMP avec des ports GDB séparés par cœur :
sudo cp /usr/local/share/openocd/scripts/target/rp2350.cfg \
/usr/local/share/openocd/scripts/target/rp2350_tzpu.cfg
Éditez rp2350_tzpu.cfg — trouvez la ligne target smp à l'intérieur du bloc if {[string compare $_USE_CORE SMP] == 0} et supprimez le # initial :
# Before:
#target smp $_TARGETNAME_0 $_TARGETNAME_1
# After:
target smp $_TARGETNAME_0 $_TARGETNAME_1
Ce simple changement fait que OpenOCD enregistre le Core 0 sur le port GDB 3333 et le Core 1 sur le port GDB 3334, permettant des sessions GDB indépendantes par cœur. Lancez OpenOCD avant de démarrer GDB :
openocd -f interface/cmsis-dap.cfg -f target/rp2350_tzpu.cfg -c "adapter speed 5000"
Configuration GDB
Ajoutez ce qui suit à ~/.gdbinit (avec les chemins absolus correspondant à l'emplacement de votre projet) pour permettre le chargement automatique des fichiers .gdbinit par répertoire :
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
Débogage du 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
Débogage du Firmware Principal
# 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
La commande GDB xac <address> <count> est définie dans les fichiers .gdbinit.3333 / .gdbinit.3334. Elle dump la mémoire en sortie combinée hexadécimale et ASCII et est utile pour inspecter le contenu des banques PSRAM et l'état des périphériques mappés en mémoire.
Débogage USB de l'ESP32
Le coprocesseur ESP32-S3 dispose d'une interface USB-JTAG intégrée — aucune sonde de débogage externe n'est requise. Connectez un câble USB depuis le PC hôte directement au port USB de l'ESP32 sur la carte 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
Assurez-vous que l'ELF a été compilé à partir de la même révision source que le firmware exécuté sur le dispositif, afin que les symboles et adresses soient correctement alignés.
Système de Compilation
Le firmware du picoZ80 utilise CMake avec le Raspberry Pi Pico SDK 2.x. Le système de compilation produit le firmware
Bootloader et
Application. L'application est compilée en quatre variantes — deux partitions (Partition 1 à 0x10020000, Partition 2 à 0x10520000) chacune en configuration standard et DBGSH. Les variantes DBGSH ajoutent
INCLUDE_DBGSH aux drapeaux de compilation, activant le shell de débogage complet sur le canal USB CDC 1. Le firmware ESP32 est compilé séparément avec ESP-IDF v5.4, géré via Docker.
La façon la plus rapide d'obtenir un environnement fonctionnel est le script automatisé
setup_picoZ80 (macOS/Linux et Windows), qui installe le SDK et toutes les dépendances et crée des scripts de build prêts à l'emploi — voir le
README et le
Guide du Développeur. Les cibles CMake, les drapeaux et les commandes ci-dessous documentent la compilation sous-jacente que le script automatise, pour ceux qui préfèrent la configurer manuellement.
Cibles de Compilation CMake
| Cible |
Sortie |
Adresse Flash |
Notes |
Bootloader |
Bootloader.elf, Bootloader.uf2 |
0x10000000 |
|
BaseZ80_0x10020000 |
BaseZ80_0x10020000.elf, .bin |
0x10020000 (Slot 1) |
Standard (pas de shell de débogage) |
BaseZ80_0x10520000 |
BaseZ80_0x10520000.elf, .bin |
0x10520000 (Slot 2) |
Standard (pas de shell de débogage) |
BaseZ80_DBGSH_0x10020000 |
BaseZ80_DBGSH_0x10020000.elf, .bin |
0x10020000 (Slot 1) |
DBGSH — inclut le shell de débogage ICE |
BaseZ80_DBGSH_0x10520000 |
BaseZ80_DBGSH_0x10520000.elf, .bin |
0x10520000 (Slot 2) |
DBGSH — inclut le shell de débogage ICE |
Les modèles
SharpZ80,
AmstradZ80,
TatungZ80 et
OpenZ80 suivent le même schéma de slot / DBGSH, p. ex.
OpenZ80_0x10020000,
OpenZ80_0x10020000_DBGSH,
OpenZ80_0x10520000 et
OpenZ80_0x10520000_DBGSH (chacun produit
.elf,
.bin,
.hex et
.map ; les slots d'application utilisent un simple
.bin, pas UF2). Compilez un seul modèle avec le filtre
build_tzpuPico.sh, p. ex.
build_tzpuPico.sh open.
Drapeaux de Compilation CMake Principaux
| Drapeau |
Effet |
INCLUDE_SHARP_DRIVERS |
Compile tous les pilotes de périphériques 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 |
Compile les pilotes de périphériques Amstrad PCW (PCW9512, uPD765). |
INCLUDE_TATUNG_DRIVERS |
Compile les pilotes de périphériques Tatung Einstein (EinsteinTC01, EinsteinFDC, WD1770). |
INCLUDE_OPEN_DRIVERS |
Compile le persona expérimentateur OpenZ80 (Open.c) et les cartes d’interface indépendantes de la machine (MZ-1R12/1R18/1R23/1R37, PIO-3034, MZ8BIO3, MZ1E24, Z80SIO, MZ-1E05, WD1773, Celestite). |
TARGET_MODEL_TATUNG |
Définit le Tatung Einstein comme modèle cible exclusif (utilisé dans le build TatungZ80). |
TARGET_MODEL_OPEN |
Définit le persona expérimentateur OpenZ80 comme modèle cible exclusif (utilisé dans le build OpenZ80 ; active INCLUDE_OPEN_DRIVERS). |
INCLUDE_DBGSH |
Compile le shell de débogage ICE sur le canal USB CDC 1. Présent uniquement dans les variantes de build DBGSH. |
CMAKE_BUILD_TYPE=Debug |
Active les symboles de débogage et désactive l’optimisation. Requis pour le débogage au niveau source avec GDB. |
CMAKE_BUILD_TYPE=Release |
Optimisation complète (-O3). Utilisé pour le firmware de production. |
Commandes de Compilation
# 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
Le script build_tzpuPico.sh incrémente automatiquement le numéro de version lors d'une compilation réussie et copie les fichiers de sortie versionnés vers fw/uf2/ (UF2 du bootloader) et fw/bin/ (binaire applicatif pour OTA). L'UF2 du Bootloader est utilisé uniquement pour le flashage initial par stockage de masse USB. Les binaires des slots applicatifs utilisent le format binaire brut (pas UF2) car ils résident à des adresses Flash non standard.
Sélection du Mode Réseau ESP32
Pour changer de mode réseau, copiez le fichier de configuration pré-construit approprié vers sdkconfig avant la compilation :
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
Sites de Référence
Avis Réglementaire sur les Communications Sans Fil
Cet appareil intègre un module sans fil ESP32-S3-PICO-1 capable d'émettre dans la bande ISM 2,4 GHz, ce qui en fait un émetteur intentionnel au titre des réglementations de radiofréquence dans le monde entier (incluant le FCC Part 15 Subpart C aux États-Unis et la Directive Équipements Radio 2014/53/UE dans l'Union Européenne) lorsque le firmware WiFi est installé.
Configuration Livrée
Tel que livré, la carte picoZ80 est flashée avec le firmware
NCM uniquement (
sdkconfig.mode_ncm_only). Dans cette configuration, la radio WiFi est complètement désactivée et les composants du réseau d'adaptation d'antenne de l'ESP32-S3 ne sont pas assemblés sur le PCB. Comme aucune émission RF n'a lieu, l'appareil
n'est pas un émetteur intentionnel et ne nécessite pas de certification FCC, CE/RED ou équivalente. Il peut être vendu, distribué ou offert sans autorisation réglementaire.
Ajout du WiFi
Les utilisateurs finaux peuvent assembler le réseau d'adaptation d'antenne et flasher le firmware avec WiFi activé (
sdkconfig.mode_wifi_only ou
sdkconfig.mode_wifi_and_ncm) pour un usage personnel, expérimental ou éducatif. Une fois le WiFi activé, l'appareil devient un émetteur intentionnel et les règles suivantes s'appliquent :
Bien que le module ESP32-S3-PICO-1 lui-même possède des certifications réglementaires préexistantes (FCC, CE et autres), ces certifications au niveau module
ne s'étendent pas automatiquement à un produit fini qui intègre le module. L'exemption de module pré-certifié permet aux
amateurs individuels de construire un nombre limité d'appareils pour un
usage personnel, expérimental ou éducatif sans obtenir d'autorisation d'équipement séparée.
Limitations Importantes
- Les appareils avec firmware WiFi ne doivent pas être vendus, proposés à la vente, offerts ou autrement distribués à des tiers à moins que le produit fini n'ait été testé de manière indépendante et n'ait obtenu sa propre autorisation d'équipement (par ex. FCC ID, marquage CE avec évaluation d'un Organisme Notifié) dans la juridiction concernée.
- La construction de ce projet avec WiFi activé pour un usage personnel en quantités limitées est généralement autorisée sous les dispositions d'usage amateur et expérimental (par ex. FCC § 15.23), à condition que l'appareil ne cause pas d'interférences nuisibles.
- La vente commerciale avec WiFi activé nécessite une certification FCC/RED (ou équivalente) complète au niveau produit.
- Les exigences réglementaires varient selon les pays. Les constructeurs en dehors des États-Unis doivent consulter leur autorité nationale de radiofréquence pour les règles applicables.
Responsabilité du Constructeur
Il incombe uniquement au constructeur de s'assurer que tout appareil construit à partir de ces conceptions est conforme à toutes les réglementations de radiofréquence applicables dans sa juridiction. L'auteur fournit ces conceptions pour un usage personnel, éducatif et amateur et ne garantit pas qu'un appareil construit à partir de celles-ci satisfait aux exigences réglementaires pour une distribution commerciale.