Repository navigation
fpga(build): skip t27b-only bitstream specs in fpga-build, not teach gen-verilog a second lowering (rc_filter_ax7203, ddr3_head_bandwidth) #10300
Description
Decision on the red fpga-lint and elaboration ratchet that rc_filter_ax7203 and ddr3_head_bandwidth bring to master (follow-up of #10294 / PR #10296; the ddr3 spec itself belongs to epic #10024 and is not touched).
Measured (Railway lab, t27c from fix/rc-filter-lint-10276)
t27c fpga-build --smoke, then the CI loop yosys -p "read_verilog -sv -DSIMULATION f.v; hierarchy -top M" over build/fpga/generated/*.v: 54 of 56 modules pass, ddr3_head_bandwidth and rc_filter_ax7203 fail ("Non-constant function call in constant expression" at localparam clkbuf = IBUFDS(...)). tools/check_elab_ratchet.py: 278 errors against a baseline of 214; rc_filter_ax7203 is 8 (a recorded KNOWN GAP) and ddr3_head_bandwidth is NEW at 64.
Cause: both specs are written in t27b's bitstream idiom. Pins are const x : bool = undefined; plus x_LOC / x_IOSTANDARD string attributes, and primitives are empty-bodied extern fns returning a struct (const clkbuf : IbufdsOut = IBUFDS(a, b);). t27b verilog (specs/tri/t27b/verilog_plan.t27) lowers that to ports and module instances, and its output is what the board-verified bitstreams are built from. t27c gen-verilog has no lowering for it and prints localparam lines.
The decision
Two fixes were on the table.
(a) t27c gen-verilog learns pins (as ports) and empty-bodied struct-returning extern fns (as module instances).
(b) t27c fpga-build skips the specs that are t27b-only bitstream specs, says so on its output, and the two baseline rows go away.
Chosen: (b). Reasons:
- The shipped RTL of these cells is
t27b verilogoutput, nevert27c gen-verilogoutput. Making the second one parse does not make the first one any better; it adds a second, unused lowering. - (a) cannot be small. To produce an instance that yosys accepts, gen-verilog has to copy t27b's conventions: port naming for pins, the
btn_Oname of an instance output read fromon_clock, parameter-by-name binding for the PLL, clock and reset wiring. That is one rule living in two homes, the recorded defect of this codebase family, and it is hundreds of lines of hand-written Rust, and the foreign-budget gate allows no net growth. The ddr3 spec is the hard case: its 64 errors are one class (unbound parameter, cascading from the pins and thelitedram_coreinstance), but closing them means lowering a 60-odd-port extern correctly, which only t27b has been checked against on a board. - (b) is a few lines in
run_fpga_build, paid for by folding two identical blocks there, so the Rust debt shrinks, and does not touch either spec.
Cost, stated plainly: the t27c-generated Verilog of these two specs is no longer linted. That output was never the shipped RTL; the shipped RTL is covered by the t27b gates and the board receipt (rc_filter 2130/2130 PASS). If t27b verilog ever runs in CI, its output is what should be linted, and that is the follow-up.
How a spec is recognised as t27b-only: it declares at least one pin attribute, a top-level const <name>_LOC : str = "<ball>";. That is t27b's own idiom for a pin, so no spec has to change or be resealed. wasm_board_ax7203 (also KIND = "board-cell", no pins) is not skipped and keeps its 0 row.
Goal
fpga-lint and the elaboration ratchet are green again for rc_filter_ax7203 and ddr3_head_bandwidth without teaching t27c a second lowering, and the skip is visible, not silent.
Boundary
- bootstrap/src/main.rs :: run_fpga_build
- tools/elab_baseline.txt
User Scenarios
- Given a spec under
specs/fpga/with a_LOCpin attribute, whent27c fpga-build --smokeruns, then it printsSKIP <name> (t27b bitstream spec)and writes no<name>.v. - Given a spec without pins such as
wasm_board_ax7203, when the same command runs, then it is generated exactly as before. - Given the CI yosys loop and
tools/check_elab_ratchet.pyover the result, when they run, then both pass with no NEW row.
Requirements
- FR-001:
run_fpga_buildMUST skip a spec that contains a top-level_LOCpin attribute, and MUST print oneSKIPline naming it and the reason. - FR-002:
run_fpga_buildMUST NOT skip any spec that has no pin attribute, and MUST still fail whengen-verilogfails on a spec it does not skip. - FR-003:
tools/elab_baseline.txtMUST drop therc_filter_ax7203row and MUST NOT gain addr3_head_bandwidthrow, with the notes rewritten to say why. - FR-004: No
.t27spec, seal or workflow file is changed.
Success Criteria
t27c fpga-build --smokeexits 0 and generates 53 modules plus the wrapper, with 2SKIPlines.- The CI yosys loop reports 0 failing modules.
tools/check_elab_ratchet.pyexits 0 with 0 NEW rows and a total of 206 errors, the master baseline.bootstrap/src/main.rsends with fewer hand-written lines than it started with (the foreign-budget gate allows no growth): the skip adds 8, and the two identical yosys script blocks inrun_fpga_buildare folded into one.
Close criteria
- The PR merges and
fpga-lintand the elaboration ratchet no longer name either module.
Activity
fpga(build): fpga-build skips t27b bitstream specs; no gen-verilog ro…
fpga(build): fpga-build skips t27b bitstream specs; no gen-verilog ro…
fpga(build): fpga-build skips t27b bitstream specs; no gen-verilog ro…
Merge master into spec/e2e-board-logic: keep both notes in tools/elab…