Summary
gft16_mul is correct — in simulation, in synthesis, and when mapped to LUTs. But a bitstream built from the DSP-mapped netlist through the openXC7 flow (yosys → nextpnr-xilinx → prjxray) computes the wrong answer on silicon.
Your RTL is not implicated and your published areas reproduce exactly. This is a warning for anyone building GF-T through openXC7 rather than your own flow.
What reproduces exactly
fpga/gft/SYNTH_RESULTS.md was re-run on a different host with yosys 0.63 (yours: 0.65), using your .ys scripts unmodified:
| unit |
DSP claim/meas |
LUT claim/meas |
CARRY4 claim/meas |
gft16_mul |
1 / 1 |
47 / 47 |
18 / 18 |
gft_add |
0 / 0 |
483 / 483 |
45 / 45 |
gft_alu |
3 / 3 |
634 / 634 |
114 / 114 |
gft_dot4_tile |
4 / 4 |
705 / 708 |
124 / 124 |
gft_dot4 |
12 / 12 |
1673 / 1673 |
303 / 303 |
Four exact, one off by 3 LUT (0.4%, yosys version). No discrepancy of any kind in your numbers.
What fails
gft16_mul + gft_mul verbatim, in a port-less BSCANE2 harness, checked by your own KAT vectors from gft16_mul_kat_tb.v — no expected value re-derived, so no second implementation in the loop.
| build |
φ¹·φ¹ → (42,0) |
1.5×1.5 → (43,64) |
cells |
| iverilog, behavioural RTL |
pass |
pass |
— |
gate-level sim of the synthesised netlist vs xilinx/cells_sim.v |
pass |
pass |
1 DSP48E1 |
| bitstream, on silicon |
pass |
FAIL |
1 DSP48E1, 56 LUT |
bitstream, -nodsp, on silicon |
pass |
pass |
0 DSP, 53 LUT |
Hardware: 3× QMTech Wukong XC7A200T-FGG676, idcode 0x3636093. Five stable reads per build per board, each bracketed with a wrong-part bitstream so Done went 0 → 1 before every read. Reply nibble is {v0_ok, v1_ok, done, sig}:
DSP build a5a5a5aa v0 ok, v1 FAIL boards 1:4, 1:6, 1:8
LUT-only build a5a5a5af v0 ok, v1 ok boards 1:4, 1:6, 1:8
Deterministic, three dice, both directions.
Where the fault is — and is not
Cleared: the RTL (passes behavioural sim) and yosys (its DSP-mapped netlist passes gate-level sim against yosys's own DSP48E1 model).
Remaining: nextpnr-xilinx FASM emission, or prjxray's DSP48E1 frame model.
The natural hypothesis — that the DSP's operating mode never reaches the bitstream, which would explain why only the nonzero-product vector fails — is refuted: the FASM carries OPMODE, ALUMODE, INMODE and the register controls (21 non-GND DSP lines), and prjxray models the tile with 436 segbits.
Separating nextpnr from prjxray needs a reference bitstream for the same netlist (Vivado, or a DSP48E1 unit test with known frames). Not attempted here.
Practical consequence
On the openXC7 flow, -nodsp costs 3 LUT (56 → 53) and both vectors pass. The DSP is not a saving on this flow.
Your on-chip claims were made through your own flow on an AX7203, which this does not test — it tests openXC7 on a QMTech board.
Reproduce
yosys -p "read_verilog -sv gft_mul.v gft16_mul.v <harness>.v; \
synth_xilinx -family xc7 -top <harness> -flatten; write_json k.json"
nextpnr-xilinx --chipdb xc7a200t*.bin --json k.json --fasm k.fasm
# fasm2frames, xc7frames2bit, openFPGALoader
# expect a5a5a5aa ; then add -nodsp and expect a5a5a5af
Full write-up and harness: docs/reports/TRINET-DSP-DEFECT-W723.md and fpga/verilog/gft_kat_jtag.v in gHashTag/t27, branch claude/igla-fpga-improvements-3f5e1a.
Summary
gft16_mulis correct — in simulation, in synthesis, and when mapped to LUTs. But a bitstream built from the DSP-mapped netlist through the openXC7 flow (yosys → nextpnr-xilinx → prjxray) computes the wrong answer on silicon.Your RTL is not implicated and your published areas reproduce exactly. This is a warning for anyone building GF-T through openXC7 rather than your own flow.
What reproduces exactly
fpga/gft/SYNTH_RESULTS.mdwas re-run on a different host with yosys 0.63 (yours: 0.65), using your.ysscripts unmodified:gft16_mulgft_addgft_alugft_dot4_tilegft_dot4Four exact, one off by 3 LUT (0.4%, yosys version). No discrepancy of any kind in your numbers.
What fails
gft16_mul+gft_mulverbatim, in a port-less BSCANE2 harness, checked by your own KAT vectors fromgft16_mul_kat_tb.v— no expected value re-derived, so no second implementation in the loop.xilinx/cells_sim.v-nodsp, on siliconHardware: 3× QMTech Wukong XC7A200T-FGG676, idcode
0x3636093. Five stable reads per build per board, each bracketed with a wrong-part bitstream soDonewent 0 → 1 before every read. Reply nibble is{v0_ok, v1_ok, done, sig}:Deterministic, three dice, both directions.
Where the fault is — and is not
Cleared: the RTL (passes behavioural sim) and yosys (its DSP-mapped netlist passes gate-level sim against yosys's own DSP48E1 model).
Remaining: nextpnr-xilinx FASM emission, or prjxray's DSP48E1 frame model.
The natural hypothesis — that the DSP's operating mode never reaches the bitstream, which would explain why only the nonzero-product vector fails — is refuted: the FASM carries
OPMODE,ALUMODE,INMODEand the register controls (21 non-GND DSP lines), and prjxray models the tile with 436 segbits.Separating nextpnr from prjxray needs a reference bitstream for the same netlist (Vivado, or a DSP48E1 unit test with known frames). Not attempted here.
Practical consequence
On the openXC7 flow,
-nodspcosts 3 LUT (56 → 53) and both vectors pass. The DSP is not a saving on this flow.Your on-chip claims were made through your own flow on an AX7203, which this does not test — it tests openXC7 on a QMTech board.
Reproduce
Full write-up and harness:
docs/reports/TRINET-DSP-DEFECT-W723.mdandfpga/verilog/gft_kat_jtag.vingHashTag/t27, branchclaude/igla-fpga-improvements-3f5e1a.