Skip to content

toolchain: pin nextpnr 1436b96f, fpga-as reference parity, chipdb part-name symlinks - #20

Merged
hansfbaier merged 6 commits into
mainfrom
build/fpga-as-parity-and-nextpnr-fixes
Sep 25, 2026
Merged

hansfbaier merged 6 commits into
mainfrom
build/fpga-as-parity-and-nextpnr-fixes

Conversation

@hansfbaier

@hansfbaier hansfbaier commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Three changes that make the toolchain's own build of the demo toolchain match what
demo-projects' CI now expects.

nextpnr → 1436b96f (openXC7/nextpnr#45)

Pins the two xc7 fixes the smoke/heavy matrix needs:

  • write_ibufds_gte2() hardcoded GTXE2_COMMON as the COMMON segment prefix;
    on a GTP_COMMON tile the database names that segment GTPE2_COMMON, so
    every Artix-7 GTP design emitted an undeclared feature. fasm2frames
    rejected the bitstream (FasmLookupError) and fpga-as aborted on the lookup.
    (litex-sata-alientek-davincipro.)
  • the OFB-loopback exemption in the packer missed the shape where the
    OSERDESE2's OFB drives the ISERDESE2's OFB input with D/DDLY open --
    Xilinx's DDR3 PHY example's training ISERDES -- and aborted with
    has disconnected D input. (ddr3-test-arty-s7.)

The rev is the pre-merge commit from that PR, so this PR's CI can run the whole
stack; re-pin to the merge commit on main once #45 lands.

fpga-as

Pinned to hansfbaier/fpga-assembler@cf0e3f0 (lromor/fpga-assembler#47, "Reproduce
the reference implementation's output"). The rev the flake used writes "fasm"
into the bitstream's b TLV where xc7frames2bit writes the part name, and sets
seven configuration bits the reference leaves clear, so demo-projects' committed
goldens cannot match a rebuild. Switch back to the upstream repo when #47 lands.

chipdb part names

nix/nextpnr-chipdb.nix installed a copy of the die's database under every
package name, so kintex7 shipped 1.2 GB for 252 MB of data. Relative symlinks
instead; openXC7.mk's ${CHIPDB}/${DBPART}.bin lookup is unchanged.
Note the CI chipdb stage still cps the store output, which dereferences the
links -- the workflow would need cp -a to see the size win.

Verification

nix build .#nextpnr .#nextpnr-xilinx-chipdb.artix7 on this branch, and all 20
smoke projects + litex-ddr-hpcstore-k420t built to .bit with the resulting
derivations (scripts in the demo-projects PR).

Assisted-by: deepseek/deepseek-flash

Summary by Sourcery

Align the FPGA toolchain dependencies and chip database packaging with the demo-projects CI and reference bitstream outputs.

Bug Fixes:

  • Update nextpnr to include XC7 fixes required for Artix-7 GTP designs and DDR3 PHY packing.
  • Align fpga-as output with the reference bitstream assembly expected by demo-project golden files.

Enhancements:

  • Replace per-part chip database copies with idempotent relative symlinks to reduce chipdb artefact size while preserving part-name lookups.

Build:

  • Pin nextpnr and fpga-assembler dependencies to revisions compatible with the current demo-project toolchain expectations.

Tests:

  • Verify chipdb artefacts for all supported Xilinx families and confirm all CI matrix part names resolve correctly.

Fix-up: the part-name symlinks were not idempotent (07b9721)

The first real build of .#nextpnr-xilinx-chipdb.artix7 aborted:

ln: failed to create symbolic link '.../xc7a100tcsg324.bin': File exists

The speed grades of one footprint collapse onto the same part name --
xc7a100tcsg324-1, -2, -2L, -3 all strip to xc7a100tcsg324 -- so the
second one to be linked hit an existing symlink. The cp this replaced
overwrote silently, so the old derivation never hit it. ln -sf is both
correct and order-independent (every duplicate links the same die's database).

Verified this time by building the artefacts, not just by reading the code:

nix build .#nextpnr-xilinx-chipdb.{artix7,kintex7,spartan7,zynq7,virtex7} \
  --print-out-paths --no-link

and by checking every part name the two CI matrices use against the resulting
directories (the openXC7.mk contract is ${DBPART}.bin, DBPART = PART
with the first -<digit> removed): all 21 part/family pairs resolve, including
the xc7a35t -> xc7a50t fabric alias (xc7a35tcsg324.bin ->
chipdb-xc7a50t.bin).

lromor/fpga-assembler@6ff89a2 writes "fasm" into the bitstream's 'b' TLV
where xc7frames2bit writes the part name, and sets seven configuration bits
the reference implementation leaves clear, so a bitstream assembled with it
differs from the one fasm2frames + xc7frames2bit produce for the same FASM.
hansfbaier's reference-parity branch fixes both.

Switch back to lromor/fpga-assembler once the PR lands:
lromor/fpga-assembler#47

Assisted-by: deepseek/deepseek-flash
The generator takes a die and one database serves every package of it, so the
copy under each part name multiplied a family's artefact by the number of
footprints: kintex7 shipped 1.2 GB for its 252 MB of data.  A relative symlink
keeps the store path self-contained and relocatable while making openXC7.mk's
per-part lookup still work.

Assisted-by: deepseek/deepseek-flash
Two xc7 fixes from openXC7/nextpnr#45:

  * write_ibufds_gte2() hardcoded GTXE2_COMMON as the COMMON segment prefix;
    on a GTP tile the database names it GTPE2_COMMON, so every Artix-7 GTP
    design emitted an undeclared feature and fasm2frames rejected the
    bitstream (FasmLookupError), fpga-as aborted on the lookup.
  * the OFB-loopback exemption in the packer missed the shape where the
    OSERDESE2's OFB drives the ISERDESE2's OFB input (D and DDLY open), which
    is how Xilinx's DDR3 PHY example instantiates its training ISERDES; the
    packer aborted with "has disconnected D input".

demo-projects' smoke and heavy workflows need both.

Assisted-by: deepseek/deepseek-flash
@sourcery-ai

sourcery-ai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Updates the toolchain inputs to revisions that reproduce the demo-projects reference bitstreams and fix xc7 packing failures, while replacing redundant chipdb copies with relocatable per-part symlinks.

Flow diagram for shared chipdb part-name symlinks

flowchart TD
    Package[Package name lookup]
    DBPart[CHIPDB/DBPART.bin]
    Link[Relative symlink]
    DieDB[chipdb-fabric.bin]

    Package --> DBPart
    DBPart --> Link
    Link --> DieDB
Loading

File-Level Changes

Change Details Files
Pin nextpnr to an xc7-fix revision required by the smoke and heavy demo matrices.
  • Update the source revision and fixed-output hash.
  • Include fixes for GTP common-segment naming and OSERDESE2/ISERDESE2 OFB-loopback packing.
nix/nextpnr.nix
Use an fpga-as revision whose generated bitstream matches the reference assembler output.
  • Switch the flake input to the fork and pinned commit.
  • Align the bitstream part-name TLV and configuration-bit behavior with fasm2frames plus xc7frames2bit.
  • Document reverting to upstream after the referenced fix merges.
flake.nix
Deduplicate chipdb artifacts by linking package part names to the shared die database.
  • Replace per-part database copies with relative symlinks.
  • Preserve the existing part-name lookup path while reducing store artifact size.
nix/nextpnr-chipdb.nix

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="nix/nextpnr-chipdb.nix" line_range="71" />
<code_context>
       fi
       if [ -f "$out/chipdb-$fabric.bin" ]; then
-        cp "$out/chipdb-$fabric.bin" "$out/$part.bin"
+        # Symlink, not copy: one die's database is 20-75 MB and serves every
+        # package of that die, so a copy under each part name inflated a
+        # family's artefact severalfold (kintex7: 1.2 GB for 252 MB of data)
+        # and made CI pull the copies with it.  Relative, so the store path
+        # stays self-contained and relocatable.
+        ln -s "chipdb-$fabric.bin" "$out/$part.bin"
       else
</code_context>
<issue_to_address>
**nitpick:** The file header still says that each package receives a copy of its die database, but the implementation now installs symlinks instead. This misleads maintainers about both the storage behavior and the artifact layout.

**Suggested fix:** Update the header comment to say that each package receives a relative symlink to its die database.

```suggestion
        # Each package receives a relative symlink to its die database; one die's
```
</issue_to_address>

### Comment 2
<location path="nix/nextpnr-chipdb.nix" line_range="76" />
<code_context>
+        # family's artefact severalfold (kintex7: 1.2 GB for 252 MB of data)
+        # and made CI pull the copies with it.  Relative, so the store path
+        # stays self-contained and relocatable.
+        ln -s "chipdb-$fabric.bin" "$out/$part.bin"
       else
         echo "no chipdb for $part (fabric $fabric) -- skipped"
</code_context>
<issue_to_address>
**issue (broader_impact):** The database-size reduction is lost when the CI packaging step copies the store output with ordinary `cp`, because that dereferences these symlinks and recreates a full copy under every part name. CI artifacts therefore remain inflated despite this change.

**Triggers:** When the CI chipdb stage packages this derivation with `cp` rather than preserving symlinks.

**Suggested fix:** Change the CI copy to `cp -a` (or otherwise preserve symlinks) when packaging the chipdb output.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and a faulty nextpnr or fpga-as pin could generate incorrect FPGA bitstreams, and consumers that do not handle the new relative chipdb symlinks could fail to build. Reverting restores the previous toolchain, and generated databases or bitstreams can be regenerated, so the impact is bounded and repairable.

Blocking findings: nix/nextpnr-chipdb.nix:76


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread nix/nextpnr-chipdb.nix
Comment thread nix/nextpnr-chipdb.nix Outdated
# family's artefact severalfold (kintex7: 1.2 GB for 252 MB of data)
# and made CI pull the copies with it. Relative, so the store path
# stays self-contained and relocatable.
ln -s "chipdb-$fabric.bin" "$out/$part.bin"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (broader_impact): The database-size reduction is lost when the CI packaging step copies the store output with ordinary cp, because that dereferences these symlinks and recreates a full copy under every part name. CI artifacts therefore remain inflated despite this change.

Triggers: When the CI chipdb stage packages this derivation with cp rather than preserving symlinks.

Suggested fix: Change the CI copy to cp -a (or otherwise preserve symlinks) when packaging the chipdb output.

The speed grades of one footprint collapse onto the same part name --
xc7a100tcsg324-1, -2, -2L and -3 all strip to xc7a100tcsg324 -- so the second
one to be linked hit an existing symlink and `ln -s` aborted the whole
derivation:

    ln: failed to create symbolic link '.../xc7a100tcsg324.bin': File exists

The copy this replaced overwrote silently, which is why it went unnoticed.
All of them link the same die's database, so `ln -sf` is both correct and
order-independent.

Verified: nix build .#nextpnr .#nextpnr-xilinx-chipdb.{artix7,kintex7,spartan7,zynq7}
--print-out-paths --no-link

Assisted-by: deepseek/deepseek-flash
The derivation was changed to install a relative symlink per package name, but
the file header still described the old copy-per-name layout.  Review comment
on #20.

Assisted-by: deepseek/deepseek-flash
#45 is merged, so track main instead of the PR branch tip.  The merge brought
nothing else (git diff 1436b96f 5a0b7e41 is empty) and the source tarball hash
is unchanged, so this is derivation-identical: nextpnr-xilinx-chipdb.{artix7,
kintex7} resolve to the same store paths as before (bds5583..., 4zz1w25...) and
nextpnr to the same 735jw473... -- no rebuild, no chipdb cache invalidation.

Assisted-by: deepseek/deepseek-flash
@hansfbaier

Copy link
Copy Markdown
Contributor Author

Both comments addressed.

Comment 1 (header says copy, code installs a symlink) — fixed in 9888734. The
header now says each package gets a relative symlink to its die's database, and
that the die databases are the only files the derivation stores.

Comment 2 (cp dereferences the symlinks, so CI still ships copies) — correct,
and worse than the comment states: cp "$OUT"/*.bin dereferences at the staging
step, before the artifact is even created. Measured on the current output, artix7
staged 1011 MB of copies for 123 MB of data; kintex7 is the 1.2 GB you
estimated.

Fixed on the demo-projects side (commit 987b035), since that is where the staging
and the artifact live:

  • the chipdb job now archives the member list with tar (cd "$OUT" && tar -cf stage/chipdb-<family>.tar *.bin) and uploads that one file;
  • the four consumers (project, determinism, regression in smoke.yml; project in
    heavy.yml) download it and tar -x it into chipdb/.

tar rather than cp -a on purpose: upload-artifact's treatment of symlinks is
version-dependent — v4.3.5 started preserving symlinks instead of dereferencing
them and broke pipelines that way (actions/upload-artifact#590) — while a tar
member list is exactly what the derivation installed. The round trip no longer
depends on the action's symlink semantics.

Verified: the artix7 tar is 123 MB for the same 25 entries, 0 broken symlinks
after extraction, every part name in the two matrices resolves, and
blinky-digilent-arty built from the extracted directory matches the committed
golden's normalized hash (ee4159f5...).

Also in this branch: 3fa6f49 re-pins nextpnr to 5a0b7e41, main's merge of #45. The
merge brought nothing else (git diff 1436b96f 5a0b7e41 is empty) and the source
hash is unchanged, so it is derivation-identical — the chipdb and nextpnr store
paths are the ones already built and verified, nothing re-derives.

@hansfbaier
hansfbaier merged commit 2234042 into main Sep 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant