picoZ80 Guía Técnica
picoZ80 Guía Técnica
Esta guía documenta la arquitectura de hardware del picoZ80, la interfaz de bus PIO del RP2350, el modelo de memoria, la referencia de configuración JSON, el framework de dispositivos virtuales y los procedimientos de depuración. Está destinada a desarrolladores que deseen comprender los aspectos internos, escribir nuevos controladores, portar el firmware a una nueva máquina host o depurar problemas a nivel de firmware.
Para la configuración de usuario final y el uso de la interfaz web, consulte el
picoZ80 User Manual. Para la descripción general del proyecto e instrucciones de compilación, consulte la
página del proyecto picoZ80.
Arquitectura de Hardware
El picoZ80 integra cinco subsistemas en una sola PCB compacta diseñada para caber dentro del formato de un paquete DIP-40. Toda la lógica opera a 3.3V; la interfaz del bus Z80 se encarga de la conversión de niveles y la corriente de excitación para el bus de 5V del host.
Diagrama de Bloques 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│ │
│ └────────┬────────┘ │
│ │ 5V bus (A0–A15, D0–D7, MREQ, IORQ, RD, WR...) │
└────────────────┼────────────────────────────────────────────────────────┘
│
┌───────┴───────┐
│ Host Z80 │
│ DIP-40 socket│
│ (legacy │
│ computer) │
└───────────────┘
Componentes Principales
| Componente |
Dispositivo |
Función |
| MCU Principal | RP2350B (QFN-80) | Dual Cortex-M33, 150MHz (hasta 300MHz OC), 512KB SRAM, 12 state machines PIO, 48 pines GPIO |
| Flash | W25Q128 (16MB SPI) | Bootloader, slots de firmware duales, particiones de configuración |
| PSRAM | 8MB SPI PSRAM | 64 × 64KB bancos RAM/ROM para el espacio de direcciones Z80 |
| Coprocesador | ESP32-S3-PICO-1 | WiFi, tarjeta SD, servidor web, OTA |
| Hub USB | CH334F | Hub USB, puente para actualización de firmware |
| Fuente de alimentación | TLV62590BV | Convertidor buck síncrono 5V → 3.3V |
Asignación GPIO del RP2350B
El paquete QFN-80 del RP2350B proporciona 48 pines GPIO. El picoZ80 utiliza prácticamente todos los pines. La asignación está fijada en el diseño de la placa y se refleja en los programas PIO:
| Rango GPIO |
Señales |
Dirección |
| GPIO 0–15 |
A0–A15 (Bus de Direcciones Z80) |
Salida (controlado por PIO) |
| GPIO 16–23 |
D0–D7 (Bus de Datos Z80) |
Bidireccional (PIO tri-state) |
| GPIO 24 |
MREQ |
Salida |
| GPIO 25 |
IORQ |
Salida |
| GPIO 26 |
RD |
Salida |
| GPIO 27 |
WR |
Salida |
| GPIO 28 |
M1 |
Salida |
| GPIO 29 |
RFSH |
Salida |
| GPIO 30 |
BUSREQ |
Entrada |
| GPIO 31 |
BUSACK |
Salida |
| GPIO 32 |
HALT |
Salida |
| GPIO 33 |
INT |
Entrada |
| GPIO 34 |
NMI |
Entrada |
| GPIO 35 |
WAIT |
Salida |
| GPIO 36 |
CLK |
Entrada (reloj del host) |
| GPIO 37 |
RESET |
Entrada |
| 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 |
Arquitectura de Firmware
El firmware del RP2350 está construido con el Raspberry Pi Pico SDK 2.x orientado a la plataforma RP2350-arm-s. El firmware se divide en dos ejecutables independientes: el Bootloader y la Aplicación.
Disposición de la Memoria Flash
| Partición |
Rango de Direcciones |
Tamaño |
Contenido |
| Bootloader |
0x10000000 – 0x1001FFFF |
128KB |
Puente USB, actualización de firmware, selector de partición |
| App Slot 1 |
0x10020000 – 0x1051FFFF |
5MB |
Firmware Z80 — aplicación activa (slot 1) |
| App Slot 2 |
0x10520000 – 0x10A1FFFF |
5MB |
Firmware Z80 — aplicación activa (slot 2) |
| App Config 1 |
0x10A20000 – 0x10C9FFFF |
2.5MB |
Imágenes ROM + JSON de configuración minificado (slot 1) |
| App Config 2 |
0x10CA0000 – 0x10F1FFFF |
2.5MB |
Imágenes ROM + JSON de configuración minificado (slot 2) |
| General Config |
0x10F20000 – 0x10FFEFFF |
892KB |
Configuración principal, espacio temporal |
| Partition Table |
0x10FFF000 – 0x11000000 |
4KB |
Número de slot activo, checksums, metadatos |
Responsabilidades Dual-Core
Los dos núcleos Cortex-M33 tienen responsabilidades completamente separadas y se comunican mediante una cola de mensajes inter-core (queue_t). Esta separación asegura que el trabajo no en tiempo real del Core 0 nunca introduzca jitter en las transacciones del bus Z80 del Core 1.
| Núcleo |
Responsabilidades |
| Core 0 |
Puente serie USB CDC; coordinación de actualización de firmware; E/S de archivos (retransmitida al ESP32 por UART); despacho de comandos ESP32 (cambios de imagen de disco, recargas de configuración, consultas de versión); gestión de particiones; despacho de mensajes inter-core. |
| Core 1 |
Bucle principal de emulación del bus Z80 — se ejecuta exclusivamente. Atiende los FIFOs PIO, resuelve cada transacción de bus contra el mapa de memoria y despacha a: hardware físico del host (PHYSICAL), PSRAM (RAM/ROM) o handler de dispositivo virtual (FUNC). El bucle interno se coloca en SRAM. |
Interfaz de Bus PIO
La interfaz del bus Z80 está implementada completamente en ensamblador PIO del RP2350 (
z80.pio). El RP2350 proporciona tres bloques PIO (PIO 0, PIO 1, PIO 2) cada uno con cuatro state machines — doce state machines en total, de las cuales el firmware Z80 utiliza las doce.
Los programas PIO se ejecutan independientemente de los núcleos Cortex-M33. La interfaz del bus continúa respondiendo de forma determinista incluso cuando el Core 1 está ocupado con accesos a PSRAM o llamadas a funciones de dispositivos virtuales. Las state machines se comunican mediante flags IRQ PIO en lugar de polling, eliminando la latencia entre máquinas.
Tabla de Programas PIO
| PIO |
State Machine |
Programa |
Función |
| 0 |
SM 0 |
z80_addr |
Emite la dirección de 16 bits (A0–A15) en el bus y señala el inicio del ciclo a SM 2. |
| 0 |
SM 1 |
z80_data |
Controla o muestrea D0–D7 con control tri-state; se libera durante BUSRQ. |
| 0 |
SM 2 |
z80_cycle |
Secuenciador de ciclo de bus de nivel superior — orquesta ciclos de fetch, lectura, escritura, E/S y refresco de DRAM. |
| 0 |
SM 3 |
z80_fetch |
Ciclo de fetch de opcode (M1 + MREQ + RD). |
| 1 |
SM 0 |
z80_mem_read |
Ciclo de lectura de memoria (MREQ + RD). |
| 1 |
SM 1 |
z80_mem_write |
Ciclo de escritura de memoria (MREQ + WR). |
| 1 |
SM 2 |
z80_io_read |
Ciclo de lectura de E/S (IORQ + RD). |
| 1 |
SM 3 |
z80_io_write |
Ciclo de escritura de E/S (IORQ + WR). |
| 2 |
SM 0 |
z80_busrq |
Gestiona BUSREQ/BUSACK; libera /IORQ, /MREQ, /RFSH, /M1, /HALT, /WR, /RD. |
| 2 |
SM 1 |
z80_nmi |
Detecta la activación de NMI y señala al Core 1. |
| 2 |
SM 2 |
z80_clk_sync |
Sincroniza las state machines PIO con la señal CLK del Z80 del host. |
| 2 |
SM 3 |
z80_int_ack |
Gestiona ciclos de reconocimiento de interrupción (M1 + IORQ). |
Convenciones de Señales IRQ PIO
La comunicación entre state machines utiliza flags IRQ PIO. El Core 1 monitoriza estos flags en el bucle principal para actuar en cada evento del bus:
| IRQ |
Evento |
| IRQ 0 |
Dirección válida / inicio de ciclo — ha comenzado un nuevo ciclo de bus y A0–A15 están estables. |
| IRQ 1 |
Fase de datos — la dirección del bus de datos ha sido resuelta; D0–D7 deben ser controlados o muestreados. |
| IRQ 2 |
T1 detectado — el flanco de subida de T1 en el ciclo actual. Se utiliza para sincronizar operaciones internas con el reloj del host. |
| IRQ 3 |
Evento RESET — la línea RESET del host ha sido activada. El Core 1 debe reinicializar el estado de emulación. |
| IRQ 4 |
NMI detectado — la línea NMI del host ha sido activada. |
| IRQ 6 |
BUSRQ activo — el host ha activado BUSREQ; PIO está liberando el bus. |
Generación de Wait States
El programa PIO
z80_wait en PIO 2 SM 0 inserta wait states de ciclo T configurables en el bus del host mediante la activación de
/WAIT. El número de wait states adicionales se controla por bloque de memoria o E/S mediante el parámetro
tcycwait en
config.json.
Los wait states son necesarios cuando el RP2350 necesita tiempo adicional para completar un acceso a PSRAM o una llamada a función de dispositivo virtual antes de presentar los datos al bus del host. El parámetro
tcycsync habilita la sincronización T1 (
z80_sync en PIO 2 SM 1), que bloquea la ventana de acceso a PSRAM al flanco de subida T1 de cada ciclo de bus, previniendo la deriva de temporización en aplicaciones que dependen del reloj del host para temporización precisa (cassette, bit-banging serie).
Arquitectura PIO — Cómo se Recrean los Ciclos de Bus
El subsistema de E/S Programable (PIO) del RP2350 es la tecnología clave que permite al picoZ80 recrear la temporización del bus Z80 con precisión de ciclo. Comprender cómo las state machines PIO trabajan juntas es esencial para cualquiera que modifique la interfaz del bus o depure problemas de temporización.
Fundamentos PIO del RP2350
Cada bloque PIO contiene cuatro state machines (SM) independientes que ejecutan pequeños programas desde una memoria compartida de 32 instrucciones. Las state machines se ejecutan independientemente de los núcleos Cortex-M33 a la frecuencia del reloj del sistema (hasta 300 MHz). Recursos PIO clave utilizados por el picoZ80:
- TX FIFO — una cola de 4 entradas desde la CPU hacia la state machine. El código C en el Core 1 envía datos (direcciones, palabras de control, instrucciones inyectadas) al FIFO; el programa PIO los extrae usando
out o pull.
- RX FIFO — una cola de 4 entradas desde la state machine hacia la CPU. El PIO envía muestras del bus de datos al FIFO usando
in; el Core 1 las lee después de que cada ciclo de bus se complete.
- Flags IRQ — 8 flags (IRQ 0–7) compartidos entre todas las state machines dentro de un bloque PIO. Los flags también pueden verse entre bloques PIO (IRQ 0–3 en un bloque se mapean a IRQ 4–7 en bloques adyacentes). Las state machines usan
irq set / irq wait / irq clear para sincronizarse entre sí y con el código C.
- Registros scratch X e Y — dos registros de 32 bits por SM utilizados para contadores de bucle y valores temporales.
out exec — una instrucción especial que extrae un valor del TX FIFO y lo ejecuta como instrucción PIO. Este es el mecanismo por el cual el código C controla dinámicamente las secuencias de ciclo de bus (ver más abajo).
set pins / out pins — controlan pines GPIO directamente. set usa un valor inmediato de 5 bits; out desplaza datos del registro de desplazamiento de salida (OSR) hacia los pines.
in pins — muestrea los pines GPIO en el registro de desplazamiento de entrada (ISR), y luego auto-envía al RX FIFO.
wait gpio — detiene la SM hasta que un pin GPIO específico alcanza un nivel determinado. Se usa extensivamente para sincronizarse con la señal de reloj CLK del Z80 del host.
- Side-set — permite que uno o dos pines GPIO se controlen como efecto lateral de cualquier instrucción, sin usar un ciclo de instrucción. El picoZ80 usa side-set de 2 bits para controlar
/RD y /WR simultáneamente con otras operaciones.
- JMP PIN — salto condicional basado en el nivel de un pin GPIO designado. Se usa para verificar
/WAIT, BUSREQ, /NMI y /RESET.
El Mecanismo out exec — Inyección Dinámica de Instrucciones
La característica más distintiva del diseño PIO del picoZ80 es el uso de
out exec, 16 en la state machine orquestadora
z80_cycle. Esta instrucción extrae un valor de 16 bits del TX FIFO y lo ejecuta inmediatamente como una instrucción PIO — el valor no es datos,
es la siguiente instrucción que la state machine ejecutará.
Este mecanismo permite al código C en el Core 1 controlar la secuencia de ciclo de bus en tiempo real. En lugar de cargar un programa PIO fijo para cada tipo de ciclo, el Core 1 envía una secuencia de instrucciones PIO pre-codificadas al TX FIFO, y la SM de ciclo las ejecuta una por 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.
El código C pre-calcula estas secuencias de instrucciones al inicio para cada tipo de ciclo (fetch, lectura de memoria, escritura de memoria, lectura de E/S, escritura de E/S, refresco, reconocimiento de interrupción). Durante la ejecución, el Core 1 selecciona la secuencia pre-construida apropiada y la envía al FIFO. Este enfoque tiene dos ventajas críticas:
- Eficiencia de espacio de programa — cada bloque PIO tiene solo 32 slots de instrucción. Al inyectar instrucciones dinámicamente, la SM de ciclo necesita solo 7 instrucciones de memoria de programa para orquestar todos los tipos de ciclo. Los programas de tipo de ciclo reales (fetch, lectura, escritura, etc.) existen como arreglos C de instrucciones codificadas, no como programas PIO residentes.
- Flexibilidad — el código C puede modificar la secuencia de instrucciones inyectada en tiempo de ejecución para manejar casos especiales (por ejemplo, insertar wait states adicionales, omitir la fase de refresco o generar un ciclo no estándar para depuración).
Coordinación de State Machines
Las 12 state machines trabajan como un pipeline coordinado. El siguiente diagrama muestra el flujo de un ciclo típico de lectura de 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
El handshake basado en IRQ asegura que el bus de direcciones esté estable antes de activar las señales de control, y que los datos se muestreen en el punto correcto del ciclo de bus. Las state machines nunca hacen polling — usan
wait 0 irq N para dormir hasta que ocurra el evento relevante, consumiendo cero ciclos de CPU mientras esperan.
Ciclo Fetch del Z80 (Ciclo M1) — Paso a Paso
El fetch de opcode es el ciclo de bus Z80 más complejo — combina una lectura de memoria con un ciclo de refresco. El programa z80_fetch se ejecuta durante 4 ciclos T del reloj del 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
El programa PIO implementa esto de la siguiente manera:
- Flanco de subida T1 — la SM
z80_addr coloca el valor de PC en A0–A15. z80_fetch activa /M1 a nivel bajo mediante set pins.
- Flanco de bajada T1 —
/MREQ y /RD se activan a nivel bajo (mediante set pins y side-set). La dirección ahora es válida y el sistema de memoria puede comenzar a responder.
- T2 — la SM entra en un bucle de wait-state: espera el flanco de subida y luego el de bajada del CLK, y verifica el pin
/WAIT mediante jmp pin. Si /WAIT está bajo, la SM repite el bucle (añadiendo ciclos Tw). Si está alto, procede a T3.
- Flanco de subida T3 —
in pins, 8 muestrea D0–D7 (el byte de opcode) y lo envía al RX FIFO. Se activa IRQ 1 para señalar a z80_data/z80_addr que ahora debe emitirse la dirección de refresco. /M1, /MREQ y /RD se desactivan; /RFSH se activa a nivel bajo.
- Flanco de bajada T3 —
/MREQ se activa nuevamente (para el strobe de fila de refresco).
- T4 — el refresco continúa. Al final de T4,
/MREQ y /RFSH se desactivan. La SM de ciclo retorna a start_cycle lista para la siguiente transacción de bus.
El Core 1 lee el opcode del RX FIFO y lo usa para decodificar la instrucción, determinar cuántos ciclos adicionales de memoria o E/S se necesitan, y enviar las secuencias de instrucciones apropiadas.
Ciclos de Lectura y Escritura de Memoria
Los ciclos de lectura y escritura de memoria son más simples que el fetch — abarcan 3 ciclos T sin fase de refresco.
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↓)
Para las lecturas, la SM
z80_mem_read activa
/MREQ y
/RD en el flanco de bajada de T1, espera durante T2 (verificando
/WAIT para wait states), y luego muestrea el bus de datos en el flanco de bajada de T3 usando
in pins, 8. Para las escrituras,
z80_mem_write activa
/MREQ en el flanco de bajada de T1, y luego activa
/WR en el flanco de bajada de T2 después de que el bus de datos sea controlado por
z80_data. Ambos desactivan todas las señales de control al final de T3.
Ciclos de Lectura y Escritura de E/S
Los ciclos de E/S del Z80 usan /IORQ en lugar de /MREQ y siempre incluyen un wait state automático (Tw) entre T2 y T3. Esta es una característica arquitectónica del Z80 — el ciclo adicional da tiempo a los dispositivos de E/S más lentos para responder:
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 activa
/IORQ y
/RD en el flanco de subida de T2 (no en T1 como en los ciclos de memoria — esto es la especificación del Z80). El wait state automático Tw se implementa mediante el mismo patrón de bucle
jmp pin /
wait utilizado para los ciclos de memoria. Las escrituras de E/S siguen el mismo patrón con
/WR reemplazando a
/RD.
Manejo de BUSREQ / BUSACK
La SM
z80_busrq (PIO 2 SM 0) monitoriza el pin de entrada
/BUSREQ del host. Cuando
/BUSREQ se activa (nivel bajo), la SM:
- Activa IRQ 6 para señalar a la SM de ciclo que hay una solicitud de bus pendiente.
- Espera a que se complete el ciclo de bus actual (
wait 1 irq 0).
- Extrae una palabra de control de 32 bits del TX FIFO que especifica las direcciones y valores de los pines para el estado de liberación del bus — esto pone en tri-state los buses de direcciones y datos y activa
/BUSACK a nivel bajo.
- Permanece en bucle con
jmp pin hasta que /BUSREQ se desactiva (nivel alto).
- Extrae una segunda palabra de 32 bits para restaurar las direcciones normales de los pines y desactivar
/BUSACK.
- Limpia IRQ 6, permitiendo que la SM de ciclo reanude su operación.
La SM de ciclo verifica IRQ 6 al inicio de cada ciclo mediante
wait 0 irq 6 — si el flag está activado, la SM se detiene hasta que la solicitud de bus se complete. Esto asegura que la liberación del bus ocurra limpiamente entre ciclos, nunca a mitad de ciclo.
Sincronización de Reloj
Todas las SM de tipo de ciclo se sincronizan con el reloj Z80 del host usando
wait 1 gpio Z80_PIN_CLK (esperar flanco de subida) y
wait 0 gpio Z80_PIN_CLK (esperar flanco de bajada). Esto significa:
- Los programas PIO son independientes de la frecuencia del reloj — funcionan a cualquier velocidad de reloj del host desde DC hasta la tasa máxima que el RP2350 puede seguir (limitada por el reloj del sistema PIO y la tasa de muestreo GPIO).
- El reloj PIO de 300 MHz del RP2350 proporciona aproximadamente 85 ciclos PIO por T-state del Z80 a 3.5 MHz, dando más que suficiente tiempo para ejecutar instrucciones PIO, enviar/recibir FIFOs y verificar flags IRQ entre flancos de reloj.
- La SM
z80_sync (PIO 2 SM 1) proporciona una IRQ de sincronización T1 que el código C usa para alinear los accesos a PSRAM con el reloj del host, previniendo la deriva de temporización en software del host sensible al reloj.
- La SM
z80_clk_sync (PIO 2 SM 2) regenera el reloj del host en un GPIO separado, proporcionando una salida de reloj limpia para monitorización externa o disparo de analizador lógico.
Ciclo de Reconocimiento de Interrupción
La SM
z80_int_ack (PIO 2 SM 3) implementa la secuencia de reconocimiento de interrupción del Z80. Cuando el código C detecta una condición de interrupción, carga el programa int_ack. Este ciclo es similar a un fetch pero con diferencias clave:
/M1 se activa en T1 (como un fetch), pero /IORQ se activa en lugar de /MREQ en el wait state (Tw1).
- Se insertan dos wait states automáticos (Tw1, Tw2) para dar tiempo al dispositivo que interrumpe a colocar un vector en el bus de datos.
- El byte de vector se lee de D0–D7 y se envía al RX FIFO.
- Sigue un ciclo de refresco, idéntico a la fase de refresco del fetch.
Modelo de Memoria
Los accesos a memoria se resuelven a través de tres niveles de latencia creciente. El diseño de tres niveles asegura que el caso común (RAM/ROM respaldada por PSRAM) sea rápido mientras permite máxima flexibilidad para dispositivos virtuales y paso directo al hardware físico del host.
Nivel 1 — Tabla de Despacho SRAM del RP2350
Un arreglo de 128 entradas de valores
membankPtr de 32 bits, residente en la SRAM de 512KB del chip del RP2350, proporciona una búsqueda O(1) del tipo de bloque para cada transacción de bus. Una entrada cubre cada bloque de 512 bytes del espacio de direcciones de 64KB del Z80 (128 × 512 = 65,536 bytes). Cada entrada codifica:
- El tipo de bloque (PHYSICAL, RAM, ROM, FUNC, etc.).
- Para bloques respaldados por PSRAM: el número de banco PSRAM y el offset.
- Para bloques FUNC: un índice en la tabla de punteros a funciones de dispositivos virtuales.
Este es el camino más rápido — el Core 1 lee la entrada de la tabla de despacho para la dirección actual en un solo acceso SRAM (cero wait states a 300MHz) antes de decidir qué hacer a continuación.
Nivel 2 — PSRAM Externa
La PSRAM de 8MB está organizada como:
- 64 bancos × 64KB — datos de imagen RAM o ROM para el espacio de direcciones Z80.
- 64KB
memPtr — arreglo de punteros de redirección por byte para bloques tipo PTR.
- 64KB
memioPtr — arreglo de punteros a funciones para dispositivos FUNC mapeados en memoria.
- 64KB
ioPtr — arreglo de punteros a funciones para dispositivos FUNC de puertos E/S.
El acceso a PSRAM se realiza mediante el periférico SPI dedicado del RP2350 con DMA. La latencia de acceso es determinista y gestionada por el generador de wait states para evitar violaciones de bus.
Nivel 3 — Flash SPI de 16MB
Las imágenes ROM se cargan desde Flash (o la tarjeta SD, a través del ESP32) a PSRAM durante el arranque. En tiempo de ejecución, la Flash no se accede para transacciones de bus — todos los datos ROM se sirven desde PSRAM. La Flash se utiliza para:
- Bootloader y firmware de aplicación.
config.json minificado (almacenado en caché desde la tarjeta SD en cada arranque).
- Imágenes ROM en particiones App Config (utilizadas cuando no hay tarjeta SD presente).
Tipos de Bloques de Memoria
| Tipo |
Descripción |
PHYSICAL |
Paso directo — el RP2350 libera el bus y la memoria física del host responde. Se utiliza para la ROM y RAM nativas del host. |
PHYSICAL_VRAM |
Como PHYSICAL pero con wait states adicionales para la temporización de la RAM de video del host. Adecuado para regiones VRAM del MZ-700/MZ-80A. |
PHYSICAL_HW |
Paso directo para registros de hardware del host (dispositivos mapeados por E/S en el espacio de memoria). |
RAM |
Lectura/escritura — respaldada por un banco PSRAM. El RP2350 atiende lecturas y escrituras desde/hacia PSRAM. |
ROM |
Solo lectura — respaldada por un banco PSRAM. Los ciclos de escritura se ignoran silenciosamente (el host ve temporización de bus normal pero no se almacenan datos). |
VRAM |
RAM de video respaldada por PSRAM. Los ciclos de escritura se reflejan simultáneamente tanto en PSRAM como en la VRAM física del host. |
FUNC |
Dispositivo virtual — cada acceso dispara una llamada a función C a través de la tabla de punteros a funciones memioPtr o ioPtr, permitiendo emulación arbitraria de E/S. |
PTR |
Redirección por byte — cada byte del bloque de 512 bytes puede apuntar independientemente a cualquier otro tipo de bloque o ubicación PSRAM. |
Referencia de Configuración
Todo el comportamiento del picoZ80 se controla mediante
config.json en la tarjeta SD. El RP2350 lee y minifica este archivo durante el arranque, almacenando el resultado en Flash. Los arranques posteriores usan la copia en Flash si no hay tarjeta SD presente.
La estructura JSON de nivel superior es:
{
"esp32": {
"core": { ... },
"wifi": { ... }
},
"rp2350": {
"core": { ... },
"z80": [ { "memory": [...], "io": [...], "drivers": [...] } ]
}
}
esp32.core
| Clave |
Tipo |
Descripción |
device |
cadena |
Personalidad de CPU — "Z80" para picoZ80, "6502" para pico6502, "6512" para pico6512. |
mode |
entero |
Modo WiFi de arranque por defecto: 0 = cliente (estación), 1 = Punto de Acceso. |
esp32.wifi
| Clave |
Tipo |
Descripción |
override |
0/1 |
Interruptor maestro: 1 = aplicar todas las configuraciones siguientes; 0 = usar configuraciones NVS persistidas. |
wifimode |
cadena |
"ap" = modo Punto de Acceso; "client" = modo Estación/cliente. |
ssid |
cadena |
Nombre de red WiFi para crear (AP) o unirse (cliente). |
password |
cadena |
Contraseña WiFi. |
ip |
cadena |
Dirección IP fija (por ejemplo, "192.168.1.192"). |
netmask |
cadena |
Máscara de subred (por ejemplo, "255.255.255.0"). |
gateway |
cadena |
Gateway predeterminado (por ejemplo, "192.168.1.1"). |
dhcp |
0/1 |
Modo cliente: 1 = DHCP; 0 = usar configuración de IP fija. |
webfs |
cadena |
Directorio raíz del sistema de archivos web en la tarjeta SD (por defecto "webfs"). |
persist |
0/1 |
1 = escribir configuraciones resueltas en NVS para persistencia entre reinicios. |
rp2350.core
| Clave |
Tipo |
Descripción |
cpufreq |
entero |
Reloj del sistema RP2350 en Hz (por ejemplo, 300000000). La frecuencia estable máxima depende de la frecuencia PSRAM y el voltaje del núcleo. |
psramfreq |
entero |
Reloj SPI de PSRAM en Hz (por ejemplo, 133000000). |
voltage |
flotante |
Voltaje del núcleo RP2350 en voltios (por ejemplo, 1.10). Velocidades de reloj más altas requieren mayor voltaje. |
addrDrive |
integer (0–3) |
Fuerza de excitación GPIO del bus de direcciones: 0=2mA, 1=4mA, 2=8mA, 3=12mA. Por defecto 0. |
addrSlew |
integer (0–1) |
Tasa de slew GPIO del bus de direcciones: 0=lento (por defecto), 1=rápido. |
dataDrive |
integer (0–3) |
Fuerza de excitación GPIO del bus de datos. Misma codificación que addrDrive. Por defecto 0. |
dataSlew |
integer (0–1) |
Tasa de slew GPIO del bus de datos. Misma codificación que addrSlew. Por defecto 0. |
ctrlDrive |
integer (0–3) |
Fuerza de excitación GPIO de señales de control. Misma codificación que addrDrive. Por defecto 0. |
ctrlSlew |
integer (0–1) |
Tasa de slew GPIO de señales de control. Misma codificación que addrSlew. Por defecto 0. |
addrSchmitt / dataSchmitt / ctrlSchmitt |
0/1 |
Habilita el disparador Schmitt de entrada para el grupo de bus de direcciones / datos / control. 1 = habilitado (por defecto), 0 = deshabilitado. Se aplica a los pines configurados como entradas. |
addrPull / dataPull / ctrlPull |
integer (0–2) |
Resistencia de pull para el grupo de bus de direcciones / datos / control: 0 = ninguna, 1 = pull-down, 2 = pull-up. |
refresh |
integer |
Generación de refresco de DRAM del Z80: 0 = desactivado (sin ciclos de refresco), 1 = un ciclo de refresco en cada búsqueda de opcode, N = un ciclo de refresco por cada N búsquedas. Reduce la sobrecarga del bus en hosts cuya DRAM no requiere refresco por búsqueda. |
pinOverrides |
arreglo |
Sobrescrituras GPIO por pin. Cada elemento: { "pin": N, "drive": D, "slew": S, "schmitt": 0/1, "pull": P }. Sobrescribe los valores predeterminados a nivel de bus para pines GPIO individuales cuando el hardware específico requiere diferentes características eléctricas. |
z80[].memory — Entradas del Mapa de Memoria
El arreglo memory define el mapa de memoria del Z80. Las entradas deben estar ordenadas por dirección. Las regiones deben estar alineadas y dimensionadas como múltiplos de 512 bytes. Los espacios entre entradas se tratan como paso directo PHYSICAL.
| Clave |
Tipo |
Descripción |
enable |
0/1 |
Si esta entrada está activa. Las entradas deshabilitadas se ignoran durante el arranque. |
addr |
hex string |
Dirección de inicio en el espacio de direcciones Z80 (por ejemplo, "0x0000"). Debe estar alineada a 512 bytes. |
size |
hex string |
Tamaño de la región en bytes (por ejemplo, "0x2000" para 8KB). Debe ser múltiplo de 512. |
type |
cadena |
Tipo de bloque — ver Tipos de Bloques de Memoria. |
bank |
entero |
Número de banco PSRAM (0–63) para tipos RAM/ROM/VRAM/FUNC. |
tcycwait |
entero |
Wait states adicionales de ciclo T a insertar en cada acceso a esta región. |
tcycsync |
0/1 |
Habilitar sincronización T1 para esta región. Requerido para regiones sensibles a la temporización. |
task |
cadena |
Identificador de tarea opcional para bloques tipo FUNC (cadena de enlace de controlador). |
file |
cadena |
Ruta en la tarjeta SD a una imagen ROM para precargar en el banco PSRAM durante el arranque (por ejemplo, "/ROM/mz700.rom"). |
fileofs |
entero |
Offset en bytes dentro del archivo de imagen ROM desde donde comenzar la lectura. |
z80[].io — Entradas del Mapa de Puertos E/S
El arreglo io mapea rangos de puertos de E/S del Z80 a tipos de bloque. Solo los tipos PHYSICAL y FUNC son significativos para entradas de E/S.
| Clave |
Tipo |
Descripción |
enable |
0/1 |
Si esta entrada de E/S está activa. |
addr |
hex string |
Dirección de puerto E/S de inicio (por ejemplo, "0xE0"). |
size |
hex string |
Número de puertos consecutivos (por ejemplo, "0x04" para puertos E0–E3). |
type |
cadena |
PHYSICAL = pasar al host; FUNC = llamar función handler C. |
task |
cadena |
Cadena de enlace de controlador para entradas tipo FUNC. |
z80[].drivers — Instancias de Controladores
El arreglo drivers instancia controladores de dispositivos virtuales y los enlaza a regiones de memoria o E/S. Cada controlador tiene un tipo (el módulo de controlador C), un nombre (identificador de instancia) y uno o más objetos de interfaz que definen las imágenes ROM, mapas de direcciones, mapas de E/S y parámetros para esa instancia de controlador.
"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" }
]
}
]
}
]
Cada entrada de controlador tiene un "name" de nivel superior (el módulo de controlador C a instanciar), "type" (PHYSICAL o VIRTUAL), y un arreglo "if" (interfaz) que contiene uno o más objetos de interfaz. Cada objeto de interfaz describe un sub-controlador o tarjeta periférica y contiene estos campos:
| Clave |
Tipo |
Descripción |
enable |
0/1 |
Si esta interfaz está activa (0 = se omite durante la inicialización). |
name |
cadena |
Identificador de instancia — debe coincidir con un nombre en el interfaceFuncMap[] de la persona. |
type |
cadena |
PHYSICAL o VIRTUAL. |
rom |
arreglo |
Imágenes ROM a cargar en PSRAM (ver más abajo). |
addrmap |
arreglo |
Entradas de remapeo de direcciones de memoria (srcaddr/dstaddr/size). |
iomap |
arreglo |
Entradas de remapeo de puertos E/S (srcaddr/dstaddr/size/16bit). |
param |
arreglo |
Parámetros específicos del controlador — típicamente { "enable":1, "file":"/path/to/image" } para imágenes de disco, { "name":"key", "value":"val" } para parámetros con nombre, o { "ip":"a.b.c.d:port", "enable":1 } para la dirección del servidor de archivos de red Celestite. |
Puertos base de interfaz reubicables. Para que las tarjetas independientes de máquina puedan usarse en placas personalizadas / de experimentador (ver OpenZ80), varios controladores de interfaz leen su puerto E/S base desde el dstaddr de su entrada iomap (con srcaddr establecido en el puerto auténtico de la tarjeta), usando por defecto su puerto original cuando no hay una entrada iomap presente. Las tarjetas reubicables y sus bases por defecto son 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) y Celestite (0x60/16). Las claves JSON están en minúsculas (srcaddr / dstaddr) y sus valores se interpretan como números. El campo Base I/O Port en la página de Configuración de la GUI escribe automáticamente la entrada iomap correcta.
rom[].loadaddr[] — Direcciones de Carga ROM
Cada entrada de archivo ROM contiene un arreglo loadaddr que especifica dónde se cargan los datos ROM en PSRAM. Múltiples entradas loadaddr permiten que un solo archivo ROM se divida en rangos de direcciones no contiguos o bancos PSRAM.
| Clave |
Tipo |
Descripción |
enable |
0/1 |
Si esta dirección de carga está activa. |
position |
entero |
Offset en bytes dentro del archivo ROM desde donde comenzar la lectura. |
addr |
hex string |
Dirección Z80 destino en el mapa de memoria (por ejemplo, "0x0000"). |
bank |
entero |
Número de banco PSRAM donde cargar. |
size |
hex string |
Número de bytes a cargar (por ejemplo, "0x1000" para 4KB). |
tcycwait |
entero |
Wait states extra de ciclo T para esta región. |
tcycsync |
entero |
Valor de sincronización de ciclo T para esta región. |
Compatibilidad Persona–Interfaz
No todos los controladores de interfaz están disponibles para cada persona. La tabla siguiente muestra la compatibilidad actual de interfaces para la serie Sharp MZ / X1. La persona Amstrad PCW-9512 es un controlador autónomo con un FDC uPD765 integrado (sin controladores de interfaz separados). La persona Tatung Einstein TC-01 es un controlador autónomo con un FDC WD1770 integrado y una sub-interfaz EinsteinFDC. La columna
Open muestra las tarjetas independientes de máquina aceptadas por la persona de experimentador
OpenZ80.
La tabla muestra qué interfaces pueden usarse con cada persona de máquina de nivel superior a través del arreglo "if". El valor "name" de la interfaz en el JSON debe coincidir con una de las entradas soportadas para la persona elegida.
| Interfaz |
MZ-700 |
MZ-1500 |
MZ-80K |
MZ-800 |
MZ-80A |
MZ-2000 |
MZ-2200 |
MZ-80B |
MZ-2500 |
Open |
| RFS |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
— |
— |
— |
— |
| TZFS |
Sí |
— |
— |
— |
— |
— |
— |
— |
— |
— |
| MZ-1E05 |
Sí |
Sí |
— |
Sí |
— |
— |
— |
— |
— |
Sí |
| MZ80FIO |
— |
— |
Sí |
Sí |
— |
— |
— |
— |
— |
— |
| MZ80AFI |
— |
— |
Sí |
Sí |
Sí |
— |
— |
— |
— |
— |
| MZ-8BFI / E0054PA |
— |
— |
— |
Sí |
— |
Sí |
Sí |
Sí |
Sí |
— |
| MZ-1E14 |
Sí |
Sí |
Sí |
Sí |
— |
— |
— |
Sí |
Sí |
— |
| MZ-1E19 |
Sí |
Sí |
Sí |
Sí |
— |
Sí |
Sí |
Sí |
Sí |
— |
| MZ-1R12 |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
| MZ-1R18 |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
Sí |
| MZ-1R23 |
— |
Sí |
— |
Sí |
— |
— |
— |
Sí |
Sí |
Sí |
| MZ-1R37 |
— |
Sí |
Sí |
Sí |
— |
— |
— |
Sí |
Sí |
Sí |
| PIO-3034 |
— |
Sí |
Sí |
Sí |
— |
— |
— |
Sí |
Sí |
Sí |
| Celestite |
— |
Sí |
— |
Sí |
— |
— |
— |
Sí |
Sí |
Sí |
| MZ-8BIO3 |
Sí |
Sí |
— |
Sí |
— |
— |
— |
Sí |
— |
Sí |
| MZ-1E24 |
Sí |
Sí |
— |
Sí |
— |
— |
— |
Sí |
— |
Sí |
| MZ-1E30 |
— |
— |
— |
— |
— |
— |
— |
Sí |
Sí |
— |
Controladores Integrados
El firmware soporta un sistema de compilación dirigido con cinco modelos objetivo: BaseZ80 (todos los controladores), SharpZ80 (solo Sharp), AmstradZ80 (solo Amstrad), TatungZ80 (solo Tatung) y OpenZ80 (la persona de experimentador independiente de máquina). Las definiciones en tiempo de compilación INCLUDE_SHARP_DRIVERS, INCLUDE_AMSTRAD_DRIVERS, INCLUDE_TATUNG_DRIVERS e INCLUDE_OPEN_DRIVERS controlan qué módulos de controladores se compilan. Las tablas siguientes listan todos los controladores disponibles.
Serie Sharp MZ (INCLUDE_SHARP_DRIVERS)
Cuando el firmware se compila con
INCLUDE_SHARP_DRIVERS, los siguientes módulos de controlador se compilan y pueden instanciarse a través del arreglo
drivers:
| Controlador |
Cadena de Tipo |
Descripción |
MZ700.c |
MZ700 |
Sharp MZ-700 — conmutación de bancos, video, E/S de teclado |
MZ80A.c |
MZ80A |
Sharp MZ-80A — ROM de monitor (SA-1510), VRAM, emulación Intel 8253 PIT, 8255 PPI, intercambio de memoria MEMSW/MEMSWR (incluyendo conmutación de bancos CP/M), soporte de modo mixto físico+virtual, y soporte para sub-interfaces RFS, MZ80AFI, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18 |
MZ2000.c |
MZ2000 |
Sharp MZ-2000 — conmutación de modo de memoria BST/NST, superposición de VRAM de caracteres + gráficos, 8253 PIT, 8255 PPI, Z80 PIO, MB8866 FDC. Soporta tanto modo físico (reemplazo directo del Z80 con detección automática de modo boot/normal) como modo virtual (emulación completa basada en PSRAM con reflejo de ROM IPL) |
MZ2200.c |
MZ2200 |
Sharp MZ-2200 — conmutación de modo de memoria BST/NST, superposición VRAM, 8253 PIT, 8255 PPI, Z80 PIO, MB8866 FDC, CRT a color |
MZ80B.c |
MZ80B |
Sharp MZ-80B — ROM IPL de 2K, BST/NST, pantalla monocromática, páginas GRPH duales, 8253 PIT, 8255 PPI, Z80 PIO |
MZ2500.c |
MZ2500 |
Sharp MZ-2500 (SuperMZ) — MMU de 8 páginas (64 bloques), modos de compatibilidad MZ-2000/MZ-80B, YM2203, G-CRTC, MB8876 FDC, paleta, controlador de interrupciones. El modo virtual soporta software controlado por interrupciones mediante handlers personalizados fetchByte/RETI (ciclos de bus M1 físicos para temporización del gate array), formato de disco D88 nativo con auto-detección sparse/contiguous, supresión de interrupción de un solo disparo durante la inicialización |
MZ1500.c |
MZ1500 |
Sharp MZ-1500 — superconjunto del MZ-700 con unidad Quick Disk incorporada, PCG, sonido estéreo PSG (SN76489AN), interfaz de impresora Z80 PIO, 8253 PIT, selección de modo MZ-700/MZ-1500 por DIP switch. Sub-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 de monitor SP-1002 (0x0000–0x0FFF), VRAM de 2KB (0xD000–0xD7FF), teclado 8255 PPI / 8253 PIT / LS367 (0xE000–0xE7FF), ROM de arranque MZ-80FD nativa (0xF000–0xF3FF), intercambio de memoria MEMSW/MEMSWR para CP/M. Modos físico + virtual (el CP/M en modo físico usa un remapeo de acceso Z80 por controlador; el modo virtual es necesario para el CP/M estándar). Dos rutas de disquete: MZ80FIO nativa (T3444M) — interfaz MZ-80FD original, arranca/lee todos los discos MZ-80K; y MZ80AFI (FDC del MZ-80A) — usada para CP/M, arranca el CP/M del MZ-80K y lee los discos CP/M del MZ-80K dentro de CP/M (C:/D:). Solo una interfaz de disquete está activa a la vez; MZ80FIO tiene prioridad si ambas están presentes. Sub-interfaces: RFS, MZ80FIO, MZ80AFI, MZ-1E14, MZ-1E19, MZ-1R12, MZ-1R18, MZ-1R37, PIO-3034 |
MZ800.c |
MZ800 |
Sharp MZ-800 — controlador de modo dual (compatibilidad MZ-700 + MZ-800 nativo). Espía el registro de Modo de Pantalla del GDG (puerto 0xCE) para conmutar de modo sobre la marcha: el modo nativo añade gráficos 320×200 / 640×200 (planos de VRAM 0x8000–0xBFFF), paleta de 4/16 colores, E/S del GDG mapeada por puertos (0xCC–0xCF, paleta 0xF0), interrupciones vectorizadas IM2 mediante la cadena daisy-chain del Z80-PIO; el modo MZ-700 usa 8255/8253 mapeados en memoria (0xE000–0xE7FF) y VRAM de texto (0xD000). PSG SN76489 (0xF2), FDC WD1773 (0xD8–0xDF), QuickDisk (0xF4–0xF7), puertos de conmutación de bancos de memoria 0xE0–0xE6. El modo virtual reproduce un RETI físico en el bus real para servir el latch en-servicio del PIO. |
MZ80AFI.c |
MZ80AFI |
Interfaz de disquete Sharp MZ-80A — emula el controlador de disco flexible MZ-80A AFI |
MZ80FIO.c |
MZ80FIO |
Interfaz de disquete Sharp MZ-80FD/MZ-80FIO (MZ-80K) — ROM de arranque FDIF en 0xF000–0xF3FF, puertos T3444M 0xF8–0xFB, hasta 4 unidades, cambio de disco en tiempo de ejecución |
T3444M.c |
(usado por MZ80FIO) |
FDC Toshiba T3444M/T3444A — disquete nativo del MZ-80K. DSK extendido CPC, 35 pistas, 2 cabezas, 16 sectores/pista, sectores FM de 128 bytes; analizador de DSK Track-Info robusto; 4 imágenes de unidad simultáneas |
WD1773.c |
WD1773 |
FDC WD1773 — imágenes DSK/RAW/D88 de 80 pistas, 2 cabezas, 8 sectores |
QDDrive.c |
QDDRIVE |
Unidad QuickDisk Sharp — emulación completa de Z80 SIO/2 con datos de pista espiral, control de motor y E/S asíncrona de tarjeta SD |
RFS.c |
RFS |
ROM Filing System — carga de MZF, CP/M, BASIC desde tarjeta SD |
TZFS.c |
TZFS |
TranZPUter Filing System — monitor multibanco funcional + sistema de archivos CP/M, seleccionable en la persona MZ-700. Modos de memoria tranZPUter mediante el puerto 0x60, procesador de servicio virtual K64F mediante OUT (0x68), E/S de sectores CP/M a través del ESP32. ROM roms/tzfs.bin desde TZFS/asm/tzfs.asm |
MZ-1E05.c |
MZ1E05 |
Unidad de interfaz de disco flexible Sharp MZ-1E05 (basada en WD1773) |
MZ8BFI.c |
MZ8BFI / E0054PA |
Interfaz de disco flexible MZ-2000 — FDC MB8866 sin ROM de controlador (código en IPL). Soporte de formato D88. |
MZ-1E14.c |
MZ1E14 |
Controlador QuickDisk MZ-1E14 con ROM BIOS (MZ-700/MZ-800) |
MZ-1E19.c |
MZ1E19 |
Controlador QuickDisk MZ-1E19 sin ROM BIOS |
MZ-1R12.c |
MZ1R12 |
Placa RAM de 32KB con batería de respaldo (persistida en tarjeta SD) |
MZ-1R18.c |
MZ1R18 |
Placa de expansión RAM de 64KB |
MZ-1R23.c |
MZ1R23 |
MZ-1R23 ROM Kanji de 128KB (patrones JIS 16×16) y MZ-1R24 ROM Diccionario de 256KB. Archivos ROM cargados desde tarjeta SD. Puertos E/S B8h–B9h con lectura auto-incrementada |
MZ-1R37.c |
MZ1R37 |
MZ-1R37 EMM (Expanded Memory Manager) de 640KB — espacio de direcciones de 20 bits con enganche de dirección por puerto E/S |
PIO-3034.c |
PIO3034 |
IO DATA PIO-3034 EMM de 320KB — contador de direcciones de 19 bits con puerto de datos auto-incrementado |
Celestite.c |
Celestite |
Placa compuesta Celestite — controlador Ethernet Wiznet W5100 (emulación de registros), controlador de interrupciones, UFM, CMOS RAM MZ-1R12 de 32KB integrada (expandible a 64KB), EMM MZ-1R37 de 640KB opcional. Puertos E/S 60h–6Fh. El parámetro ip en el arreglo JSON param configura la dirección del servidor de archivos netfs.py (por ejemplo, "192.168.1.210:6800"). Fase 2: networking TCP/IP real a través de puente ESP32 — comandos de socket W5100 reenviados al ESP32 para operaciones de socket BSD reales. IPC inter-core para NET_CFG, NET_SOCK, NET_SEND, NET_RECV, NET_PING |
MZ8BIO3.c |
MZ-8BIO3 |
Tarjeta serie RS-232C (conector BI), Z80 SIO emulado en los puertos 0xB0–0xB3 (base configurable). Canales A/B puenteados a los puertos serie USB CDC 2 y 3. Sin ROM. |
MZ1E24.c |
MZ-1E24 |
Tarjeta serie RS-232C (conector Sharp ST); igual que MZ-8BIO3 con cableado de conector diferente. |
Z80SIO.c |
(usado por MZ-8BIO3 / MZ-1E24) |
Zilog Z80 SIO/2 preciso a nivel de registro: WR0–WR7, RR0–RR2, interrupciones vectorizadas Z80 modo-2, cadena daisy-chain en-servicio de 4 niveles, status-affects-vector. Anillos SPSC sin bloqueo (lock-free) puentean el núcleo Z80 (core 1) y el servicio USB CDC (core 0). |
SASI.c + MZ1E30.c |
MZ-1E30 |
Controlador de disco duro SASI MZ-1E30 — emula el controlador de disco duro SASI (Shugart Associates System Interface) Sharp MZ-1E30 para MZ-2500/MZ-80B. Hasta 4 destinos de disco (~21.4 MB cada uno, bloques de 256 bytes), ROM IPL de 32KB (accedida por E/S a través de puertos 0xA8–0xA9), E/S de sector bajo demanda desde imágenes de disco en tarjeta SD. Comandos SASI: TEST_UNIT_READY, REQUEST_SENSE, READ(6), WRITE(6), SEEK(6), INQUIRY. Puertos E/S 0xA4–0xA5 (datos/control SASI) |
PIT8253.c |
PIT8253 |
Emulación Intel 8253 PIT independiente — los seis modos de contador, BCD/binario, latch, lectura/carga LSB/MSB |
PPI8255.c |
PPI8255 |
Emulación Intel 8255 PPI independiente — E/S Modo 0, set/reset de bits, callbacks de salida, inyección de entrada |
Serie Amstrad PCW (INCLUDE_AMSTRAD_DRIVERS)
Cuando el firmware se compila con
INCLUDE_AMSTRAD_DRIVERS, los siguientes módulos de controlador se compilan:
| Controlador |
Cadena de Tipo |
Descripción |
PCW9512.c |
PCW9512 |
Amstrad PCW-9512 — Z80A @ 4MHz, 512KB RAM con conmutación de páginas de 16KB en 4 bancos (puertos F0–F3), gate array (ASIC) para video/reloj del sistema/enrutamiento FDC/control de motor (puerto F8), controlador de impresora de margarita 8041 (puertos FC–FD), emulación de secuencia de arranque. Modos virtual y físico soportados |
uPD765.c |
— |
Emulación FDC NEC uPD765 — soporte de formato CPC DSK (puertos 00–01). Comandos del gate array: finalizar bootstrap, reiniciar, enrutamiento de INT FDC (NMI/INT/ignorar), terminal count, motor on/off. Imagen de disco físico mediante código Z80 inyectado. Módulo FDC reutilizable (análogo a WD1773.c para Sharp) |
Serie Tatung Einstein (INCLUDE_TATUNG_DRIVERS)
Cuando el firmware se compila con
INCLUDE_TATUNG_DRIVERS, los siguientes módulos de controlador se compilan:
| Controlador |
Cadena de Tipo |
Descripción |
EinsteinTC01.c |
EinsteinTC01 |
Tatung Einstein TC-01 — Z80A @ 4MHz, 64KB RAM + 8KB ROM conmutable (X-TAL MOS), conmutación ROM/RAM por puerto 0x24, VDP TMS9129 con aplicación de temporización entre accesos (~2us de intervalo), PSG AY-3-8910 (puertos 0x02-0x03), Z80 CTC (puertos 0x28-0x2B), Z80 PIO (puertos 0x30-0x33), interfaz de teclado (puerto 0x20). Modos virtual y físico soportados |
EinsteinFDC.c |
— |
Sub-interfaz FDC Einstein — 2 unidades, soporte de formato DSK/D88. Imagen de disco físico: leer disquete físico a DSK, escribir DSK a disquete físico |
WD1770.c |
— |
Emulación FDC WD1770 — soporte de formato Extended CPC DSK, D88 y DSK estándar. 40 pistas, 1 cabeza, 10 sectores, 512 bytes (discos de 200KB). Módulo FDC reutilizable para máquinas basadas en WD1770 (separado de WD1773.c usado por Sharp) |
TZFS — Modelo de Monitor + CP/M (persona MZ-700)
TZFS.c implementa un monitor de bajo nivel multibanco y sistema de archivos funcional — un conjunto de mejoras sobre el MONITOR 1Z-013A original (acceso a SD, banqueo de ROM, un ensamblador / desensamblador y herramientas) — modelado sobre el TZFS del tranZPUter SW y su procesador de E/S virtual K64F. Se ofrece como una
interfaz seleccionable únicamente en la persona MZ-700 (registrado en
MZ700.c junto a RFS, y en la práctica mutuamente excluyente con él), no como una persona de nivel superior. CP/M se ejecuta por debajo del monitor.
Emulación de modos de memoria (puerto 0x60)
Al escribir un modo de memoria tranZPUter en el puerto de E/S
0x60 se reapuntan los punteros de banco. Los modos son
TZMM_ORIG,
TZMM_BOOT,
TZMM_TZFS,
TZMM_TZFS2,
TZMM_TZFS3,
TZMM_TZFS4,
TZMM_CPM,
TZMM_CPM2 y
TZMM_COMPAT. La disposición CP/M
CPM2 usa paginación del bloque 0 con granularidad de byte —
0x0000–
0x003F se asignan al bloque de vectores y
0x0040–
0x01FF al inicio del TPA.
Procesador de servicio virtual K64F (puerto 0x68)
El Z80 solicita servicios ejecutando
OUT (0x68), que encola un mensaje
MSG_TZFS_SVCREQ al Core 0; el Core 0 ejecuta
TZFS_processServiceRequest. Los servicios del sistema de archivos son READDIR / NEXTDIR (bloques de directorio de 16 entradas en caché), READFILE / NEXTREADFILE, LOADFILE (consciente de la cabecera MZF y de los objetos de banco), CHANGEDIR y CLOSE. Los servicios de CP/M son LOADBDOS (recarga de CCP + BDOS en arranque en caliente), ADDSDDRIVE, READSDDRIVE y WRITESDDRIVE, más servicios de frecuencia de CPU. Como picoZ80 no tiene acceso directo a la SD, los sectores de 512 bytes de CP/M se leen y escriben a través del
ESP32 (
ESP_readSector /
ESP_writeSector) contra archivos de imagen completos; las rutas de imagen por unidad provienen de las entradas
param[].file del JSON de la interfaz, con la plantilla de reserva
CPM/SDC16M/RAW/CPMDSK<nn>.RAW. La ROM TZFS es
roms/tzfs.bin en la tarjeta SD, ensamblada desde
TZFS/asm/tzfs.asm (su BIOS de CP/M desde
TZFS/asm/cbios.asm /
cpm22.asm). Se distribuye en
config_MZ-700_MZ-700.json con
"enable": 0 y se activa en el JSON o desde la página de Configuración de la GUI web.
OpenZ80 — Persona de Experimentador (INCLUDE_OPEN_DRIVERS)
El objetivo
OpenZ80 (
TARGET_MODEL_OPEN →
INCLUDE_OPEN_DRIVERS) compila una persona Z80 "vanilla" deliberadamente básica para experimentadores que instalan el picoZ80 en una placa de su propio diseño o en una máquina sin controlador dedicado. En modo
PHYSICAL, todo el espacio de 64K de memoria y E/S pasa directamente a la placa real (las tarjetas de interfaz superponen sus puertos E/S); en modo
VIRTUAL presenta una RAM plana de 64K en la que las imágenes ROM a nivel de controlador se cargan secuencialmente desde 0x0000. No incorpora hardware de máquina y reutiliza los módulos de tarjetas de interfaz Sharp de forma literal (no mantienen estado específico de la persona), exponiendo solo las tarjetas independientes de máquina a continuación — cada una de las cuales soporta
reubicación del puerto E/S base.
| Controlador |
Cadena de Tipo |
Descripción |
Open.c |
Open |
Persona Z80 vanilla / de experimentador — sin hardware de máquina. Paso directo físico o RAM virtual plana de 64K con carga de ROM a nivel de controlador desde 0x0000 |
MZ-1R12.c |
MZ1R12 |
Tarjeta RAM-file MZ-1R12 de 32K (base por defecto 0xF8, reubicable) |
MZ-1R18.c |
MZ1R18 |
Placa RAM MZ-1R18 de 64K (base por defecto 0xEA, reubicable) |
MZ-1R23.c |
MZ1R23 |
Placa ROM Kanji MZ-1R23 / diccionario MZ-1R24 (base por defecto 0xB8, reubicable) |
MZ-1R37.c |
MZ1R37 |
MZ-1R37 EMM de 640K (base por defecto 0xAC, reubicable) |
PIO-3034.c |
PIO3034 |
PIO-3034 EMM paralelo / E/S paralela (base por defecto 0x00, reubicable) |
MZ8BIO3.c / MZ1E24.c |
MZ8BIO3 / MZ1E24 |
Tarjetas serie RS-232C duales (Z80 SIO, base por defecto 0xB0, reubicable; canales A/B en USB CDC 2/3) |
MZ-1E05.c |
MZ1E05 |
Interfaz de disquete WD1773 (base por defecto 0xD8, reubicable; requiere una ROM de arranque FDC) |
Celestite.c |
Celestite |
Placa LAN ESP32 Celestite (base por defecto 0x60, reubicable) |
Compile con
build_tzpuPico.sh open. Para adaptar el picoZ80 a una nueva máquina, tome uno de los controladores de persona bajo
src/drivers/{Sharp,Amstrad,Tatung,Other}/ como base y combínelo con el código fuente de la ROM de monitor / IPL / BIOS CP/M / arranque de disquete correspondiente en los directorios
asm/ de los proyectos RFS y TZFS (por ejemplo,
RFS/asm/sa1510.asm,
RFS/asm/cbios.asm,
TZFS/asm/mz2000_ipl.asm,
RFS/asm/mz80afi.asm). Consulte la
Guía del Desarrollador para el procedimiento paso a paso.
Framework de Dispositivos Virtuales
El tipo de bloque FUNC permite la emulación arbitraria de E/S llamando funciones handler C en cada acceso al bus. Cualquier bloque de 512 bytes de memoria o rango de puertos E/S puede estar respaldado por una función.
Firmas de Funciones Handler
Los handlers FUNC de memoria se almacenan en la tabla memioPtr en PSRAM. Los handlers FUNC de E/S se almacenan en la tabla ioPtr. Las firmas de las funciones son:
/* 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);
Las funciones handler se llaman directamente desde el bucle principal del Core 1. Deben completarse antes de que expiren los wait states del ciclo de bus actual — mantenga los handlers breves y evite cualquier operación bloqueante (E/S de archivos, UART, etc.). Si un handler necesita disparar una operación más larga (por ejemplo, cargar un sector de disco), debe enviar un mensaje al Core 0 a través de la cola inter-core y retornar inmediatamente con un byte de estado, difiriendo la E/S real al Core 0.
Escribir un Nuevo Controlador
Para añadir soporte para un nuevo periférico o máquina host:
- Crear un nuevo archivo
.c / .h en el directorio src/drivers/.
- Implementar funciones handler de lectura y escritura que coincidan con las firmas anteriores.
- Registrar los punteros a funciones handler en las tablas
memioPtr o ioPtr durante la inicialización del controlador.
- Añadir el controlador al objetivo de compilación CMakeLists.txt.
- Añadir una entrada de cadena de tipo para que el parser de configuración JSON pueda instanciar el controlador por nombre.
- Documentar las claves
param del controlador en el archivo de cabecera del controlador.
La función de inicialización del controlador se llama una vez durante el arranque, después de que se haya parseado
config.json. El controlador recibe un puntero a su bloque de configuración de interfaz y debe configurar cualquier estado interno y registrar sus handlers en ese momento.
ICE (Shell de Depuración)
El picoZ80 incluye un shell de depuración ICE (In-Circuit Emulator) integrado en el Canal 1 USB CDC (el segundo puerto serie enumerado cuando la placa está conectada por USB). El shell se ejecuta en el Core 0 y se comunica con el bucle de emulación del Core 1 mediante flags compartidos en la estructura de contexto Z80CPU. El shell de depuración solo está disponible en la variante de firmware DBGSH, que se compila con la definición INCLUDE_DBGSH.
Canales Serie USB CDC
El picoZ80 enumera varios puertos serie USB CDC cuando se conecta a un host. CDC 0 y CDC 1 sirven a los UARTs físicos / puente ESP32 y al shell de depuración ICE (CDC 1, variantes DBGSH). CDC 2 y CDC 3 son los dos canales (A y B) de una tarjeta serie RS-232C virtual — el controlador MZ-8BIO3 o MZ-1E24 — cuando uno de ellos está configurado en config.json. Estos dos puertos no tienen un UART físico detrás: son puentes de búfer en anillo hacia el Z80 SIO emulado, de modo que los datos escritos en CDC 2/3 en el host aparecen en el canal A/B del Z80 SIO visto por el invitado, y viceversa. Si no hay ninguna tarjeta serie configurada, CDC 2 y CDC 3 no se enumeran.
Arquitectura
- Entrada/Salida: Canal 1 USB CDC a 115200 baudios. El prompt del shell es
dbg> . Se soporta historial de comandos (16 entradas) y eco de caracteres.
- Breakpoints: Hasta 8 breakpoints simultáneos almacenados en
cpu->dbgBpAddr[]. El Core 1 verifica el arreglo de breakpoints antes de cada fetch de opcode; al encontrar una coincidencia, establece cpu->hold = true y señala al Core 0 mediante dbgBpHit.
- Paso a paso: El comando
step establece cpu->dbgStepCount. El Core 1 decrementa este contador después de cada instrucción, deteniendo automáticamente cuando llega a cero. Se muestra el estado de registros antes/después y la instrucción desensamblada para cada paso.
- Traza de ejecución: Un buffer circular de 512 entradas (
cpu->dbgTrace[]) registra PC, opcode y registro de flags para cada instrucción ejecutada cuando la traza está habilitada. Cada entrada de 32 bits empaqueta [31:16]=PC, [15:8]=opcode, [7:0]=registro F.
- Acceso a memoria: El acceso a memoria física (
dm p, wm p) genera ciclos de bus Z80 reales a través de las state machines PIO. El acceso virtual (dm v, wm v) lee/escribe PSRAM directamente. El modo automático (wm sin calificador) sigue el mapa de memoria. El acceso RP2350 (dm r) lee el espacio de direcciones del microcontrolador host con validación de rango.
- Hold/Release: El comando
hold establece cpu->hold = true. El Core 1 confirma mediante cpu->holdAck, asegurando que la CPU esté inactiva antes de que el shell acceda al estado compartido.
- Break: El comando
break detiene el Core 1 y luego reporta el PC actual, la instrucción a punto de ejecutarse (desensamblada) y el conjunto completo de registros — la forma más rápida de ver dónde se encuentra un programa en ejecución, antes de avanzar paso a paso o inspeccionar. go/cont reanuda.
- Teclas rápidas y abreviaturas: Para reducir la escritura durante la depuración, los comandos más comunes tienen teclas rápidas de una sola letra —
c=cont, s=step, g=go, b=break, r=regs, h=hold — que se resuelven antes de la coincidencia por prefijo, por lo que nunca se tratan como ambiguas. Cualquier otro comando puede introducirse como su prefijo único más corto (p. ej. ste=step, sta=status, dis=disassemble); un prefijo ambiguo lista los candidatos, y un nombre escrito por completo siempre tiene prioridad.
Referencia de Comandos
| Comando |
Sintaxis |
Descripción |
help |
help |
Listar todos los comandos |
regs |
regs |
Volcar todos los registros Z80, flags y contador de ciclos |
dm |
dm <p|f|v|r> <addr> [len] |
Volcar memoria (física / fetch / virtual / RP2350) |
search |
search [p|v] <start> <end> <hex..>|"text" |
Buscar en memoria un patrón de bytes o cadena de texto ASCII. p = bus físico, v = PSRAM virtual, omitir para mapeado. Las coincidencias se muestran con 8 bytes de contexto. Auto-detiene la CPU para acceso físico/mapeado. Patrón de hasta 32 bytes |
cmp |
cmp [f] <phys> <virt> <len> |
Comparar memoria del bus físico con PSRAM virtual |
dis |
dis [p|v] [addr] [count] |
Desensamblar código Z80 |
asm |
asm [addr] |
Ensamblador Z80 interactivo |
memmap |
memmap [block] |
Mostrar tabla de punteros de banco de memoria |
memptr |
memptr [addr] |
Mostrar tabla PSRAM memPtr |
iomap |
iomap [port] |
Mostrar tabla de handlers de puertos E/S |
status |
status |
Estado del sistema (frecuencia CPU, PSRAM, tiempo de actividad) |
ver |
ver |
Versión de firmware e información de partición |
drivers |
drivers |
Listar controladores e interfaces activos |
hold |
hold |
Pausar emulación de CPU |
release |
release |
Reanudar emulación de CPU |
break |
break |
Detener el Z80 en ejecución y reportar dónde se detuvo — PC, la instrucción (bytes + desensamblado) a punto de ejecutarse, y un volcado completo de registros. A diferencia de hold (que pausa silenciosamente), break muestra el estado para que puedas ver exactamente dónde está la ejecución (p. ej. cuando está atascado en un bucle). Reemitir break vuelve a mostrar el estado. Reanudar con go/cont o avanzar paso a paso con step. Expira (~3 s) si el Z80 se mantiene en reset o su reloj está bloqueado |
go |
go |
Continuar (liberar hold, breakpoints activos) |
cont |
cont |
Alias de go. Continuar ejecución (liberar hold, breakpoints activos) |
step |
step [n] |
Ejecutar paso a paso n instrucciones |
bp |
bp <addr> |
Establecer breakpoint (máximo 8) |
bc |
bc <n|*> |
Limpiar breakpoint n o todos |
bl |
bl |
Listar breakpoints |
wm |
wm [p|v] <addr> <byte>... |
Escribir en memoria (física/virtual/auto) |
fill |
fill [p|v] <addr> <len> [w|d] <val> |
Llenar memoria con un valor constante |
copy |
copy <pv|fp|vp> <src> <len> <dst> |
Copiar memoria entre física y virtual |
memtest |
memtest <addr> <len> [pattern] |
Probar memoria física (escritura+lectura, escritura+fetch, intercalado) |
in |
in <port> |
Leer puerto E/S Z80 |
out |
out <port> <byte> |
Escribir puerto E/S Z80 |
trace |
trace <on|off|dump [n]|clear|rt|byte ...> |
Control de traza de ejecución; rt habilita salida de traza en tiempo real; byte habilita traza a nivel de byte |
verify |
verify <on|off> |
Alternar verificación completa de fetch de opcode |
fwait |
fwait <0-4> |
Forzar wait states extra en M1 (fetch de opcode); 0 = desactivado (por defecto) |
iowait |
iowait <0-8> |
Forzar wait states extra en ciclo E/S; 0 = desactivado (por defecto) |
corrupt |
corrupt [clear] |
Mostrar o limpiar corrupciones de fetch detectadas |
fdctrace |
fdctrace <on|off|dump> |
Habilitar/deshabilitar traza de E/S FDC; dump muestra las últimas 64 operaciones |
qdtrace |
qdtrace <on|off|dump> |
Habilitar/deshabilitar traza de E/S Quick Disk; dump muestra las últimas 64 operaciones |
piodbg |
piodbg [clear] |
Mostrar diagnósticos de hardware PIO del RP2350 (FDEBUG, FSTAT, FIFO, PCs, GPIO); clear reinicia flags persistentes |
load |
load <p|v> <file> <addr> [len] [ofs] |
Cargar un archivo desde la tarjeta SD del ESP32 en memoria Z80. p = bus físico, v = banco 0 de PSRAM virtual. file relativo a /sdcard/. Si se omite len, se carga el archivo completo (hasta 64KB); si se especifica, máximo 1MB. ofs opcional para offset del archivo. Auto-detiene la CPU para escrituras físicas. Usa banco 63 de PSRAM como buffer temporal |
save |
save <p|pf|v> <file> <addr> <len> |
Guardar memoria Z80 en un archivo en la tarjeta SD del ESP32. p = bus físico, pf = fetch físico (M1), v = banco 0 de PSRAM virtual. file relativo a /sdcard/. Máximo 64KB. Auto-detiene la CPU para lecturas físicas. Refresco periódico de DRAM durante lecturas físicas |
dir |
dir [path] |
Listar archivos en la tarjeta SD del ESP32. La ruta opcional es relativa a /sdcard/. Muestra nombres de archivo y tamaños |
echo |
echo [on|off] |
Alternar eco del terminal |
reset |
reset |
Forzar reset del Z80 |
set |
set <reg|flags|memmap|memptr|iomap> <idx> <val> |
Modificar registro Z80, flags, mapa de memoria, memPtr o entrada de mapa E/S en tiempo de ejecución |
hist |
hist [n] |
Mostrar historial de comandos (preservado entre sesiones mediante ESP32 NVS) |
savehst |
savehst |
Forzar guardado del historial de comandos en ESP32 NVS |
ipl |
ipl |
Realizar un reset IPL (modo BST) alternando el bit 3 del Puerto C del 8255 PPI. Reinicia al modo boot sin un reset completo del Z80 |
mmutrace |
mmutrace |
Volcar información de traza específica de la máquina (estado MMU, instantáneas de registros E/S). La salida varía según la persona a través del handler de traza registrado |
intcount |
intcount |
Mostrar conteo de reconocimiento de interrupciones y estado actual de interrupción |
psync |
psync [start end] |
Sincronizar memoria física con PSRAM. Rango de direcciones opcional; por defecto el espacio completo de direcciones |
dskimage |
dskimage read <filename> [cylinders] [heads] / dskimage write <filename> |
Crear imagen de un disquete físico a un archivo DSK en la tarjeta SD (read), o escribir un archivo DSK desde la tarjeta SD a un disquete físico (write). dskimage <filename> por defecto es lectura (compatible con versiones anteriores). Auto-detecta geometría si se omite |
busdiag |
busdiag |
Mostrar diagnósticos de bus (estado PIO, niveles de señal, contención de bus) |
fdcimage |
fdcimage |
Mostrar estado y progreso de creación de imagen FDC |
fdcdiag |
fdcdiag |
Mostrar información de diagnóstico FDC (estado del controlador, volcado de registros) |
gadiag |
gadiag |
Mostrar información de diagnóstico del gate array (estado de comandos, enrutamiento de interrupciones) |
Teclas rápidas y abreviaturas. Los comandos no necesitan escribirse completos. Los seis comandos más usados tienen teclas rápidas de una sola letra — c (cont), s (step), g (go), b (break), r (regs) y h (hold) — y cualquier otro comando puede introducirse como su prefijo único más corto (por ejemplo ste para step, sta para status, dis para disassemble). Un nombre de comando escrito por completo siempre tiene prioridad, y un prefijo ambiguo imprime la lista de comandos coincidentes.
Coprocesador ESP32
El módulo ESP32-S3-PICO-1 actúa como coprocesador manejando todas las funciones de red y almacenamiento. Se comunica con el RP2350 a través de dos interfaces:
- FSPI (50MHz, SPI de 4 hilos) — Protocolo IPC Binario v1.1 — transferencia masiva de datos de alta velocidad (imágenes ROM, lecturas/escrituras de sectores de disco, descarga de archivo de configuración). El protocolo usa un encabezado de trama binario fijo de 64 bytes con verificación de integridad CRC32 (reemplazando el anterior checksum XOR). Los canales DMA se pre-asignan durante la inicialización y nunca se liberan, eliminando la sobrecarga de claim/unclaim por transferencia y las condiciones de carrera. Las transferencias de sectores en ráfaga permiten hasta 16 × 512 bytes de sectores (8KB) en una sola transacción SPI, mejorando significativamente los tiempos de carga de imágenes de disquete y QuickDisk. El canal DMA RX se eleva a PRIORIDAD ALTA para prevenir desbordamiento del FIFO causado por la contención del bus QMI PSRAM del Core 1.
- UART (460.8kbaud) — protocolo de comando/respuesta para mensajes de control, consultas de estado e intercambios cortos de datos.
Modos de Red
El firmware ESP32 soporta tres modos de red, seleccionados en tiempo de compilación mediante archivos sdkconfig pre-construidos:
| Modo |
Archivo de Config |
WiFi |
USB NCM |
Consola |
FCC/RED Requerido |
| Solo WiFi |
sdkconfig.mode_wifi_only |
Sí |
No |
USB Serial/JTAG |
Sí |
| WiFi + NCM |
sdkconfig.mode_wifi_and_ncm |
Sí |
Sí |
TinyUSB CDC-ACM |
Sí |
| Solo NCM |
sdkconfig.mode_ncm_only |
No |
Sí |
TinyUSB CDC-ACM |
No |
USB NCM (Network Control Model) presenta un adaptador Ethernet CDC-NCM en el puerto USB OTG del ESP32-S3 (GPIO 19/20). Un dispositivo USB compuesto expone tanto un puerto serie CDC-ACM (para registro de depuración) como la interfaz de red NCM. El servidor DHCP integrado asigna al host una dirección IP de la subred
192.168.7.0/24, con el picoZ80 accesible en
192.168.7.1. El tiempo de arrendamiento es de 120 minutos.
En modo WiFi+NCM, el servidor HTTP se enlaza a
INADDR_ANY:80 y sirve ambas interfaces simultáneamente. WiFi se conecta asíncronamente por lo que la interfaz USB NCM está disponible inmediatamente al encender.
Cuando solo NCM está habilitado, la radio WiFi se deshabilita completamente, la página del WiFi Manager se elimina de la interfaz web, y el título del panel de estado del Dashboard cambia de "WiFi Configuration" a "Network Configuration" (mostrando el estado USB NCM en lugar de SSID/detalles WiFi). La red de adaptación de antena del ESP32-S3 no necesita ser poblada en la PCB.
Interfaz de Tarjeta SD
El ESP32 gestiona la tarjeta SD a través de su interfaz SPI. La tarjeta SD se monta como FAT32 y todo el acceso a archivos desde el RP2350 es mediado por el ESP32 — el RP2350 envía comandos de E/S de archivos por el enlace FSPI/UART y el ESP32 realiza las operaciones reales de lectura/escritura FAT32.
La tarjeta SD también es directamente accesible para el servidor web del ESP32, que sirve archivos desde el directorio
webfs/ y permite al Administrador de Archivos navegar y modificar el contenido de la tarjeta mediante HTTP.
Servidor Web
El ESP32 ejecuta un servidor HTTP en el puerto 80 (sin TLS — solo para uso en red local). Todos los recursos web (HTML, CSS, JavaScript) se sirven desde el directorio
webfs/ en la tarjeta SD, permitiendo que la interfaz web se actualice sin reflashear el firmware del ESP32. El servidor web maneja:
- Servir recursos web estáticos desde el directorio
webfs/ de la tarjeta SD.
- Endpoints de API REST para datos JSON (estado del sistema, lectura/escritura de configuración, operaciones de archivos).
- Endpoints de carga de firmware OTA tanto para el RP2350 como para el ESP32.
- Conexión WebSocket para actualizaciones de estado del Dashboard en tiempo real.
Protocolo de Comandos RP2350 ↔ ESP32
El RP2350 (Core 0) se comunica con el ESP32 usando un protocolo simple de comando/respuesta sobre el enlace UART. Los comandos son opcodes de un solo byte con bytes de payload opcionales. El ESP32 confirma cada comando con un byte de estado seguido de cualquier dato de respuesta.
Categorías comunes de comandos:
- E/S de Archivos — abrir, leer, escribir, cerrar, listado de directorio, stat de archivo.
- Configuración — solicitar contenido de config.json, escribir configuración actualizada, solicitud de recarga.
- Disco — montar/desmontar imagen de disco, leer/escribir sector (retransmitido desde emulación WD1773 y QDDrive). Los nombres de archivo de la imagen de disquete y QuickDisk actualmente montada son rastreados por el ESP32 y mostrados en el menú de Acciones de la interfaz web.
- Sistema — consulta de versión, solicitud de reinicio, lectura/escritura NVS.
La interfaz FSPI se usa para transferencias masivas donde el payload es demasiado grande para el UART (subidas de imágenes ROM, datos de sectores de disco), mientras que el UART maneja todos los comandos de control.
Comandos IPC de Red
La implementación de red Celestite Fase 2 añade cinco comandos IPC inter-core que el RP2350 usa para solicitar operaciones de red al ESP32. Estos comandos se reenvían por el enlace FSPI/UART y el ESP32 realiza las operaciones de socket BSD correspondientes. Los connects no bloqueantes usan select() con timeout, y flags pendientes por socket rastrean las operaciones en curso.
| Comando |
Opcode |
Descripción |
IPCF_CMD_NET_CFG |
0x10 |
Obtener configuración de red del ESP32 — devuelve dirección IP, gateway, máscara de subred y dirección MAC |
IPCF_CMD_NET_SOCK |
0x11 |
Operación de ciclo de vida de socket — abrir, conectar, escuchar, cerrar o desconectar un socket |
IPCF_CMD_NET_SEND |
0x12 |
Enviar datos a un socket abierto |
IPCF_CMD_NET_RECV |
0x13 |
Recibir datos de un socket abierto |
IPCF_CMD_NET_PING |
0x14 |
Solicitud de eco ICMP (ping) |
Los comandos de socket W5100 soportados a través de esta capa IPC son: OPEN, CONNECT, LISTEN, SEND, RECV, CLOSE y DISCON. El ESP32 los traduce a llamadas estándar de la API de socket BSD (
socket(),
connect(),
listen(),
send(),
recv(),
close(),
shutdown()), permitiendo que la placa Celestite se comunique con servicios de red como el servidor de archivos
netfs.py.
Watchdog y Diagnósticos de Arranque
El firmware del RP2350 utiliza un temporizador watchdog de hardware para detectar y recuperarse de bloqueos durante el arranque y paradas del bucle principal. El watchdog se habilita tempranamente en la secuencia de arranque con un timeout de 30 segundos y se actualiza (watchdog_update()) en cada hito importante. Si cualquier etapa de arranque o iteración del bucle principal tarda más que el timeout, el watchdog reinicia el RP2350 automáticamente.
Seguimiento del Progreso de Arranque
El progreso de arranque se rastrea usando los registros scratch del watchdog del RP2350, que sobreviven a resets del watchdog (pero no a resets de encendido). Esto permite al firmware determinar, después de un reset del watchdog, exactamente a qué etapa de arranque se llegó antes del bloqueo.
| Registro Scratch |
Nombre |
Contenido |
scratch[0–3] |
Historial de arranque |
Últimos cuatro intentos de reset — cada entrada codifica (attempt_count << 24) | (stage << 16) | (resetCause & 0xFFFF). Las entradas se desplazan en cada reset del watchdog: [0]←[1]←[2]←[3]←actual. |
scratch[4] |
Diagnósticos SPI |
Contadores de diagnóstico empaquetados para el enlace FSPI: breadcrumbs, tipo de mensaje, contadores de timeout T1/T3, conteo de tramas erróneas y conteo OK. |
scratch[5] |
Marcador mágico |
Establecido a 0xB00710BE para indicar que los registros scratch contienen datos válidos de progreso de arranque. |
scratch[6] |
Etapa actual |
El código de etapa de arranque más reciente (ver tabla siguiente). |
scratch[7] |
Causa de reset |
El código de causa de reset del controlador de reset de hardware. |
Los códigos de etapa de arranque progresan desde
0x01 (inicio) hasta
0x10 (bucle principal iniciado). Las sub-etapas dentro del bucle principal (
0x11–0x17) y el procesamiento de comandos inter-core (
0x20–0x27) proporcionan seguimiento de grano fino:
| Código |
Etapa |
Descripción |
0x01 |
BOOTP_START |
Punto de entrada alcanzado |
0x02 |
BOOTP_CLK_SET |
Reloj del sistema configurado |
0x03 |
BOOTP_PSRAM_INIT |
Inicialización de PSRAM comenzada |
0x04 |
BOOTP_PSRAM_OK |
PSRAM inicializada exitosamente |
0x05 |
BOOTP_STDIO_INIT |
USB stdio inicializado |
0x06 |
BOOTP_PIO_INIT |
State machines PIO cargadas |
0x07 |
BOOTP_Z80_INIT |
Contexto de CPU Z80 inicializado |
0x08 |
BOOTP_USB_INIT |
Puente USB inicializado |
0x0A |
BOOTP_ESP_HS_SYNC |
Sincronización de handshake SPI ESP32 |
0x0B |
BOOTP_CORE1_LAUNCH |
Core 1 lanzado |
0x0D |
BOOTP_FSPI_INIT |
IPC binario FSPI inicializado |
0x0E |
BOOTP_ESP_INIT |
Comunicación ESP32 lista |
0x10 |
BOOTP_MAIN_LOOP |
Bucle principal iniciado |
0x11–0x17 |
Sub-etapas del bucle principal |
Sondeo USB, inter-core, SPI NOP/CMD, tareas |
0x20–0x27 |
Comandos inter-core |
Carga de disquete, carga QD, carga RAMFILE, E/S de archivos |
Log Persistente en PSRAM (plogf)
Los últimos 4KB de la PSRAM de 8MB (dirección 0x117FF000) están reservados para un log de depuración persistente que sobrevive a resets del watchdog. La macro plogf() escribe mensajes estilo printf en este buffer durante el arranque, antes de que USB esté disponible para la salida normal de debugf(). En el siguiente arranque exitoso, la función dump_plog() envía cualquier mensaje capturado a la consola de depuración y luego limpia el buffer. El log usa una estructura simple: un marcador mágico de 4 bytes (0x504C4F47 = "PLOG"), un contador de longitud de 4 bytes, y un buffer de texto circular de 3840 bytes.
Diagnósticos de Fallos
El firmware instala handlers de fallo Cortex-M33 para fallos graves, fallos de gestión de memoria, fallos de bus y fallos de uso. Cuando ocurre un fallo, el handler guarda una instantánea de diagnóstico completa en los últimos 256 bytes de PSRAM (dirección 0x117FFF00) con un marcador mágico (0xFA017000), el tipo de fallo, todos los registros relevantes (PC, LR, SP, R0–R3, R12, PSR), el Registro de Estado de Fallo Configurable (CFSR), el Registro de Estado de Fallo Grave (HFSR), el Registro de Dirección de Fallo de Bus (BFAR), el Registro de Dirección de Fallo de Gestión de Memoria (MMFAR) y el ID del núcleo. El handler luego entra en un bucle infinito, permitiendo que el watchdog dispare un reset. En el siguiente arranque, el firmware verifica si hay un diagnóstico de fallo válido y envía la información capturada mediante debugf(), permitiendo análisis post-mortem sin requerir una sesión de depurador en vivo.
Limpieza de Configuración Flash
El mecanismo de actualización OTA del RP2350 soporta dos operaciones adicionales más allá de la carga de firmware:
- Limpiar App Config (
FW_CFGCLEAR_ID = 0xB1D7E5FA) — borra la partición App Config (imágenes ROM y JSON minificado) asociada con el slot de firmware destino. Esto fuerza al firmware a releer config.json desde la tarjeta SD en el siguiente arranque, lo cual es necesario cuando el esquema de configuración ha cambiado entre versiones de firmware.
- Limpiar Flash Header (
FW_HDRCLEAR_ID = 0xC2E8F6AB) — reinicia el encabezado de partición Flash a valores de fábrica. La configuración del bootloader (partición 0) se preserva, pero todos los metadatos de particiones de aplicación se reconstruyen desde cero. Úselo cuando la tabla de particiones se haya corrompido o al regresar a una versión anterior de firmware que espera un diseño de partición diferente.
Ambas operaciones se activan desde las casillas de verificación de la página web OTA del RP2350 y son ejecutadas por el bootloader durante el proceso de actualización de firmware.
Depuración SWD — RP2350
El RP2350 soporta depuración completa a nivel de código fuente sobre ARM Serial Wire Debug (SWD). Conecte una sonda compatible con CMSIS-DAP (Raspberry Pi Debug Probe, Black Magic Probe o similar) a los Pines 1 (SWCLK), 2 (SWDIO) y 5 (GND) del conector de depuración.
Configuración de OpenOCD
El picoZ80 requiere una pequeña modificación al script estándar de destino OpenOCD del RP2350 para habilitar depuración SMP con puertos GDB separados por núcleo:
sudo cp /usr/local/share/openocd/scripts/target/rp2350.cfg \
/usr/local/share/openocd/scripts/target/rp2350_tzpu.cfg
Edite rp2350_tzpu.cfg — busque la línea target smp dentro del bloque if {[string compare $_USE_CORE SMP] == 0} y elimine el # inicial:
# Before:
#target smp $_TARGETNAME_0 $_TARGETNAME_1
# After:
target smp $_TARGETNAME_0 $_TARGETNAME_1
Este único cambio hace que OpenOCD registre el Core 0 en el puerto GDB 3333 y el Core 1 en el puerto GDB 3334, permitiendo sesiones GDB independientes por núcleo. Inicie OpenOCD antes de iniciar GDB:
openocd -f interface/cmsis-dap.cfg -f target/rp2350_tzpu.cfg -c "adapter speed 5000"
Configuración de GDB
Añada lo siguiente a ~/.gdbinit (con rutas absolutas que coincidan con la ubicación de su proyecto) para permitir la carga automática de archivos .gdbinit por directorio:
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
Depuración 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
Depuración del 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
El comando GDB xac <address> <count> está definido en los archivos .gdbinit.3333 / .gdbinit.3334. Vuelca memoria como salida combinada hexadecimal y ASCII y es útil para inspeccionar contenidos de bancos PSRAM y estado de dispositivos mapeados en memoria.
Depuración USB del ESP32
El coprocesador ESP32-S3 tiene una interfaz USB-JTAG incorporada — no se requiere sonda de depuración externa. Conecte un cable USB desde el PC host directamente al puerto USB del ESP32 en la placa 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
Asegúrese de que el ELF fue compilado desde la misma revisión de código fuente que el firmware ejecutándose en el dispositivo, para que los símbolos y direcciones se alineen correctamente.
Sistema de Compilación
El firmware del picoZ80 usa CMake con el Raspberry Pi Pico SDK 2.x. El sistema de compilación produce el firmware
Bootloader y la
Aplicación. La aplicación se compila en cuatro variantes — dos particiones (Partición 1 en 0x10020000, Partición 2 en 0x10520000) cada una en configuraciones estándar y DBGSH. Las variantes DBGSH añaden
INCLUDE_DBGSH a los flags de compilación, habilitando el shell de depuración completo en el Canal 1 USB CDC. El firmware ESP32 se compila separadamente usando ESP-IDF v5.4, gestionado mediante Docker.
La forma más rápida de obtener un entorno funcional es el script automatizado
setup_picoZ80 (macOS/Linux y Windows), que instala el SDK y todas las dependencias y crea scripts de compilación listos para usar — consulte el
README y la
Guía del Desarrollador. Los objetivos, flags y comandos de CMake que se describen a continuación documentan la compilación subyacente que el script automatiza, para quienes prefieran configurarla manualmente.
Objetivos de Compilación CMake
| Objetivo |
Salida |
Dirección Flash |
Notas |
Bootloader |
Bootloader.elf, Bootloader.uf2 |
0x10000000 |
|
BaseZ80_0x10020000 |
BaseZ80_0x10020000.elf, .bin |
0x10020000 (Slot 1) |
Estándar (sin shell de depuración) |
BaseZ80_0x10520000 |
BaseZ80_0x10520000.elf, .bin |
0x10520000 (Slot 2) |
Estándar (sin shell de depuración) |
BaseZ80_DBGSH_0x10020000 |
BaseZ80_DBGSH_0x10020000.elf, .bin |
0x10020000 (Slot 1) |
DBGSH — incluye shell de depuración ICE |
BaseZ80_DBGSH_0x10520000 |
BaseZ80_DBGSH_0x10520000.elf, .bin |
0x10520000 (Slot 2) |
DBGSH — incluye shell de depuración ICE |
Los modelos
SharpZ80,
AmstradZ80,
TatungZ80 y
OpenZ80 siguen el mismo patrón de slot / DBGSH, por ejemplo
OpenZ80_0x10020000,
OpenZ80_0x10020000_DBGSH,
OpenZ80_0x10520000 y
OpenZ80_0x10520000_DBGSH (cada uno emite
.elf,
.bin,
.hex y
.map; los slots de aplicación usan
.bin simple, no UF2). Compile un solo modelo con el filtro
build_tzpuPico.sh, por ejemplo
build_tzpuPico.sh open.
Flags Clave de Compilación CMake
| Flag |
Efecto |
INCLUDE_SHARP_DRIVERS |
Compila todos los controladores de periféricos 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 los controladores de periféricos Amstrad PCW (PCW9512, uPD765). |
INCLUDE_TATUNG_DRIVERS |
Compila los controladores de periféricos Tatung Einstein (EinsteinTC01, EinsteinFDC, WD1770). |
INCLUDE_OPEN_DRIVERS |
Compila la persona de experimentador OpenZ80 (Open.c) y las tarjetas de interfaz independientes de máquina (MZ-1R12/1R18/1R23/1R37, PIO-3034, MZ8BIO3, MZ1E24, Z80SIO, MZ-1E05, WD1773, Celestite). |
TARGET_MODEL_TATUNG |
Establece Tatung Einstein como el modelo objetivo exclusivo (usado en la compilación TatungZ80). |
TARGET_MODEL_OPEN |
Establece la persona de experimentador OpenZ80 como el modelo objetivo exclusivo (usado en la compilación OpenZ80; habilita INCLUDE_OPEN_DRIVERS). |
INCLUDE_DBGSH |
Compila el shell de depuración ICE en el Canal 1 USB CDC. Presente solo en variantes de compilación DBGSH. |
CMAKE_BUILD_TYPE=Debug |
Habilita símbolos de depuración y deshabilita optimización. Requerido para depuración GDB a nivel de código fuente. |
CMAKE_BUILD_TYPE=Release |
Optimización completa (-O3). Usado para firmware de producción. |
Comandos de Compilación
# 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
El script build_tzpuPico.sh incrementa automáticamente el número de versión en una compilación exitosa y copia los archivos de salida versionados a fw/uf2/ (bootloader UF2) y fw/bin/ (binario de aplicación para OTA). El UF2 del Bootloader se usa solo para el flasheo inicial mediante almacenamiento masivo USB. Los binarios de slot de aplicación usan formato binario simple (no UF2) porque residen en direcciones de Flash no estándar.
Selección de Modo de Red ESP32
Para cambiar el modo de red, copie el archivo de configuración pre-construido apropiado a sdkconfig antes de compilar:
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
Sitios de Referencia
Aviso Regulatorio de Comunicaciones Inalámbricas
Este dispositivo incorpora un módulo inalámbrico ESP32-S3-PICO-1 capaz de transmitir en la banda ISM de 2.4 GHz, lo que lo convierte en un radiador intencional bajo las regulaciones de radiofrecuencia a nivel mundial (incluyendo FCC Part 15 Subpart C en los Estados Unidos y la Directiva de Equipos Radioeléctricos 2014/53/EU en la Unión Europea) cuando el firmware WiFi está instalado.
Configuración de Fábrica
Tal como se envía, la placa picoZ80 viene flasheada con el firmware
solo NCM (
sdkconfig.mode_ncm_only). En esta configuración, la radio WiFi está completamente deshabilitada y los componentes de la red de adaptación de antena del ESP32-S3 no están poblados en la PCB. Debido a que no ocurre transmisión RF, el dispositivo
no es un radiador intencional y no requiere certificación FCC, CE/RED o equivalente. Puede venderse, distribuirse o regalarse sin autorización regulatoria.
Añadir WiFi
Los usuarios finales pueden poblar la red de adaptación de antena y flashear firmware con WiFi habilitado (
sdkconfig.mode_wifi_only o
sdkconfig.mode_wifi_and_ncm) para uso personal, experimental o educativo. Una vez que el WiFi está habilitado, el dispositivo se convierte en un radiador intencional y se aplican las siguientes reglas:
Aunque el módulo ESP32-S3-PICO-1 por sí mismo lleva certificaciones regulatorias preexistentes (FCC, CE y otras), esas certificaciones a nivel de módulo
no se extienden automáticamente a un producto terminado que incorpore el módulo. La exención de módulo pre-certificado permite a
individuos aficionados construir un número limitado de dispositivos para
uso personal, experimental o educativo sin obtener una autorización de equipo separada.
Limitaciones Importantes
- Los dispositivos con firmware WiFi no deben venderse, ofrecerse a la venta, regalarse ni distribuirse de otra manera a terceros a menos que el producto terminado haya sido probado independientemente y se le haya otorgado su propia autorización de equipo (por ejemplo, FCC ID, marcado CE con evaluación de un Organismo Notificado) en la jurisdicción correspondiente.
- Construir este proyecto con WiFi habilitado para uso personal en cantidades limitadas generalmente está permitido bajo las disposiciones de uso aficionado y experimental (por ejemplo, FCC § 15.23), siempre que el dispositivo no cause interferencia perjudicial.
- La venta comercial con WiFi habilitado requiere certificación completa FCC/RED (o equivalente) a nivel de producto.
- Los requisitos regulatorios varían según el país. Los constructores fuera de los Estados Unidos deben consultar a su autoridad nacional de radiofrecuencia para las reglas aplicables.
Responsabilidad del Constructor
Es responsabilidad exclusiva del constructor asegurar que cualquier dispositivo construido a partir de estos diseños cumpla con todas las regulaciones de radiofrecuencia aplicables en su jurisdicción. El autor proporciona estos diseños para uso personal, educativo y de aficionados y no hace ninguna representación de que un dispositivo construido a partir de ellos satisfaga los requisitos regulatorios para distribución comercial.