Skip to content

openXC7 emits a wrong bitstream from a correct netlist for SRL16E (same class as DSP48E1) #2173

Description

@gHashTag

Summary

openXC7 emits a wrong bitstream from a correct netlist for SRL16E. This is
the same defect class as the already-recorded live-operand DSP48E1 failure
(tri-net#381). Both pass the wrong-part → ours Done 0 → done 1 acceptance
criterion while computing the wrong answer, and every tool upstream reports
success.

Status: [измерено] — reproduced on three QMTech XC7A200T-FGG676 dice.

Symptom

A design whose only unusual feature is a long shift register returns wrong values
from the fabric. Nothing upstream complains:

  • yosys elaborates and maps without error;
  • nextpnr places and routes and reports a valid Fmax;
  • fasm2frames and xc7frames2bit produce a bitstream of the correct size;
  • the die accepts it — a wrong-part bitstream drives Done to 0 and ours returns
    it to 1, so the acceptance criterion passes;
  • the JTAG readback register works and returns the design's magic word.

Only the computed values are wrong.

Reproduction

Design: a 593-bit shift register loaded 31 bits per BSCANE2 UPDATE, with 16
combinational truth tables reading scattered bits of it and reporting through
CAPTURE. The Verilog source is byte-identical between the two runs; only the
yosys flag differs.

synthesis cells rows agreeing with the reference model
synth_xilinx -family xc7 -nodsp 44 SRL16E + 58 FDRE 0 / 6
synth_xilinx -family xc7 -nodsp -nosrl 0 SRL16E + 362 FDRE 24 / 24

The reference model was independently confirmed against the emitted Verilog
under Icarus Verilog 13.0: 64 of 64 vectors exact. So the netlist is right and
the bitstream is not.

Toolchain: yosys 0.63, nextpnr-xilinx (openXC7 fork), prjxray-db artix7,
part xc7a200tfbg676-1, host macOS 25.3.0 / arm64.

How it was localised, for whoever hits this next

  1. Simulate the emitted Verilog against the model. If it passes, the defect
    is below the netlist. This step alone would have saved three waves.
  2. Build a small bitstream that reports the suspect register's own contents.
    Ours was 33 LUT and exonerated the transport in one pass.
  3. Read the cell list, not the LUT count. SRL16E was visible in the stat
    output for a whole wave before anyone looked past the first line.

Mitigation, already in the tree

synth_xilinx -nodsp -nosrl is now mandatory for this toolchain, and
t27c yostat exits 2 when SRL16E, SRLC32E or DSP48E1 appears in a
synthesis log, naming the flag to add:

!! KNOWN-BAD PRIMITIVES FOR openXC7 !!
44 shift-register LUT(s). The bitstream is wrong while the netlist is right.
   Re-synthesise with `synth_xilinx -nosrl`.
A bitstream built from this netlist will load, pass the 0->1 acceptance
criterion, and compute the wrong answer.

Full write-up: docs/reports/OPENXC7-SRL16E-DEFECT.md.

What is NOT claimed

The root cause inside openXC7 is not identified — only that the defect is
reproducible, primitive-specific, and removed by suppressing inference of that
primitive. Whether it lies in nextpnr's SRL placement, in the fasm emission, or
in prjxray's database for SLICEM shift registers is not measured.

Wider lesson recorded

Done 0 → done 1 proves a bitstream was accepted by the configuration
engine
, never that it implements the netlist. Pair it always with a
design-specific readback that a wrong build cannot produce.

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