7 · Resultados¶
Todo lo de esta página es salida real de una ejecución sobre el árbol limpio. Reproducible con:
make venv && make check
Resumen¶
| Gate | Herramienta | Estado |
|---|---|---|
| Paquete de parámetros al día | tools/gen_params.py --check |
verde |
| Coeficientes congelados al día | tools/gen_coeffs.py --check |
verde |
| Contrato al día | tools/gen_contract.py --check |
verde |
| Sin constantes de reloj | tools/check_hardcoded_clock.py |
verde |
| Lint de Python | Ruff 0.14.5 | verde |
| Lint de HDL | Verilator 5.006, -Wall |
verde |
| Regresión | pytest 8.4.2 | 69 tests, verde |
| Síntesis e implementación | Vivado | no ejecutado, falta la herramienta |
BOOT.BIN reproducible |
bootgen | no ejecutado, falta la herramienta |
Los gates de generación y lint¶
$ .venv/bin/python tools/gen_params.py --check
parámetros generados al día
$ .venv/bin/python tools/gen_coeffs.py --check
coeficientes al día
$ .venv/bin/python tools/gen_contract.py --check
contrato generado al día
$ .venv/bin/python tools/check_hardcoded_clock.py
sin constantes de reloj hardcodeadas
$ .venv/bin/ruff check .
All checks passed!
$ make lint-hdl
verilator --lint-only -Wall --timing sim/verilator_waivers.vlt \
rtl/generated/drx_params_pkg.sv rtl/ssa/drx_ssa_pkg.sv \
rtl/drx_heartbeat.sv rtl/drx_top.sv --top-module drx_top
El lint de HDL no imprime nada cuando pasa. Verilator con -Wall trata los avisos como errores, así
que salida vacía y código 0 significa cero avisos.
El gate de reloj, comprobado en las dos direcciones¶
Un gate que nunca ha fallado no se sabe si funciona. Este se probó con una constante plantada:
$ echo 'localparam int FS = 100_000_000;' > /tmp/bad.sv
$ .venv/bin/python tools/check_hardcoded_clock.py /tmp/bad.sv
/tmp/bad.sv:1: constante de reloj hardcodeada: 100_000_000
localparam int FS = 100_000_000;
1 constante(s) sospechosa(s). ...
$ echo $?
1
Medidas del modelo dorado¶
Números producidos por el propio modelo, no estimaciones.
CIC · N=5, R=52, M=1¶
| Magnitud | Valor | De dónde sale |
|---|---|---|
| Ganancia en continua | 380 204 032 = 52⁵ | Medida sobre entrada constante |
| Bits de crecimiento | 29 | ⌈5·log₂52⌉ |
| Ancho de registro | 45 bits | 16 de entrada + 29 |
| Caída en el borde de banda de paso (0,09) | −0,580 dB | Cic.response |
FIR compensador · 63 taps, coeficientes de 18 bits¶
| Magnitud | Valor |
|---|---|
| Ganancia de continua entera | 552 725 |
| Coeficiente mínimo / máximo | −23 885 / 131 071 |
| Rizado de la cascada CIC+FIR en 0…0,06 | 0,006 dB |
| Rizado de la cascada CIC+FIR en 0…0,09 | 0,909 dB |
| Atenuación en la banda que pliega (≥0,16) | −58,7 dB |
El compensador reduce el rizado en un factor 40 en los dos tercios interiores de la banda y lo empeora en el borde. Es un punto de diseño mejorable, documentado en la página del DDC, no un bug: los 63 taps y la ventana de Hamming son un compromiso que Z1 revisará contra el cierre de recursos real.
Semibanda del modo grueso · 23 taps¶
| Magnitud | Valor |
|---|---|
| Ganancia de continua entera | 328 067 |
| Atenuación en la banda que pliega (≥0,35) | −69,4 dB |
| Rizado de banda de paso (0…0,15) | 1,20 dB |
NCO¶
| Magnitud | Valor |
|---|---|
| Palabra de fase | 1 030 792 151 (idéntica en las dos plataformas) |
| Peor espurio de truncamiento | −86,4 dBc |
Cadena completa¶
Tono de −3 dBFS, 60 000 muestras, pico de entrada 23 197:
| Modo | R | Muestras de salida | |I+jQ| medio | Desviación relativa |
|---|---|---|---|---|
| fino | 208 | 288 | 4330,0 | 0,00e+00 |
| grueso | 416 | 144 | 2709,0 | 0,00e+00 |
Desviación exactamente cero: la amplitud es constante bit a bit.
Huella del oráculo¶
fine 192 muestras edf20575a4b82e3b96a2bd4333b60e0922e69cd1554ab7504154eb2aadcd6cca
coarse 96 muestras d51dee4c0b61b30ea7a93dd6dd3aa5ca0d1c56e2f37b8979913d5ec4bef76feb
Simulación L0¶
0.00ns INFO cocotb Running on Verilator version 5.006 2023-01-22
0.00ns INFO cocotb Running tests with cocotb v1.9.2
350.00ns INFO cocotb.regression test_periodo_del_latido passed
460.00ns INFO cocotb.regression test_reset_asincrono passed
** tb_drx_heartbeat.test_periodo_del_latido PASS 350.00 0.00 81042.87 **
** tb_drx_heartbeat.test_reset_asincrono PASS 110.00 0.00 81732.09 **
Desde limpio tarda unos 17 s, casi todo compilando el C++ que genera Verilator.
Contrato: C y Python, byte a byte¶
$ ./dump # programa en C con la cabecera generada
52 44 4d 4c 00 01 01 00 64 73 00 00
sizeof header=12 ray=36 status=28 config=48 config_ack=8 afc=16
$ .venv/bin/python dump.py # implementación de Python generada
52 44 4d 4c 00 01 01 00 64 73 00 00
Firmware¶
$ make -C fw check
auto-comprobación de parámetros: OK
$ make -C fw check PLATFORM=zu9
auto-comprobación de parámetros: OK
Compila y pasa para las dos plataformas, con gcc de host. La toolchain cruzada y el BSP llegan en
Z4.
La regresión completa¶
69 tests, todos en verde:
model/tests/test_bloques.py::test_nco_emite_en_la_frecuencia_normalizada_del_if PASSED
model/tests/test_bloques.py::test_nco_respeta_el_fondo_de_escala PASSED
model/tests/test_bloques.py::test_el_acumulador_de_fase_envuelve PASSED
model/tests/test_bloques.py::test_el_nco_es_determinista PASSED
model/tests/test_bloques.py::test_ganancia_en_continua_del_cic PASSED
model/tests/test_bloques.py::test_ancho_de_registro_de_hogenauer PASSED
model/tests/test_bloques.py::test_el_cic_diezma_por_r PASSED
model/tests/test_bloques.py::test_el_cic_rechaza_un_ancho_que_no_cabe_en_int64 PASSED
model/tests/test_bloques.py::test_la_respuesta_del_cic_cae_monotona_en_la_banda_de_paso PASSED
model/tests/test_bloques.py::test_los_coeficientes_congelados_estan_al_dia PASSED
model/tests/test_bloques.py::test_el_fir_tiene_los_taps_del_paquete_de_parametros PASSED
model/tests/test_bloques.py::test_el_fir_compensa_el_droop_del_cic PASSED
model/tests/test_bloques.py::test_el_fir_atenua_lo_que_pliega_sobre_la_banda_de_paso PASSED
model/tests/test_bloques.py::test_el_semibanda_diezma_por_dos PASSED
model/tests/test_bloques.py::test_el_semibanda_atenua_lo_que_pliega PASSED
model/tests/test_bloques.py::test_faltan_coeficientes_da_un_error_util PASSED
model/tests/test_chain.py::test_el_diezmado_coincide_con_el_paquete_de_parametros[fine] PASSED
model/tests/test_chain.py::test_el_diezmado_coincide_con_el_paquete_de_parametros[coarse] PASSED
model/tests/test_chain.py::test_un_tono_en_el_if_baja_a_continua[fine] PASSED
model/tests/test_chain.py::test_un_tono_en_el_if_baja_a_continua[coarse] PASSED
model/tests/test_chain.py::test_el_oraculo_es_reproducible_bit_a_bit[fine] PASSED
model/tests/test_chain.py::test_el_oraculo_es_reproducible_bit_a_bit[coarse] PASSED
model/tests/test_chain.py::test_el_modo_grueso_diezma_el_doble_que_el_fino PASSED
model/tests/test_chain.py::test_una_entrada_fuera_de_banda_se_rechaza PASSED
model/tests/test_chain.py::test_el_offset_de_continua_se_rechaza PASSED
model/tests/test_chain.py::test_el_ruido_no_rompe_la_cadena_y_es_reproducible PASSED
model/tests/test_chain.py::test_una_cadena_inconsistente_con_los_parametros_falla_ruidosamente PASSED
model/tests/test_chain.py::test_la_salida_se_puede_enrejar_en_rayos PASSED
model/tests/test_fixed.py::test_limites_con_signo PASSED
model/tests/test_fixed.py::test_wrap_es_complemento_a_dos PASSED
model/tests/test_fixed.py::test_saturate_marca_overflow_por_muestra PASSED
model/tests/test_fixed.py::test_redondeo_es_medio_hacia_arriba PASSED
model/tests/test_fixed.py::test_truncamiento_va_hacia_menos_infinito PASSED
model/tests/test_fixed.py::test_quantize_satura_lo_que_se_sale PASSED
model/tests/test_fixed.py::test_growth_bits PASSED
model/tests/test_gating_y_vectores.py::test_conteo_de_bins_por_modo PASSED
model/tests/test_gating_y_vectores.py::test_los_rayos_completos_no_se_marcan_truncados PASSED
model/tests/test_gating_y_vectores.py::test_un_rayo_corto_se_marca_en_vez_de_descartarse PASSED
model/tests/test_gating_y_vectores.py::test_tlast_cae_en_la_ultima_muestra_de_cada_rayo PASSED
model/tests/test_gating_y_vectores.py::test_gating_rechaza_entradas_descuadradas PASSED
model/tests/test_gating_y_vectores.py::test_el_tono_por_defecto_sale_en_el_if PASSED
model/tests/test_gating_y_vectores.py::test_la_amplitud_en_dbfs_es_la_pedida PASSED
model/tests/test_gating_y_vectores.py::test_la_entrada_sobre_escala_satura_en_vez_de_envolver PASSED
model/tests/test_gating_y_vectores.py::test_los_vectores_son_identicos_en_las_dos_plataformas PASSED
model/tests/test_gating_y_vectores.py::test_el_desbalance_iq_cambia_la_señal_y_es_determinista PASSED
model/tests/test_gating_y_vectores.py::test_el_ruido_exige_semilla PASSED
model/tests/test_params.py::test_hay_dos_plataformas PASSED
model/tests/test_params.py::test_if_normalizado_identico_en_las_dos_plataformas PASSED
model/tests/test_params.py::test_palabra_de_fase_del_nco_es_invariante PASSED
model/tests/test_params.py::test_el_if_cae_en_un_entero_de_hz PASSED
model/tests/test_params.py::test_la_descomposicion_de_la_cadena_reproduce_r1_y_r2 PASSED
model/tests/test_params.py::test_tamano_de_celda_en_la_plataforma_objetivo PASSED
model/tests/test_params.py::test_prf_de_pared_se_dilata_y_el_registro_no PASSED
model/tests/test_params.py::test_los_ficheros_generados_estan_al_dia PASSED
model/tests/test_params.py::test_el_toml_no_declara_frecuencias_fuera_de_platform PASSED
sim/tests/test_l0_heartbeat.py::test_l0_heartbeat_verilator PASSED
sim/tests/test_l0_heartbeat.py::test_l1_declara_su_bloqueo PASSED
contract/tests/test_contract.py::test_los_ficheros_generados_estan_al_dia PASSED
contract/tests/test_contract.py::test_los_tres_lados_declaran_el_mismo_tamano PASSED
contract/tests/test_contract.py::test_c_y_python_producen_los_mismos_bytes PASSED
contract/tests/test_contract.py::test_ida_y_vuelta_en_python PASSED
contract/tests/test_contract.py::test_el_codigo_de_error_de_d09_existe PASSED
contract/tests/test_contract.py::test_los_tipos_de_mensaje_son_unicos PASSED
fw/tests/test_params_header.py::test_el_firmware_ve_los_mismos_parametros_que_el_modelo PASSED
fw/tests/test_params_header.py::test_el_firmware_compila_tambien_para_la_plataforma_objetivo PASSED
Lo que estos 69 tests no demuestran¶
Merece un apartado propio, porque la diferencia entre «CI verde» y «funciona» es donde se pierden los proyectos.
No demuestran que el modelo coincida con la IP de Xilinx. El modelo está escrito contra la configuración pretendida del DDS/CIC/FIR Compiler, no contra la IP real: en Z0 no hay Vivado. Esa comparación es Z1, y puede obligar a ajustar modos de redondeo.
No demuestran que el RTL haga el DDC. El RTL de Z0 es un divisor de reloj. Lo que la simulación prueba es que el substrato está cerrado, no que el receptor funcione — no existe todavía.
No demuestran nada sobre temporización. No se ha sintetizado nunca. Que el 7Z020-1 cierre a 100 MHz con cuatro canales es una hipótesis, y está listada como riesgo con su mitigación (bajar a 62,5 MHz o a dos canales).
No demuestran que el BOOT.BIN sea reproducible. Nunca se ha construido uno.
No dicen nada sobre JESD204B, clocking, SYSREF, 250 MSPS, el frontal analógico, el DAC AD9129 ni RS-422. Ese es el riesgo número uno del proyecto y no se reduce con trabajo de software. Ver P-03.
Y el recordatorio que AGENTS.md repite: no escribas «validado» donde corresponde «validado en
ZedBoard» — y ahora mismo, ni siquiera eso: corresponde «validado en simulación».
Lo siguiente¶
- Una máquina con Vivado, y ejecutar
tcl/build.tclpara las dos plataformas. - Decidir P-09: qué hace L1 ahora que se sabe que cocotb no habla con xsim.
- Empaquetar el
BOOT.BINcuando Z4 dé los ELF, y comprobar que se repite byte a byte.
Con eso, ZM0 se cierra y empieza Z1 — el DDC de verdad, contra este oráculo.
Anterior: 6 · Gateware · Volver al índice del tutorial