From 34426486e5886a4f13eaf664ede16c0cc5238d6b Mon Sep 17 00:00:00 2001 From: Dr Jonathan Richard Robert Kimmitt Date: Fri, 29 May 2026 10:54:59 +0100 Subject: [PATCH] README: bring Virtex-7 port status current - 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 --- README.md | 190 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 40c56b4a..7ac15171 100644 --- a/README.md +++ b/README.md @@ -245,21 +245,58 @@ can not do this alone, **we need your help**! ## Virtex-7 Port Status (`virtex7-support` branch) This branch ports the openXC7 prjxray flow to **Virtex-7 `xc7vx485tffg1761-2`** -(VC707 board), modelled on the Kintex-7 sub-flow. The goal is a fully -open-source bit→DCP / fasm→bit round-trip on a Virtex-7 HP-only part. +(VC707 board), modelled on the Kintex-7 sub-flow. The original goal — a fully +open-source bit→DCP / fasm→bit round-trip on a Virtex-7 HP-only part — has +been met for the four VC707 reference designs (`rst_to_led`, `counter`, +`counter_bufr`, `telegraph`) and end-to-end for the PicoSoC UART demo running +on real silicon. + +The work spans four sibling branches on the openXC7 GitHub: + +| Repo | Branch | Carries | +|---|---|---| +| openXC7/prjxray | `virtex7-support` | this DB tree + `fasm2frames.py` bank-glue rules | +| openXC7/nextpnr-xilinx-meta | `virtex7-support` | per-site metadata + `wire_intents.json` | +| openXC7/nextpnr-xilinx | `virtex7-support` | RAM128/256X1S packing + INT-tile constant-net bridge | +| openXC7/demo-projects | `virtex7-branch` | VC707 reference `.bit` files + sources | ### Achievements -- **End-to-end smoke test passes** on `xc7vx485tffg1761-2`: System-Verilog - → Yosys → nextpnr-xilinx → FASM → `fasm2frames.py` → `xc7frames2bit` - → `.bit`. First run required 3 patches and surfaced 2 nextpnr-xilinx bugs - (filed upstream). +- **End-to-end open flow on real hardware (VC707):** + - 8-bit skew-tolerant counter blinks on VC707 with reset debounce. + - 200 MHz LVDS sysclk variant (`counter_bufr`) runs via IBUFDS + BUFR. + - `telegraph` UART smoke test prints `ABCDEFG` at 115200 baud on + `/dev/ttyUSB0`, bit-equivalent to the Vivado reference. + - **PicoSoC** (`picorv32/picosoc`) running on VC707 at 125 MHz from the + SGMIICLK crystal — BRAM-resident firmware prints + `PicoSoC alive on VC707 @ 125 MHz`, LEDs walk a pattern. +- **All four reference designs at 0/0 bit-difference** vs Vivado, with **zero + `.frm` patches** — the bank-glue rules are now codified as DB entries plus + auto-inject in `utils/fasm2frames.py`. - **Cross-family segbits/ppips transplant** from the openXC7 [`prjxray-db`](https://github.com/openXC7/prjxray-db) Kintex-7 tree into `database/virtex7/`: ~39 381 segbits + ~12 273 ppips entries, plus targeted key copies for `clk_hrow_*`, `clk_bufg_*`, `hclk_cmt*`, `io_int_interface_*` (≈51 k entries total). Pre-transplant tree backed up at `database/virtex7.before_transplant/`. +- **HP-bank glue codified — 7 new segbits entries + auto-inject:** + - `LIOB18.IOB_Y0.IBUF_HP_BANK_GLUE` (1 bit) + - `LIOB18.IOB_Y0.OBUF_HP_BANK_GLUE` (3 bits) + - `LIOB18.IOB_Y1.OBUF_HP_BANK_GLUE` (3 bits) + - `RIOB18.IOB_Y0.IBUFDS_BANK_GLUE` (7 bits, LVDS pair root) + - `INT_L.IOB_COL_OBUF_CASCADE_Y1` (3 bits, Y1 OBUF column carry) + - `INT_L.IOB_COL_BANK_ACTIVE` (3 bits, bank-active marker) + - `INT_L.GFAN_TIE_ROOT_GLUE` (1 bit, OBUF T-tie GND routing) + - `HCLK_L.HCLK_LEAF_BUFRCLK3_ACTIVE` (1 bit, BUFR clock leaf) + - Plus 14 silicon-default bits added as IOB18 `default` entries (`PUDC_B` + cascade, DCI cascade, slew/drive defaults Vivado emits unconditionally). +- **`utils/fasm2frames.py` bank-glue auto-inject** — direction-aware + walk over the FASM stream classifies each LIOB18 site as input / output / + diff-input from feature names (`IN_ONLY`, `.IN`, `IBUFDISABLE` → in; + `.DRIVE.` → out; `IN_DIFF` → diff_in) and injects the matching glue + features before frame assembly. `PUDC_B` template emission rewritten for + HP-bank IOSTANDARDs (10 features cover Y0 + Y1 default state). The + `pudc_b_tile_site` is resolved unconditionally so the HP-bank walk skips it. - **11 fuzzers patched** for HP-bank / virtex7-grid awareness: - `037-iob18-pips` — left-side mirror sites (LIOI / LIOI_TBYTESRC / LIOI_TBYTETERM), `top.py` NOT_INCLUDED_TILES for `*_SING`, generate-side @@ -281,44 +318,117 @@ open-source bit→DCP / fasm→bit round-trip on a Virtex-7 HP-only part. - **`utils/mergedb.sh` extended** with LIOI / LIOI_TBYTESRC / LIOI_TBYTETERM / LIOB18 / mask_liob18 cases. - **RapidWright `json2dcp.jar` rebuilt** against modern RapidWright (2025.2.1) - and patched for virtex7 — at `~/rapidwright/build/rapidwright_json2dcp.jar` - (17 KB). Verified `rst_to_led_routed.json` → 1.38 MB DCP that loads back - cleanly on `xc7vx485tffg1761-2`. Patch list in - `~/rapidwright/build/README.md`. + and patched for virtex7 — verified `rst_to_led_routed.json` → 1.38 MB DCP + that loads back cleanly on `xc7vx485tffg1761-2`. +- **nextpnr-xilinx companion patches** (on its `virtex7-support` branch): + - `xilinx/pack_dram.cc` — RAM128X1S / RAM256X1S single-port distributed RAM + packing (mirrors the SPO half of the dual-port families); needed by + PicoSoC's BRAM-fallback synthesis. + - `xilinx/python/nextpnr_structs.py` — bridges `PSEUDO_GND_WIRE_ROW` / + `PSEUDO_VCC_WIRE_ROW` to the INT tile's `GND_WIRE` / `VCC_WIRE` via + `CONST_DRIVER` pseudo-pips, so the router can find a route for OBUF + T-tie nets to the global GND. -### Goals +### Virtex-7 architecture discoveries -- Document `xc7vx485tffg1761-2` bitstream format with parity sufficient for a - Vivado-equivalent bitstream on IOB-only designs first, then SLICE and CMT. -- Achieve bit ↔ bit equivalence with Vivado on the `rst_to_led` pass-through - reference, then incrementally on counter, BUFR/IDELAY, and CMT designs. -- Provide a runnable bit→DCP path so open-flow bitstreams can be inspected / - diffed against Vivado checkpoints (Phase A via `json2dcp.jar` done; Phase B - via a virtex7-aware `fasm2bels` still in progress). +These are the things that turned out to be **different on Virtex-7**, not +inherited automatically by transplanting the Kintex-7 sub-flow. Some are +silicon-level facts that prjxray was never set up to capture; others are +nextpnr-xilinx assumptions that broke at scale. -### Work in Progress +- **HP-bank ≠ HR-bank silicon.** Virtex-7 `xc7vx485t` is HP-bank-only + (`IOB18` family using `INBUF_DCIEN` / `OUTBUF_DCIEN`), whereas Kintex-7 + parts on the openXC7 path are mostly HR (`IOB33` family using + `IBUF` / `OBUF`). The HR and HP IO logic share the same prjxray feature + syntax but **encode different silicon bits**, and the surrounding clock + region differs: + - HR uses `HCLK_IOI3_*` tiles. + - HP uses `HCLK_IOI_*` tiles. + - The IO-related fasm tools were hard-coded to `HCLK_IOI3_*` and silently + dropped HP-bank features until probed; `fasm2frames.py` and several + fuzzers now branch on a runtime grid probe. +- **L/R-side mirror.** The VC707 IO column lives on the **left** side + (`LIOB18_X81*` / `LIOI_X*`) — most Kintex-7 reference designs used the + right-side mirror. The 037-iob18-pips fuzzer had to learn left-side + emission (it had only ever exercised RIOB18). +- **"Bank glue" — the silicon enables Vivado sets that no prjxray feature + emits.** A correct prjxray-driven bitstream for an HP-bank design is a + proper *subset* of what Vivado emits because Vivado writes ~14 extra bits + per bank-in-use that the prjxray feature schema never claimed. These are + not user-visible (no fasm feature corresponds to them) but the HP-bank + IOB silicon **will not drive** without them. Categories: + - **Tile-in-use markers** in `INT_L_X62Y*` and `INT_L_X32Y49` — three bits + that indicate "this bank's OBUF column is live" / "DCI cascade is live". + - **Y0 vs Y1 OBUF cascade** — `LIOB18.IOB_Y0.OBUF_HP_BANK_GLUE` and + `.IOB_Y1.OBUF_HP_BANK_GLUE` are independent 3-bit groups. Crucially the + Y1 column's 3 bits also have to be cascaded into the next INT_L row up + (`INT_L.IOB_COL_OBUF_CASCADE_Y1`). + - **`PUDC_B` cascade.** The HP-bank `PUDC_B` pin (`LIOB18_X81Y97` on + `xc7vx485tffg1761-2`) controls bank-wide auto-pullup behaviour at boot + and **always** appears in the bitstream with 10 silicon-default features, + even when the user never references it. We now emit those features + unconditionally from `fasm2frames.py`. + - **IBUFDS pair root.** A differential IBUFDS uses the Master IOB + (`Y0`) as the live pin and emits 7 silicon-enable bits there + (`RIOB18.IOB_Y0.IBUFDS_BANK_GLUE`). The Slave (`Y1`) stays in default + state. Without these the LVDS receiver does not enable. + - Heuristic gotcha: our first cut classified OBUFs by `.SLEW.`; that gave + false positives because Vivado emits `SLEW.SLOW` on default-state IBUFs + too. The reliable OBUF marker is `.DRIVE.`. +- **`HCLK_L.HCLK_LEAF_BUFRCLK3_ACTIVE`** — a one-bit "this BUFR leaf is + live" marker that Vivado sets when a BUFR is the source for a clock + region. Required for the `counter_bufr` 200 MHz LVDS clocking path; we + inject it whenever the FASM stream mentions any BUFR feature. +- **`INT_L.GFAN_TIE_ROOT_GLUE`** — OBUF `T` (tristate) input must be tied + to GND for non-tristate use. Vivado routes that GND from the **next + INT_L row up** via the `GFAN0.GND_WIRE` pseudo-pip; the routing-graph + signature requires one extra bit at `26_018` in `INT_L_X62Y(N+10)`. We + detect any `INT_L_X62Y*.GFAN0.GND_WIRE` in the FASM and inject the + root-row glue automatically. This is the last residual that brought all + four reference designs to 0/0 vs Vivado on raw open flow. +- **`fasm2bels` chokes on `NOCLKINV`** — the `xc7vx485t` connection + database builds (14 min, 4.2 GB, 56.8 M wires), but `clb_models.py` does + not yet handle the `NOCLKINV` packer feature that nextpnr-xilinx emits + for HP-bank SLICEs. Asserted as `{NOCLKINV}`. Phase B (`fasm2bels` + virtex7 port) is paused on this. +- **nextpnr-xilinx OBUF T-tie convergence.** Within nextpnr the router + cannot find a path from `NULL_X0Y364/PSEUDO_GND_WIRE_GLBL` to the LIOB18 + OBUF `TRI` pin because the constant-net source lives outside the INT + tile graph. Fixed at chipdb-build time by `nextpnr_structs.py`: + emit `CONST_DRIVER` pseudo-pips that bridge `PSEUDO_GND_WIRE_ROW` / + `PSEUDO_VCC_WIRE_ROW` into each INT tile's `GND_WIRE` / `VCC_WIRE`. +- **nextpnr-xilinx Y137/Y138 chipdb wire mapping** — still open. Two LIOB18 + rows present in the chipdb point at wires that the architecture + assignment then loses track of. Functional impact zero (our + `fasm2frames.py` covers the silicon-enable side); but the bug is real and + filed at task #31. +- **PicoSoC needed RAM128X1S / RAM256X1S packing.** PicoSoC's + default `picorv32_pcpi_div` synthesises into single-port distributed RAM. + nextpnr-xilinx had packers only for the dual-port `RAM128X1D` / + `RAM256X1D` variants; the SP packers are mirrors of the SPO half of + those, added on this branch. -- **030-iob18 N=200 rerun** for finer IOSTANDARD/DRIVE coverage on LIOB18. - Running at one specimen per ~3 min, currently ≈187 of 200 specimens written; - will trigger `make pushdb` automatically on completion. -- **LIOB18 IOSTANDARD bit-encoding bug** — `rst_to_led.bit` produced by our - flow flickers and is unresponsive on hardware; Vivado-built reference works. - Targeted bit-diff localised the discrepancy to LIOI and LIOI_TBYTETERM - tiles sharing a frame range but with different word offsets — partial fix - applied (per-tile partitioning) reduced missing bits 28 → 21 and extras - 14 → 12, but IOSTANDARD bits still wrong. Awaiting N=200 segdata to - re-derive. -- **037-iob18-pips left-side coverage** — residual pip-convergence iteration; - iter 1 was salvaged after a JVM crash on `spec_008` left 19 surviving - specimens that yielded 128 LIOI entries. -- **Phase B — virtex7 `fasm2bels` port** — parked. Connection database for - `xc7vx485tffg1761-2` builds successfully (14 min, 4.2 GB on disk, 56.8 M - wires). First failure is in `clb_models.py` on the nextpnr-emitted - PSEUDO_VCC packer cell (`assert False, {'NOCLKINV'}`). IOB18 / HP-bank BEL - name substitutions drafted in `models/iob_models.py` (uncommitted). -- **Open TODOs (cross-cutting)** — expand the virtex7 ROI; add a Vivado DRC - cross-check of nextpnr output; exclude `GTX_INT_INTERFACE` pips from the - virtex7 chipdb; add bits info for `CFG_CENTER` / `*_SING` tiles. +### Goals (remaining) + +- **Codify the 228-bit PicoSoC CLB-glue family** (relative offsets + `30_006 / 30_011 / 30_020 / 30_022 / 30_040 / 30_045 / 30_052 / 30_056` + + `31_040 / 31_043`) — per-SLICE "in use" bits that show up only when a + SLICE is occupied. Would push PicoSoC's bit-diff vs Vivado to zero. +- **Restore the 236 missing IOI features** (IDELAY / OSERDES / OQ) into + `segbits_lioi.db` — currently we have HR-side coverage transplanted but + the HP-side variants need their own segdata. +- **`fasm2bels` virtex7 port** — past the `NOCLKINV` block, then through + HP-bank IOB BEL substitutions (sketched in `models/iob_models.py`). +- **Y137/Y138 chipdb wire mapping** in nextpnr-xilinx — for parity with + Vivado's checkpoint format. + +### Cross-cutting open TODOs + +- Expand the virtex7 ROI (small ROI was sufficient for the IO / HCLK + fuzzers but the CMT / DSP / GTX fuzzers will want more). +- Vivado DRC cross-check of nextpnr output. +- Exclude `GTX_INT_INTERFACE` pips from the virtex7 chipdb. +- Bits info for `CFG_CENTER` / `*_SING` tiles. ### Constraints