Skip to content

GF-T16 multiply: correct RTL, correct netlist, wrong bitstream through openXC7's DSP path #381

Description

@gHashTag

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions