Known Issues & Bring-up Findings¶
Pitfalls encountered while verifying and bringing up this IP, kept out of the regular guides on purpose. Each entry states the symptom, the cause and the fix/workaround as applied in this repository. SoC-level findings (linker script, UART baud rate, simulator flags of the hatch build) are documented in the hatch repository’s Known issues page instead.
Simulation / testbench¶
TB race at the OBI port (Verilator --timing)¶
Task code that drives stimulus with blocking assignments right after a
@(posedge clk) resumption executes before the FFs of the same time
step. Consequences: double acceptance of requests and missed one-cycle
rvalid pulses. Rule (applied in test/tb_qspi_top.sv, to be adopted in
new TBs): drive stimulus on negedges only, and check gnt in the request
cycle after a #1ps settle.
Yosys fsm pass miscompiles certain FSMs¶
FSMs whose state register is written in two places of the same process
(spi_test_master.sv) were re-encoded incorrectly: RTL sim green, netlist
dead (stuck in StIdle). Fix: (* fsm_encoding = "none" *) on the state
signals. Diagnosis method that found it: post-synthesis simulation of the
yosys netlist with Verilator + cells_sim.v against the same TB (prep
netlist OK, synth_xilinx netlist broken → pass bisection).
Synthesis / place & route (openXC7 flow)¶
yosys needs the slang frontend¶
read_verilog -sv already fails on parameter string INIT_FILE. Use
yosys -m slang with read_slang (the OSS CAD Suite ships slang.so).
nextpnr-xilinx XDC parser is a minimal subset¶
No set_property -dict { ... }, no whitespace inside { }
([get_ports { x }] → assertion str.back() == '}'), no -waveform.
One property per line, [get_ports {x}] without spaces.
create_clock is effectively ignored¶
nextpnr-xilinx checks timing against its 12 MHz default and reports “PASS”
even if the design is slower than the board clock. Read Fmax from the log
yourself (make check-fmax in the Makefiles). The FPGA tops here run on
half the board clock (50 MHz) for that reason; the hatch SoC top runs at
20 MHz.
LUTRAM (RAM256X1S) cannot be placed¶
nextpnr-xilinx fails on distributed-RAM primitives. Synthesise with
-nolutram; small memories then become FFs — keep model memories small
(MEM_ADDR_BITS, loopback uses 1 KiB).
IOBUF / tri-state is non-functional¶
yosys’ automatic inout lowering produces output-only buffers in this
flow (confirmed by an isolation test). All board-to-board lanes are
therefore wired unidirectionally (separate a2b/b2a pin groups, see
FPGA Test Setups (Arty A7)); nothing in the test setups relies on z states.
This is specific to the yosys/nextpnr-xilinx flow, not a hardware
limitation: Vivado’s synthesis handles the standard oe ? drive : 1'bz
idiom natively, confirmed both on fpga/vivado/top_model.sv here and on the
hatch SoC side (hatch repo, docs/fpga_vivado_flow.md) – real tri-state,
fewer wires, FPGA Test Setups (Arty A7) setup 3.
Async-CS constructs do not map¶
model/s23lc1024.sv uses posedge cs_ni simultaneously as a clock
(bus-mode switch) and as an async reset of the shift FFs. On the FPGA this
forces CS onto a global clock buffer and a data mux — unroutable, or the
slave hangs in CS reset (proven via a bus-spy bitstream: SCK edges arrived,
bit_cnt/active stayed 0). On hardware, use the fully synchronous
fpga_sram_slave.sv, which oversamples cs/sclk/data with the board
clock. The behavioural model remains the simulation reference.
Auto-start pulse lost at configuration¶
A start pulse fired in the first cycles after configuration is swallowed
by the GSR release. top_loopback waits ~10 ms (BOOT_BITS) before
starting.
BUFG-promoted pins cannot reach slice data pins¶
nextpnr promotes CS/SCLK to BUFG clocks; a BUFG net cannot additionally route to slice data inputs (“Unrouteable … BUFGCTRL -> DFFMUX”). The activity LED therefore synchronises SIO0 (a pure data net) instead of CS.
Board / host¶
openFPGALoader: unable to open ftdi device¶
udev rules for the Digilent FTDI (0403:6010) missing or not reloaded.
Install the rules (usually shipped with the package), re-plug the board,
verify with openFPGALoader --scan-usb without sudo.
Debug methodology for dead links¶
A single dead data wire (here: SIO0) looks exactly like a logic bug — CS/SCK/other lanes arrive, one lane shows zero edges. Before debugging logic, load a small bus-spy bitstream on the slave board that counts edges per lane and reports the decoded opcode over its own UART. It separates “command does not arrive” from “response does not come back” and finds broken jumper wires in minutes.