propagate_IOB_SING and propagate_IOI_SING set the top SING-row tile's alias
start_offset to 0, mapping the full tile's lower words (0-1) into the tile's
only frame words (99-100). But nextpnr-xilinx targets the full tile's UPPER
OLOGIC/IOB words (2-3) on the top SING tile; under start_offset 0 those map to
absolute frame words 101-102, which don't exist, so fasm2frames raises
"invalid word address" and silently drops the features (e.g. a VC707 LED or
UART output on LIOI_SING_X82Y51.OLOGIC_Y0).
start_offset 2 (effective offset 97) lands words 2-3 at abs 99-100 -- matching
the bottom SING tiles and the HW-verified tilegrid data fix. Confirmed by
re-running fuzzer 036-iob18-ologic-sing (OLOGIC_Y0.OMUX.D1 at abs word 100) and
by the open-flow UART DSP calculator computing correctly on hardware.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The virtex7 CLB segbits had duplicate OUTMUX.O5 entries; fasm2frames
resolves duplicates last-wins and was selecting the INCOMPLETE variant,
which omits the shared O5/O6 xMUX-enable bit (e.g. SLICEL_X1.COUTMUX.O5
missing 31_43, SLICEL_X0.BOUTMUX.O5 missing 30_20, SLICEL_X0.DOUTMUX.O5
missing 30_56). LUT outputs routed out of a slice via the xMUX were
therefore under-encoded, corrupting any design that uses them (FSM/data
paths), while designs that don't (counters, shift regs) were unaffected.
Dedupe segbits_clbll_{l,r}.db and segbits_clblm_{l,r}.db keeping the
complete OUTMUX definition (the one including the shared xMUX-enable bit).
Hardware-confirmed on a VC707: the open-flow telegraph (bit-banged UART)
now transmits correctly end-to-end (nextpnr -> fasm2frames -> bitstream,
no Vivado, no frame patch); johnson and bincount are byte-identical
(config) and unaffected.
Force-added like segbits_liob18/riob18 (database/ is otherwise ignored).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A SING-row sibling of 036-iob18-ologic. The parent fuzzer filters
to IOB18S / IOB18M (diff-pair main / secondary), leaving the IOB18
site type in *_SING tiles uncharacterised. This fuzzer's filter
is the complement: only the IOB18 site type, only in *_SING
tiles. Pushes to lioi_sing / rioi_sing via the two new mergedb
modes.
utils/mergedb.sh: add the two missing modes. The captured
specimens emit LIOI_SING. and RIOI_SING. entries in the same
file; the new cases grep each side into its own merge target so
the existing segbits_lioi_sing.db / segbits_rioi_sing.db are
populated symmetrically without needing to refactor the fuzzer
into two passes.
Note: the SING-tile frame layout has 2 words (offsets 99..100),
so OLOGIC features at word offsets 30+ within the regular LIOI
tile cannot be straightforwardly mirrored. The 10 features the
fuzzer captures (ZINV_CLK, ODDR/OSERDES SRTYPE/TSRTYPE, OSERDES
DATA_WIDTH variants) all land within the SING tile's two-word
window. The OMUX.D1 / OQUSED / OSERDES.DATA_RATE_TQ.BUF features
nextpnr-xilinx emits for transparent OBUF route-thrus on V7
SING-row IOBs (VC707 led[?] @ LIOI_SING_X82Y51) still need a
separate solution -- they likely live in an aliased frame
through the neighbouring full LIOI tile. Tracking that as a
separate follow-up.
Companion to a4e6351 — the IN_ONLY segbit over-claim that has to
land in the on-disk DB for the open-source FASM path to work
end-to-end (a4e6351 documented the change but the .db files are
gitignore'd via the upstream `database/` rule; force-adding the
two patched rows here).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two surgical fixes that together close the FASM -> frames -> bitstream
path for designs that use IOB_Y1 (slave) as an input alongside IOB_Y0
(master) as an output in the same LIOB18/RIOB18 tile. Verified
end-to-end on VC707 (~/johnson_8bit, 8-bit Johnson counter with
LEDs on Y0 and the centre-button input landing on Y1): single
`fasm2frames` + `xc7frames2bit` run with no Vivado in the loop, the
loaded bitstream advances the ring on each button press.
(1) Layer-A — IN_ONLY segbit over-claim.
LIOB18.IOB_Y1.LVCMOS..._IN_ONLY rows previously CLEARed bits
`!38_32 !38_34`. Those two bits actually belong to
INT_L.IOB_COL_BANK_ACTIVE (which SETs them). When a tile has a
Y0 OBUF + Y1 IBUF, both features fire and conflict on the same
physical bits — fasm2frames stops with FasmInconsistentBits.
Drop those two bits from every Y1 IN_ONLY row in LIOB18 and
RIOB18; let the bits default-to-zero unless bank-active sets
them. Verified that the Y0 IN_ONLY rows are untouched.
(2) Layer-B — XRAY_ALLOW_MISSING_FEATURES escape hatch.
fasm_assembler.py: parse_fasm_filename() now respects the env
var XRAY_ALLOW_MISSING_FEATURES=1. When set, missing-feature
lookups become per-line console warnings instead of a
FasmLookupError. Three IOB_Y1 features still need fuzzing
(IBUF_HP_BANK_GLUE, LVCMOS12_LVCMOS15.IN,
LVCMOS12_LVCMOS15_SSTL12_SSTL135_SSTL15.IN_ONLY) — the proper
fix is a fuzzer pass that places IBUFs on Y1 sites and merges
the captured segbits into segbits_{l,r}iob18.db, but until then
the escape hatch keeps the open-source path moving.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
End-to-end recipe for the IBUFDS+BUFG+FDRE+OBUF demo that produced the
first confirmed-working open-flow bitstream on a VC707 (xc7vx485tffg1761-2)
on 2026-06-01. Covers tooling versions, the test design + XDC, build
order (nextpnr-xilinx -> json2dcp+WireOracle -> Vivado lock-and-route ->
write_bitstream), the openFPGALoader command, expected hardware
behaviour, and the three known follow-ups (SLICE pin-assignment CRITICAL,
IOB sitetype-net overwrite, XDC LOC not auto-applied).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
propagate_IOB_SING and propagate_IOI_SING walk each IO column from a
parent IOB/IOI tile down to the SING half-tiles at the column endpoints
and alias the parent's CLB_IO_CLK bits into both halves (offset=0 for
the bottom SING, offset=99 for the top SING). The parent-type
allowlists were missing the HP-bank L-column types:
propagate_IOB_SING: ["LIOB33", "RIOB33", "RIOB18"] # LIOB18 missing
propagate_IOI_SING: ["LIOI3", "RIOI3", "RIOI"] # LIOI missing
On artix7 / kintex7 the leftmost HP column doesn't exist as a parent
LIOB18 / LIOI in the tilegrid, so the omission was latent. On
virtex7 VX (HP-only) both LIOB18 and RIOB18 columns exist, and the
gap surfaces as half the SING IOB / IOI tiles (the L-column ones)
having empty bits in tilegrid.json:
LIOB18_SING: 0/14 with bits -> 14/14
RIOB18_SING: 14/14 (unchanged)
LIOI_SING: 0/14 with bits -> 14/14
RIOI_SING: 14/14 (unchanged)
Add the missing types. Cross-checked against iob18's own measured
parent bases (e.g. LIOB18_X81Y2 -> 0x00421000 lines up with the
propagated LIOB18_SING_X81Y1 base 0x00421000 offset=0 and Y51 offset=99).
Also de-wire the iob18_sing sub-fuzzer from TILEGRID_TDB_DEPENDENCIES:
SING tiles aren't independently addressed (they share the parent IOB's
base with a word-offset variant), and half of iob18_sing's tdb entries
land at an unaligned frame (offset+1) that add_tdb's frame-alignment
assertion would reject anyway. The build rule stays so the fuzzer can
be invoked manually as a Vivado-measurement guard for the propagation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The existing iob18 sub-fuzzer filters to IOB18S (main IOB of a diff
pair) and ioi18 explicitly skips _SING tile types, so the SING-row
IOB18 singletons (one IOB18 site per LIOB18_SING / RIOB18_SING tile)
never had their tilegrid frame addresses resolved. On xc7vx485t this
left 28 tile rows un-addressed in tilegrid.json.
Add a parallel iob18_sing sub-fuzzer: places an IBUF on every SING-row
IOB18 site (14 specimens), bit-diffs to a segbits_tilegrid.tdb, and
hooks into TILEGRID_TDB_DEPENDENCIES alongside iob18 / iob18_int so
add_tdb.py merges the resulting frame addresses into tilegrid.json.
Pairs with task #17 (HP-bank glue end-to-end).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This system standardises on /opt/Xilinx/Vivado/2020.1 not the NFS share
the upstream default points at; honour the local standardisation while
remaining overridable via the env var.
Pairs with task #50 (005-tilegrid virtex7 unaligned-frame fix).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a callout under the project tagline pointing Virtex-7 / VC707 users
straight to the Virtex-7 Port Status section, and note that the
Quickstart Guide assumes the upstream Artix-7 / 2017.2 path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a callout block under the four-repo branch table noting that the
Virtex-7 work was developed and validated against Vivado 2020.1, that
other 2018+ releases may work, and that the upstream-recommended 2017.2
is too old for this device (predates xc7vx485tffg1761-2 HP-bank IOB18
support, several HCLK_IOI/CMT properties the fuzzers query, and the
write_pip_txtdata bulk paths the utils.tcl patch exercises).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add the four-repo upstream branch map (prjxray / nextpnr-xilinx-meta /
nextpnr-xilinx / demo-projects), pointing at the openXC7 mirrors.
- Replace the smoke-test-passes Achievements with the current end-to-end
state: rst_to_led / counter / counter_bufr / telegraph at 0/0 vs Vivado
with zero .frm patches, and the PicoSoC UART demo running on real VC707
silicon at 125 MHz.
- List the 7 codified HP-bank glue segbits (LIOB18 IBUF/OBUF Y0+Y1, RIOB18
IBUFDS, INT_L IOB_COL_OBUF_CASCADE_Y1 / IOB_COL_BANK_ACTIVE /
GFAN_TIE_ROOT_GLUE, HCLK_L BUFRCLK3_ACTIVE) plus the 14 IOB18 silicon
defaults.
- New 'Virtex-7 architecture discoveries' section describing the things
that turned out to differ from Kintex-7 and weren't inherited by
transplant: HP vs HR silicon, HCLK_IOI vs HCLK_IOI3, L/R-side mirror,
the bank-glue category itself (tile-in-use markers / Y0+Y1 OBUF
cascade / PUDC_B / IBUFDS pair root), the .DRIVE. vs .SLEW. classifier
gotcha, HCLK_L BUFRCLK3 leaf, GFAN T-tie INT_L+10 row glue, fasm2bels
NOCLKINV block, nextpnr-xilinx OBUF T-tie convergence + Y137/Y138 wire
mapping, and the PicoSoC RAM128/256X1S packing requirement.
- Goals now reflect what's still open: the 228-bit PicoSoC CLB-glue
family, the 236 missing IOI features, fasm2bels past NOCLKINV, and the
Y137/Y138 nextpnr-xilinx wire mapping.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Failed bitgen with 'ERROR: [DRC PDRC-2] BSCAN_JtagChain: Unsupported
programming for BSCAN site BSCAN_X0Y0 and JTAG_CHAIN attribute value
3.' Same DRC already disabled in fuzzers/005-tilegrid/cfg/generate.tcl
for the same reason — Vivado 2020.1 tightened this check vs 2017.2.
Add the matching disable here.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Was wedging the build at ~7h elapsed in iteration 1 (one specimen at
~40% through a sequential per-net Tcl loop, ~13h/specimen extrapolated
on xc7vx485t). Two compounding problems, both contained to this fuzzer:
1) generate.tcl redefined write_pip_txtdata as a slow Tcl
'foreach net { foreach pip { ... get_nodes -uphill ... } }'.
On a big device with ~1296 nets this scales as O(nets*pips) with
per-pip routing-graph queries. The custom proc produces the same
6-column output (tile pip src dst pnum pdir) that the segmakers
parse — i.e., identical to Vivado's built-in write_pip_txtdata
that 049/053 et al. use. Drop the override so the built-in is
invoked (~10x speed-up).
2) Makefile set N = 120 specimens, 6x the typical 20. Reduce to 20
to match other pip fuzzers; segmatch still converges with plenty
of variety.
Combined: ~60x faster, lighter mem footprint. Won't change behaviour
for other families that weren't memory-bound — they get the same
faster path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Both fuzzers crashed in Vivado with 'ERROR: [Common 17-69] Missing
name/value pair in -dict argument' at the set_property -dict 'LOC ...
BEL ...' line. Cause: generate.tcl reserves 3*todo_lines INT tiles
via randsample_list (utils.tcl), which samples without replacement
and pads with empty strings once exhausted. The off-edge virtex7 ROI
holds only ~150 INT_L/INT_R tiles, but 053 has 64 todo lines, so
3*64=192 > 150 and the tail of the sample is empty entries; high-idx
todo lines (tile_idx = idx*3) get empty tiles -> empty driver_site
-> odd-length -dict -> error.
Reduce the per-todo-line retry window from 3 to 2 (set tiles
expr 2*todo_lines, tile_idx idx*2, retry limit tries>=2). 2*64=128
fits comfortably in ~150 pool. Other pip fuzzers use a different
indexing pattern; only these two use idx*K. For larger-ROI families
the pool still exceeds 2*N as it did 3*N, so no regression.
Verified: 053 single-specimen run reaches all 64 todo lines (idx 63
previously died at 50), emits segdata_int_l/r; 055 likewise.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Failed in dbfixup.py:153 add_tag_bits (AssertionError) because the
process_rdb name-harmonisation loop folded two distinct-bit Y1 IN
groups onto a single feature name. On Virtex-7 IOB_Y1 LVCMOS*.IN
has bits {38_00,39_01} but SSTL*.IN has only {38_00}; the visited-
iostandard logic forced both onto 'LVCMOS18_SSTL12_SSTL135_SSTL15.IN'
(driven by the Y0 grouping where they happened to share bits),
emitting two contradictory db lines that dbfixup can't merge.
(The existing filter_negbits already expects the un-merged name
IOB_Y1.LVCMOS12_LVCMOS15_LVCMOS18.IN, confirming the merge is wrong
here.) kintex7's Y1 LVCMOS and SSTL share bits, so it never hits
this case.
Fix: require identical bits before adopting a visited name; gate
via XRAY_DATABASE == virtex7 so kintex7's behaviour is provably
unchanged. Adds 'import os' for the env check.
Verified: no duplicate tags; Y1 splits correctly into
LVCMOS12_LVCMOS15_LVCMOS18.IN + SSTL12_SSTL135_SSTL15.IN.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two unrelated fixes the HP-IOB18 fuzzers need on a full-chip part:
1) top.py for both idelay and odelay collects all IOB18 tiles
('IOB18' in tile_name) but sorted with a key hardcoded to prefix
'RIOB18_' via create_xy_fun('RIOB18_'), which asserts on the first
LIOB18_* tile. kintex7's ROI only ever exposed the R side so this
was latent. Switch to a regex prefix '[LR]IOB18_' (matches the
existing '\\S+' idiom used by 037-iob18-pips). Doesn't change
which tiles get collected, so no-op for kintex7.
2) odelay generate.tcl: Vivado 2020.1 enforces DRC REQP-135 (ODELAY
VAR_LOAD/VAR_LOAD_PIPE requires CNTVALUEIN[0:4] connected) before
write_bitstream, but the fuzzer intentionally leaves CNTVALUEIN
unconnected. The idelay generate.tcl already disables IDELAY's
equivalents (REQP-79/81/84/85/87); add REQP-135 to the odelay
disable list to mirror.
Verified: idelay/odelay both run to completion on xc7vx485tffg1761-2,
producing valid segdata.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The earlier skip blamed a 'Vivado 2020.1 BEL-slot' difference; on close
investigation the real failure was generate.py:79 `assert bels == bels_tcl`
in the my_ram_N branch. The two ROI definitions disagree on X extent:
util.get_roi() (XRAY_ROI_GRID_*) yields SLICEM at SLICE X2..X12, but the
Vivado dump pblock built from $XRAY_ROI is X0..X11 — so the whole
SLICE_X12Y* column top.py LOC's primitives into falls outside the dumped
pblock and shows up as None in design.csv, tripping the assert.
The sibling RAM path already tolerated this via 'if ram != has_bel_tcl:
continue' (line ~137); mirror the same graceful skip in the SRL/LUT path.
For other families bels always == bels_tcl, so the change is a no-op.
Verified end-to-end on xc7vx485tffg1761-2: produces valid LUTRAM segdata
(ALUT/BLUT/CLUT/DLUT.{RAM,SRL,SMALL} + WA7USED/WA8USED/WEMUX.CE), pushes
into segbits_clblm_l/r (clblm coverage 95% -> ~100% vs kintex7).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
xc7vx485t has no IOB33/IOI3 (HR) tiles, so the HR-bank IOB/IOI fuzzers (030-iob,
035-iob-ilogic, 035a-iob-idelay, 035b-iob-iserdes, 036-iob-ologic, 037-iob-pips,
047-hclk-ioi-pips) have no sites. Gate them on a new HAS_HIGH_RANGE_BANKS flag
(0 for virtex7); the HP iob18/ioi18 fuzzers cover the part. Decouple
037-iob18-pips and 047a-hclk-idelayctrl-pips from the now-skipped HR fuzzers.
Kintex-7 and the other families are unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- settings/virtex7.sh: move XRAY_ROI and XRAY_ROI_GRID off the device bottom
edge (SLICE_X0Y50:X11Y99; grid 5-20/261-312). Edge tiles at Y0 can't exercise
features like BRAM36 ECC/cascade, and the bottom-edge BRAM is unsolvable.
- prjxray/segmaker.py: when a tile has no bitstream info (dummy tile, or an edge
tile dropped from the tilegrid such as BRAM_L_X114Y0 on xc7vx485t), account
for any tags on it and skip with a warning instead of asserting. Fixes the
BRAM config/FIFO fuzzers (027, 029, ...) for virtex7; no-op for normal dummy
tiles. Also print the unsolved tags before the all-tags-used assertion.
- fuzzers/Makefile: skip 018-clb-ram for virtex7 (Vivado 2020.1 packs SRL/RAM
into different BEL slots than the fuzzer pins).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Port prjxray to the Virtex-7 family, modelled on Kintex-7, targeting
xc7vx485tffg1761-2 (vc707). Non-breaking for the existing families.
Family registration:
- settings/virtex7.sh, settings/virtex7/devices.yaml
- Makefile: virtex7 in DATABASES/XRAY_PARTS + db-extras-virtex7 targets
- utils/update_parts.py, update_resources.py: virtex7 choice
- CI matrix (Pipeline.yml), Vivado edition (xilinx.sh), README
Architecture adaptations for the HP-bank-only VX part (verified non-breaking):
- update_resources.tcl: fall back to HP banks when no HR banks exist
- XRAY_IOSTANDARD env (default LVCMOS33; LVCMOS18 for virtex7), parameterised
across the fuzzer generate.tcl files
- fuzzers: enable HP-bank (iob18/ioi18) + IOI/HCLK handling for virtex7;
GTX skipped (ffg1761 bonds only ~7 of 14 GTX quads)
- 005-tilegrid: HP/HR bank tile handling; iob18_int INT offset 3->2;
ioi18 AUTO_FRAME; cfg PDRC-2 DRC disable; add_tdb skips unsolved edge tiles;
per-specimen retry for transient FlexLM SIGSEGV under concurrency
- per-family Vivado version gate (virtex7 -> v2020.1.1)
- XRAY_ROI and XRAY_ROI_GRID tuned to a compact CLBLL+CLBLM region
General fixes:
- tools/bitread.cc: fix use-after-free of the mmap'd bitstream (exposed by the
larger Virtex-7 bitstream)
- utils/environment.python.sh: add repo root to PYTHONPATH (PEP 660 editable
install doesn't expose the repo-root utils/ package)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>