Saltar a contenido

Substrato Z0: qué existe y cómo se corre

Esta página es el inventario: qué hay construido, en qué estado y cómo ejecutarlo. La planificación está en Fases Z0–Z5 y la disposición de directorios en Estructura del repositorio.

Si lo que quieres es entenderlo, no inventariarlo

El tutorial recorre lo mismo en siete páginas en orden, explicando por qué existe cada pieza, con enlaces a la documentación de cada herramienta externa y con las gráficas y los números reales que produce el modelo. Esta página asume que ya sabes de qué va.

Arranque

make venv     # crea .venv e instala requirements-dev.txt (pinado)
make check    # todos los gates que corre el CI en el job de substrato

make check necesita verilator y gcc en el PATH. Verilator viene de los repositorios de la distribución (apt install verilator); no hace falta Vivado para nada de lo anterior.

La fuente única de verdad

config/params.toml es el paquete de parámetros de D-02. De él salen, por generación, las vistas de los cuatro consumidores:

Consumidor Cómo lo lee
rtl/ rtl/generated/drx_params_pkg.sv, generado
fw/ fw/include/drx_params.h, generado
tcl/ tcl/generated/drx_params.tcl, generado
model/, sim/ drx_model.params, que lee el TOML directamente
python3 tools/gen_params.py            # regenera
python3 tools/gen_params.py --check    # gate de CI: falla si hay desfase

Cambiar fs, R₁ o R₂ —que es lo que va a pasar cuando se cierren P-01 y P-08— empieza por editar dos líneas del TOML y regenerar (a 8-oct-2026 el cierre además exige auditar constantes de PRF y ancho de pulso y repetir la verificación; ver la revisión del ADR-001). Ese es el motivo entero de que este fichero exista antes que el RTL.

El gate de la constante hardcodeada es real, no decorativo

tools/check_hardcoded_clock.py falla la build si aparece un literal decimal ≥ 10⁶ en rtl/, fw/, sim/, model/, tcl/ o contract/. Ignora comentarios y ficheros generados, y admite el marcador clock-const-ok: <razón> para las excepciones legítimas —que hoy son dos: la velocidad de la luz y una conversión de unidades—. Cada excepción lleva su razón escrita.

Modelo dorado

model/drx_model/ es el oráculo de D-03: NCO con truncamiento de fase, mezclador complejo, CIC de Hogenauer con desbordamiento intencionado, FIR de coeficientes cuantizados, enrejado en rango y generador de vectores con degradaciones inyectables. Todo en aritmética entera; la coma flotante solo aparece antes de cuantizar y en el análisis.

Los coeficientes del FIR están congelados en config/coeffs/ y son los que se cargarán en el FIR Compiler. No se rediseñan en cada ejecución: si lo hicieran, una actualización de scipy movería el oráculo por debajo.

python3 tools/gen_coeffs.py --check

La suite del modelo incluye una huella del oráculo: un vector conocido produce una salida cuyo SHA-256 está fijado en el test. Cualquier cambio de comportamiento del modelo la mueve, y eso obliga a justificarlo en el commit en lugar de que pase inadvertido.

Lo que el modelo todavía no puede prometer

La cadena está modelada contra la configuración pretendida de la IP de Xilinx, no contra la IP real: en Z0 no hay Vivado ni IP generada. La correspondencia bit a bit modelo↔IP se establece en Z1 y es ahí donde pueden aparecer ajustes de redondeo. Hoy el modelo es autoconsistente, determinista y reproducible, que es lo que Z0 promete — no más.

Simulación

Dos niveles, dos caminos. El runner único que pedía D-05 no existe: cocotb no tiene backend para xsim (P-09, decidido el 30 de agosto de 2026). Lo compartido es el oráculo, no la herramienta.

  • L0 — Verilator, bajo cocotb. Funciona. make sim.
  • L1 — SystemVerilog nativo, sobre xsim. El oráculo del modelo dorado cruza por fichero: tools/gen_l1_vectors.py escribe stimulus.hex, expected_i.hex, expected_q.hex y un manifest.json con conteos, modo, transitorio de arranque y la huella SHA-256 de config/params.toml. sim/tb_sv/drx_l1_file_source.sv los reproduce con handshake y sim/tb_sv/drx_l1_checker.sv compara bit a bit. Lo lanza tcl/sim_l1.tcl.

El arnés de L1 está verificado sin Vivado. sim/tests/test_l1_harness.py lo corre en Verilator sobre los vectores del propio modelo y comprueba las dos direcciones: cero discrepancias con vectores limpios y exactamente una cuando se invierte un bit de una muestra. La segunda es la que vale, porque el modo de fallo peligroso de un comparador es dar verde. Lo que no se ha ejecutado nunca es tcl/sim_l1.tcl —falta Vivado— y sim/tb_sv/tb_l1_ddc.sv no elabora todavía porque su DUT, drx_ddc_top, es trabajo de Z1; el make check lo linta para que no se pudra mientras tanto.

Contrato DRx↔DSP v0.1

Congelado unilateralmente según D-08. Fuente única en contract/schema/drx_dsp_v0_1.toml; de ahí salen las tres implementaciones: C (lado DRx), Rust (lado DSP, que es un servicio Rust) y Python (referencia de los tests).

El test de contrato compila un programa en C con la cabecera generada, vuelca los bytes de cada mensaje y los compara con los que produce la implementación de Python. Si los layouts divergen, el test falla. La implementación de Rust no se compila aquí —no hay toolchain de Rust en este repositorio— y de ella solo se comprueba que las constantes de tamaño coinciden; el test de layout del lado Rust le toca al proyecto DSP.

Formato: little-endian, empaquetado, sin relleno implícito, solo enteros en el cable. Los ángulos viajan como cuenta cruda del encoder y la corrección AFC como palabra de fase absoluta del NCO: en Hz haría falta que el DSP conociera el FS_HZ del DRx, y eso rompería D-02.

Gateware: escrito, no ejecutado

tcl/build.tcl implementa el flujo no-project de D-07 —síntesis, implementación con el WNS como gate duro, informes y bitstream con -bin_file—, tcl/ip.tcl regenera la IP desde los XCI versionados, tcl/sim_l1.tcl lanza la simulación L1 sobre xsim y tools/make_boot.sh empaqueta el BOOT.BIN y comprueba la reproducibilidad empaquetando dos veces y comparando.

Nada de esto se ha ejecutado nunca: no hay Vivado en el entorno de desarrollo ni runner de CI con licencia. El job gateware del CI existe y está condicionado a que aparezca un runner etiquetado. Hasta que corra, el hito ZM0 no está cerrado: CI verde sobre el substrato no es lo mismo que un BOOT.BIN reproducible byte a byte.

Estado de los puntos de Z0

Punto de Z0 Estado
Estructura de repositorio Hecho
Paquete único de parámetros con FS_HZ Hecho, con gate de regeneración y de constante hardcodeada
Flujo Vivado no-project en Tcl Escrito, no ejecutado (falta Vivado)
Runner cocotb de doble backend L0 hecho. El doble backend no se hace así: P-09 decidido, L1 es SystemVerilog nativo con oráculo por fichero; arnés verificado, flujo xsim sin ejecutar
Modelo dorado NumPy + generador de vectores Hecho
Congelado del esquema DRx↔DSP v0.1 Hecho, con codegen para C, Rust y Python
Gates de CI Hechos salvo los que necesitan Vivado
BOOT.BIN reproducible byte a byte Pendiente: depende de Vivado