Repository navigation
cmt, hclk_cmt: CLK_PERF and PHSR_PERFCLK rows with all their bits - #30
Conversation
Each CMT_LR_LOWER_B_CLK_PERFn mux is set by an enable bit plus a 2-bit
code, not by one bit per source. The rows before this change named a
single code bit, so in both directions they were wrong:
decode CLK_PERF2.CLKOUT3 = 29_994 fires on every CLKOUT1 mux too
(29_994 is the low code bit): 204 false hits in the 039b
campaign across the four families;
encode CLK_PERF1.CLKOUT3 = 28_996 and CLK_PERF2.CLKOUT3 = 29_994
leave the enable bit and the other code bit clear, which
Vivado sets for the same pip.
New rows, the same in all four families and on both CMT sides:
CLK_PERF2 enable 29_1022, code 28_994 29_994, CLKFBOUT 29_993
CLK_PERF3 enable 28_1022, code 29_992 28_993, CLKFBOUT 28_992
CLK_PERF1 enable 28_1023, code 29_995 28_996 (CLKOUT2, CLKOUT3 only)
CLK_PERF0.CLKOUT2 is unchanged, and is added to zynq7 CMT_TOP_R_LOWER_B
where it was missing.
Checked against cavearr's perfclk-campaign-2026-09 (152 specimens per
family): bits read from each design.bit through the tilegrid, compared
with the pips Vivado routed, in every CMT tile of every specimen, used
or not. Every row decodes with 0 false and 0 missed hits, and the rows
for the routed pips reproduce the bitstream exactly over every bit the
rows mention: artix7 912/912, kintex7 912/912, spartan7 456/456,
zynq7 608/608 tile samples.
No pseudo-pips: every source sets bits, CLKOUT0 included (the enable).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HCLK_CMT_MUX_PHSR_PERFCLKn rows existed only in artix7, and there the PERFCLK3 <- MUXED2 row was missing. Added it, and added the six measured rows to kintex7, spartan7 and zynq7 (HCLK_CMT and HCLK_CMT_L): PERFCLK0.MUXED1 26_177 26_180 PERFCLK1.MUXED0 27_176 29_134 PERFCLK2.MUXED2 28_176 29_133 PERFCLK2.MUXED3 28_177 PERFCLK3.MUXED2 29_133 29_176 29_180 (new in artix7 too) PERFCLK3.MUXED3 29_177 29_180 29_180 is set whenever PERFCLK3 is used; 29_133 whenever either PERFCLK mux selects MUXED2. Checked the same way as the CMT rows, against cavearr's perfclk-campaign-2026-09: 0 false, 0 missed, encode exact in all 2888 HCLK tile samples. artix7's PERFCLK1.MUXED1 row (27_177) has no sample in the campaign and is left where it was, artix7 only. Not measured: in the campaign PERFCLK2 is never used without PERFCLK3, so whether PERFCLK2 alone also needs 29_180 is open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's guide (collapsed on small PRs)Reviewer's GuideExtends and corrects CMT performance-clock database coverage across artix7, kintex7, spartan7, and zynq7 by encoding complete CLK_PERF mux conditions and adding HCLK_CMT PERFCLK/PHSR_PERFCLK rows, with matching origin metadata. The changes were validated against 407,166 measured tile bits: decode produced no false or missed routes, encode matched all tested bits, and strict database parsing passed. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Checked against cavearr's perfclk-campaign-2026-10 (1083 specimens, every CLK_PERFn and PERFCLKn source forced), the rows of the two previous commits are incomplete, and one row they carried is wrong. CLK_PERF0.CLKOUT2 = 28_997 29_1023, on master since ae4770b, also fires on every CLKOUT3 mux: 268 false hits (artix7 83, kintex7 83, spartan7 45, zynq7 57). 28_997 is one bit of the 2-bit code. CLK_PERF0 and CLK_PERF1 have the same enable + 2-bit code layout as CLK_PERF2/3, but only CLK_PERF0.CLKOUT2 and CLK_PERF1.CLKOUT2/3 had rows. The PERFCLK rows leave out two bits Vivado sets with every pip: used(p) = (26+p)_180, and selected(m) = 29_134, 28_134, 29_133, 28_133 for MUXED0..3. PERFCLK0 <- MUXED0 had no row. The previous commit's "encode exact in all 2888 HCLK tile samples" was measured only over the bits some row names, so it could not see a bit that no row names. Over all 16 PERFCLK bits, the encode of those rows is short in 1230 of the 2888 samples. New rows, the same in all four families and on both sides. Per CMT tile, 20 rows (4 muxes x 5 sources), enable E, code A B, feedback F: E A B F CLK_PERF0 29_1023 28_997 29_997 29_996 CLK_PERF1 28_1023 29_995 28_996 28_995 CLK_PERF2 29_1022 28_994 29_994 29_993 CLK_PERF3 28_1022 29_992 28_993 28_992 CLKFBOUT E F; CLKOUT0 E !A !B !F; CLKOUT1 E !A B; CLKOUT2 E A !B; CLKOUT3 E A B Per HCLK_CMT{,_L} tile, 8 rows: PERFCLKp <- MUXEDm sets (26+p)_(176+(m&1)), (26+p)_180 and selected(m), for PERFCLK0/1 <- MUXED0/1 and PERFCLK2/3 <- MUXED2/3. Rows added or changed carry origin 039c-perfclk01-forced-mux; the 104 rows that did not change keep 039b. Checked as before: bits read from each design.bit through the tilegrid and compared with the pips Vivado routed, in every CMT_TOP_*_LOWER_B and HCLK_CMT tile of every specimen, used or not. Encode is now measured over every bit of the mux, not just the bits a row names. campaign tile samples a7/k7/s7/z7 CMT and HCLK rows 2026-09 912/912/456/608 0 false, 0 missed, encode exact 2026-10 1464/1464/912/1164 0 false, 0 missed, 0 pips with no row, encode exact The rows before this change, same check, 2026-10: 268 false (above), 2969 routed pips with no row, encode short in 1409 CMT and 2304 HCLK samples. utils/parsedb.py --strict passes on all 16 changed segbits files. No pseudo-pips: every source sets at least the enable or the used bit. Not measured: none of this has run on silicon yet. The PHASERIN_RCLK side of PERFCLK is not covered by either campaign. mask_hclk_cmt*.db lists none of the 16 PERFCLK bits, here or on master; left as it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A post on the board half of openXC7/prjxray-db#30: a BUFR counter clocked through CLK_PERF2 <- CLKOUT3 and PERFCLK2 <- MUXED2 runs on the AX7203 with the c030ed6 rows and stays dead with the master rows; the two bitstreams differ in three bits, and clearing any one of them stops the counter again. It also records the stale nextpnr-xilinx build (#191 and #205 missing) and the edit-to-board loop going from about 104-111 s to about 19-28 s. Two recordings published under t27.ai/term/ and replayed in the post: perf2-knockouts (the three bits named, the knockout bitstreams rebuilt byte-identical to the flashed ones) and perf2-loop (router1 to SRAM, 19.06 s in that run, at load average ~110). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A post on the board half of openXC7/prjxray-db#30: a BUFR counter clocked through CLK_PERF2 <- CLKOUT3 and PERFCLK2 <- MUXED2 runs on the AX7203 with the c030ed6 rows and stays dead with the master rows; the two bitstreams differ in three bits, and clearing any one of them stops the counter again. It also records the stale nextpnr-xilinx build (#191 and #205 missing) and the edit-to-board loop going from about 104-111 s to about 19-28 s. Two recordings published under t27.ai/term/ and replayed in the post: perf2-knockouts (the three bits named, the knockout bitstreams rebuilt byte-identical to the flashed ones) and perf2-loop (router1 to SRAM, 19.06 s in that run, at load average ~110). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
) A post on the board half of openXC7/prjxray-db#30: a BUFR counter clocked through CLK_PERF2 <- CLKOUT3 and PERFCLK2 <- MUXED2 runs on the AX7203 with the c030ed6 rows and stays dead with the master rows; the two bitstreams differ in three bits, and clearing any one of them stops the counter again. It also records the stale nextpnr-xilinx build (#191 and #205 missing) and the edit-to-board loop going from about 104-111 s to about 19-28 s. Two recordings published under t27.ai/term/ and replayed in the post: perf2-knockouts (the three bits named, the knockout bitstreams rebuilt byte-identical to the flashed ones) and perf2-loop (router1 to SRAM, 19.06 s in that run, at load average ~110). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
docs(blog): three bits, each one necessary - CLK_PERF2 on silicon (#1309) A post on the board half of openXC7/prjxray-db#30: a BUFR counter clocked through CLK_PERF2 <- CLKOUT3 and PERFCLK2 <- MUXED2 runs on the AX7203 with the c030ed6 rows and stays dead with the master rows; the two bitstreams differ in three bits, and clearing any one of them stops the counter again. It also records the stale nextpnr-xilinx build (#191 and #205 missing) and the edit-to-board loop going from about 104-111 s to about 19-28 s. Two recordings published under t27.ai/term/ and replayed in the post: perf2-knockouts (the three bits named, the knockout bitstreams rebuilt byte-identical to the flashed ones) and perf2-loop (router1 to SRAM, 19.06 s in that run, at load average ~110). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
@gHashTag we ran #30 (together with #31) on the bench before merging. The short version; the full tables are folded below.
Not measured: silicon with this engine (the AX7203 test used the classic one), the BUFR divider (BYPASS only), This is enough for us to merge it. Thank you for the rows and for the board test. Full validation tables (prjxray-db #30 and #31, prjxray #27 and #28)Validation of prjxray-db #30 and #31 and prjxray #27 and #28 before mergingEvery row below was run, not read. Linux x86-64 only; nothing was tried on silicon by us. What was compared
One factor changes at a time. The engine is db #31 — DSP48E1
|
| die | bytes | master | master + #31 | master + #30 + #31 |
|---|---|---|---|---|
| xc7a100t | 40104101 | 9206e3d71cdb | 9206e3d71cdb | dcdd9257af9b |
| xc7a200t | 60816292 | 7b6b4a949810 | 7b6b4a949810 | 9af6a090522b |
| xc7a50t | 30491033 | f875b15c4807 | f875b15c4807 | f708dacc1045 |
| xc7s25 | 22033751 | 315d2dfdffc4 | 315d2dfdffc4 | 82f539fbd534 |
| xc7s50 | 29757535 | 270e5c046074 | 270e5c046074 | 9c7fd24f4d57 |
| xc7z010 | 21834289 | a30aa993e89f | a30aa993e89f | 434bd51e8dc3 |
| xc7z020 | 39838438 | c19e8fa16e22 | c19e8fa16e22 | bc50b369687d |
| xc7z030 | 49186438 | 52f0369cfa4b | 52f0369cfa4b | ff8b05c117b0 |
| xc7z045 | 65240318 | bfda448bf564 | bfda448bf564 | 78883aefdc34 |
| xc7z100 | 76918990 | 21feccaf0e21 | 21feccaf0e21 | bf2ffc91b176 |
With #31 alone, 10 of 10 chipdb files are byte-identical to master's. In the generator's census of pips, #31 turns 0 pips from "no row" to "has a row" on any die: its eight rows name no pip.
What the suite and the e2e say about #31 and #30 together
The builder's regression suite (59 entries) and the 37-part blinky e2e, run once per db arm (master vs master + #30 + #31):
| master vs master + #30 + #31 | |
|---|---|
| suite netlists identical | 59 of 59 |
| suite entries with FASM, canonical FASM identical | 58 of 58 |
suite .bit equal, every field |
58 of 58 |
| suite status changes | 0 |
| e2e parts, canonical FASM identical | 37 of 37 |
e2e parts, .bit equal, every field |
37 of 37 |
The suite entries that contain a cell the two PRs have rows for: dsp48 (DSP48E1), pll (PLLE2_BASE). None uses a BUFR, a BUFIO, or an MMCM output through the performance clock lanes, so the suite shows that nothing else moved; the proof of #30 is the next section.
The suite's overall verdict is FAIL in both arms for the same single entry (bram, a guard that expects the flow to fail and the flow now completes); it does not depend on the db.
What this does not cover for #31: the new rows were not compared with a Vivado bitstream here (no DSP48E1 with AREG/BREG = 1 in the corpus).
db #30 — complete CLK_PERF0..3 and PERFCLK0..3 rows
On top of #31, the PR touches 32 files (the CMT and HCLK_CMT segbits and their origin_info, in artix7, kintex7, spartan7 and zynq7; nothing else). Segbits rows added / removed: artix7 +56 -18, kintex7 +56 -6, spartan7 +56 -6, zynq7 +56 -5. Some of the removed rows are existing rows that the PR rewrites with more bits, for example CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT3 (28_996 becomes 28_996 28_1023 29_995) and HCLK_CMT_MUX_PHSR_PERFCLK0.HCLK_CMT_MUX_MMCM_MUXED1 (26_177 26_180 becomes 26_177 26_180 28_134).
The chipdb changes, and the generator's pip census explains each change
The generator offers the router only the pips that have a row. Per die, pips going from "no row" to "has a row" with db master → master + #30 + #31, and how many of them an added row names:
| die | chipdb bytes (both) | sha master | sha master + #30 + #31 | pips without a row, before → after | flipped | named by an added row | back to no row | tile types of the flipped pips |
|---|---|---|---|---|---|---|---|---|
| xc7a100t | 40104101 | 9206e3d71cdb | dcdd9257af9b | 1869 → 1831 | 38 | 38 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 17, HCLK_CMT 2, HCLK_CMT_L 2 |
| xc7a200t | 60816292 | 7b6b4a949810 | 9af6a090522b | 2097 → 2059 | 38 | 38 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 17, HCLK_CMT 2, HCLK_CMT_L 2 |
| xc7a50t | 30491033 | f875b15c4807 | f708dacc1045 | 1869 → 1831 | 38 | 38 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 17, HCLK_CMT 2, HCLK_CMT_L 2 |
| xc7s25 | 22033751 | 315d2dfdffc4 | 82f539fbd534 | 1992 → 1942 | 50 | 50 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 17, HCLK_CMT 8, HCLK_CMT_L 8 |
| xc7s50 | 29757535 | 270e5c046074 | 9c7fd24f4d57 | 1992 → 1942 | 50 | 50 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 17, HCLK_CMT 8, HCLK_CMT_L 8 |
| xc7z010 | 21834289 | a30aa993e89f | 434bd51e8dc3 | 1548 → 1523 | 25 | 25 | 0 | CMT_TOP_L_LOWER_B 17, HCLK_CMT_L 8 |
| xc7z020 | 39838438 | c19e8fa16e22 | bc50b369687d | 2353 → 2302 | 51 | 51 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 18, HCLK_CMT 8, HCLK_CMT_L 8 |
| xc7z030 | 49186438 | 52f0369cfa4b | ff8b05c117b0 | 2469 → 2418 | 51 | 51 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 18, HCLK_CMT 8, HCLK_CMT_L 8 |
| xc7z045 | 65240318 | bfda448bf564 | 78883aefdc34 | 2469 → 2418 | 51 | 51 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 18, HCLK_CMT 8, HCLK_CMT_L 8 |
| xc7z100 | 76918990 | 21feccaf0e21 | bf2ffc91b176 | 2469 → 2418 | 51 | 51 | 0 | CMT_TOP_L_LOWER_B 17, CMT_TOP_R_LOWER_B 18, HCLK_CMT 8, HCLK_CMT_L 8 |
So the chipdb of every die changes (same size, different content), and every changed pip is one that a row of #30 names; none goes the other way.
The db at a90f27c1 (the one the current package carries) and master give a byte-identical chipdb for the three artix7 dies and a different one for the other seven.
An MMCM output feeding a BUFR or a BUFIO, end to end
Designs (top = clock pad → MMCME2_ADV → one output → BUFR in BYPASS or BUFIO → 32 registers fed by a counter; the pad-fed BUFR and the MMCM → BUFG are controls). Parts: xc7a35tcsg324-1 (a35), xc7a200tfbg484-1 (a200), xc7s50csga324-1 (s50), xc7z010clg400-1 (z010). The same netlist and the same placement in both db arms where both place.
| design | what it is |
|---|---|
| mb0 | MMCM CLKOUT0 → BUFR |
| mb3 | MMCM CLKOUT3 → BUFR (the case of nextpnr#24) |
| mbi3 | MMCM CLKOUT3 → BUFR and BUFIO |
| mi0 | MMCM CLKOUT0 → BUFIO |
| mi3 | MMCM CLKOUT3 → BUFIO |
| ctl-bufr-pad | control: pad → BUFR |
| ctl-mmcm-bufg | control: MMCM → BUFG |
Result of each run (rc 0 = nextpnr, fasm2frames with no unknown feature, xc7frames2bit and bit2fasm all returned 0):
| design | part | db master | db master + #30 + #31 |
|---|---|---|---|
| mb0 | a35 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT0 to X1Y130/BUFR_X0Y1.I. | rc 0 |
| mb0 | a200 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT0 to X1Y130/BUFR_X0Y0.I. | rc 0 |
| mb0 | s50 | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| mb0 | z010 | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| mb3 | a35 | rc 0 | rc 0 |
| mb3 | a200 | rc 0 | rc 0 |
| mb3 | s50 | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| mb3 | z010 | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c38_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| mbi3 | a35 | rc 0 | rc 0 |
| mbi3 | a200 | rc 125: ERROR: Failed to route arc 1.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT3 to X1Y130/BUFIO_X0Y1.I. | rc 0 |
| mbi3 | s50 | rc 125: ERROR: Unable to place cell 'c41_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c41_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| mbi3 | z010 | rc 125: ERROR: Unable to place cell 'c41_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c41_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| mi0 | a35 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT0 to X1Y130/BUFIO_X0Y3.I. | rc 0 |
| mi0 | a200 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT0 to X1Y130/BUFIO_X0Y2.I. | rc 0 |
| mi0 | s50 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT0 to X1Y130/BUFIO_X0Y3.I. | rc 0 |
| mi0 | z010 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X119Y95/MMCME2_ADV_X0Y0.CLKOUT0 to X126Y78/BUFIO_X0Y3.I. | rc 0 |
| mi3 | a35 | rc 0 | rc 0 |
| mi3 | a200 | rc 0 | rc 0 |
| mi3 | s50 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X8Y147/MMCME2_ADV_X0Y0.CLKOUT3 to X1Y130/BUFIO_X0Y3.I. | rc 0 |
| mi3 | z010 | rc 125: ERROR: Failed to route arc 0.0 of net 'c', from X119Y95/MMCME2_ADV_X0Y0.CLKOUT3 to X126Y78/BUFIO_X0Y3.I. | rc 0 |
| ctl-bufr-pad | a35 | rc 0 | rc 0 |
| ctl-bufr-pad | a200 | rc 0 | rc 0 |
| ctl-bufr-pad | s50 | rc 125: ERROR: Unable to place cell 'c14_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c14_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| ctl-bufr-pad | z010 | rc 125: ERROR: Unable to place cell 'c14_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' | rc 125: ERROR: Unable to place cell 'c14_BUFR', no BELs remaining to implement cell type 'BUFR_BUFR' |
| ctl-mmcm-bufg | a35 | rc 0 | rc 0 |
| ctl-mmcm-bufg | a200 | rc 0 | rc 0 |
| ctl-mmcm-bufg | s50 | rc 0 | rc 0 |
| ctl-mmcm-bufg | z010 | rc 0 | rc 0 |
Of the 20 MMCM → BUFR/BUFIO runs, 5 build with db master and 14 with db master + #30 + #31. The ones that still fail in both arms are the BUFR cases on spartan7 and zynq7 ("no BELs remaining to implement cell type BUFR_BUFR", also with a pad-fed BUFR: an engine matter, not the db).
Where both arms build, the placement is byte-identical.
What a build with db master is. Five runs build with db master (mb3 on a35 and a200, mbi3 on a35, mi3 on a35 and a200). They route CLKOUT3 through CMT_R_LOWER_B_CLK_PERF1 and HCLK_CMT_MUX_PHSR_PERFCLKn ← MUXED1, pips whose rows #30 rewrites. The .bit nextpnr wrote with them, read back with the rows of #30, no longer contains those pips (< = with master's rows, > = with #30's):
| run | pips read back with master's rows and not with #30's |
|---|---|
| mb3/a200 | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT3; HCLK_CMT_MUX_PHSR_PERFCLK0.HCLK_CMT_MUX_MMCM_MUXED1 |
| mb3/a35 | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT3; HCLK_CMT_MUX_PHSR_PERFCLK0.HCLK_CMT_MUX_MMCM_MUXED1 |
| mbi3/a35 | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT3; HCLK_CMT_MUX_PHSR_PERFCLK0.HCLK_CMT_MUX_MMCM_MUXED1; HCLK_CMT_MUX_PHSR_PERFCLK1.HCLK_CMT_MUX_MMCM_MUXED1 |
| mi3/a200 | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT3; HCLK_CMT_MUX_PHSR_PERFCLK0.HCLK_CMT_MUX_MMCM_MUXED1 |
| mi3/a35 | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT3; HCLK_CMT_MUX_PHSR_PERFCLK1.HCLK_CMT_MUX_MMCM_MUXED1 |
So the five builds that work today carry bits that, read with #30's rows, are not those pips. Whether such a clock path runs on silicon is not measured. From the other side, the Vivado bitstream of each case read back with each db (same bit2fasm, same file; Vivado placed and routed it itself):
| run | read only with master's rows | read only with #30's rows | unknown bits (master / #30) |
|---|---|---|---|
| mb0/a200 | none | CMT_R_LOWER_B_CLK_PERF3.CMT_LR_LOWER_B_MMCM_CLKOUT0 | 0 / 0 |
| mb0/a35 | none | CMT_R_LOWER_B_CLK_PERF3.CMT_LR_LOWER_B_MMCM_CLKOUT0 | 0 / 0 |
| mb3/a200 | none | CMT_R_LOWER_B_CLK_PERF3.CMT_LR_LOWER_B_MMCM_CLKOUT3 | 0 / 0 |
| mb3/a35 | none | CMT_R_LOWER_B_CLK_PERF3.CMT_LR_LOWER_B_MMCM_CLKOUT3 | 0 / 0 |
| mbi3/a200 | none | CMT_R_LOWER_B_CLK_PERF3.CMT_LR_LOWER_B_MMCM_CLKOUT3 | 0 / 0 |
| mi0/a200 | none | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT0 | 0 / 0 |
| mi0/a35 | none | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT0 | 0 / 0 |
| mi0/s50 | none | CMT_R_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT0; HCLK_CMT_MUX_PHSR_PERFCLK1.HCLK_CMT_MUX_MMCM_MUXED1 | 0 / 0 |
| mi0/z010 | none | CMT_L_LOWER_B_CLK_PERF1.CMT_LR_LOWER_B_MMCM_CLKOUT0; HCLK_CMT_MUX_PHSR_PERFCLK1.HCLK_CMT_MUX_MMCM_MUXED1 | 0 / 0 |
| mi3/s50 | none | HCLK_CMT_MUX_PHSR_PERFCLK1.HCLK_CMT_MUX_MMCM_MUXED1 | 0 / 0 |
| mi3/z010 | none | HCLK_CMT_MUX_PHSR_PERFCLK1.HCLK_CMT_MUX_MMCM_MUXED1 | 0 / 0 |
11 of 20 Vivado bitstreams read differently; the runs not shown read the same. Every difference is a CLK_PERFn.CLKOUTm or PERFCLKn ← MUXEDm pip that only #30's rows name. No unknown bit appears with either db.
Against Vivado, same placement
For every run that builds with db master + #30 + #31 (20 runs), Vivado 2026.1 was given the same netlist with every cell fixed where nextpnr placed it (LOC/BEL, LUT pins), routed freely, and both bitstreams went through bit2fasm. Window = the tiles that carry the clock path (CMT_TOP_*, HCLK_CMT*, HCLK_IOI*, HCLK_L/R) plus every placed cell's tile. SITE features decide; pips are routing and are listed. Unknown bits in either bitstream: 0 in all 20 runs, and 0 in the 11 runs of db master.
| run | clock pips: same chain as Vivado | site features only nextpnr writes (path tiles) | site features only Vivado writes (path tiles) |
|---|---|---|---|
| ctl-bufr-pad/a200 | identical pips | HCLK_CMT_L_X256Y130.HCLK_CMT_CK_BUFRCLK0_USED, HCLK_CMT_L_X256Y130.HCLK_CMT_CK_BUFRCLK1_USED, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q4 | HCLK_CMT_X8Y130.HCLK_CMT_CCIO1_ACTIVE |
| ctl-bufr-pad/a35 | identical pips | HCLK_CMT_L_X106Y26.HCLK_CMT_CK_BUFRCLK0_USED, HCLK_CMT_L_X106Y26.HCLK_CMT_CK_BUFRCLK1_USED, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | HCLK_CMT_X8Y26.HCLK_CMT_CCIO1_ACTIVE |
| ctl-mmcm-bufg/a200 | identical pips | HCLK_CMT_L_X256Y130.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_CMT_X8Y130.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_R_X12Y130.ENABLE_BUFFER.HCLK_CK_BUFHCLK0 | HCLK_CMT_X8Y130.HCLK_CMT_CK_BUFHCLK8_USED, HCLK_L_X11Y130.ENABLE_BUFFER.HCLK_CK_BUFHCLK8 |
| ctl-mmcm-bufg/a35 | identical pips | HCLK_CMT_L_X106Y78.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_CMT_X8Y78.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_R_X12Y78.ENABLE_BUFFER.HCLK_CK_BUFHCLK0 | HCLK_CMT_X8Y78.HCLK_CMT_CK_BUFHCLK8_USED, HCLK_L_X11Y78.ENABLE_BUFFER.HCLK_CK_BUFHCLK8 |
| ctl-mmcm-bufg/s50 | identical pips | HCLK_CMT_L_X106Y78.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_CMT_X8Y78.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_R_X12Y78.ENABLE_BUFFER.HCLK_CK_BUFHCLK0 | HCLK_CMT_X8Y78.HCLK_CMT_CK_BUFHCLK8_USED, HCLK_L_X11Y78.ENABLE_BUFFER.HCLK_CK_BUFHCLK8 |
| ctl-mmcm-bufg/z010 | identical pips | HCLK_CMT_L_X119Y78.HCLK_CMT_CK_BUFHCLK0_USED, HCLK_R_X116Y78.ENABLE_BUFFER.HCLK_CK_BUFHCLK0 | HCLK_CMT_L_X119Y78.HCLK_CMT_CK_BUFHCLK8_USED, HCLK_L_X115Y78.ENABLE_BUFFER.HCLK_CK_BUFHCLK8 |
| mb0/a200 | a different, internally consistent lane | HCLK_CMT_L_X256Y130.HCLK_CMT_CK_BUFRCLK2_USED | MMCME2_ADV.CLKOUT3_CLKOUT1_HIGH_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT1_LOW_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT2_NO_COUNT[0] |
| mb0/a35 | a different, internally consistent lane | HCLK_CMT_L_X106Y26.HCLK_CMT_CK_BUFRCLK3_USED | MMCME2_ADV.CLKOUT3_CLKOUT1_HIGH_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT1_LOW_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT2_NO_COUNT[0] |
| mb3/a200 | a different, internally consistent lane | HCLK_CMT_L_X256Y130.HCLK_CMT_CK_BUFRCLK2_USED | none |
| mb3/a35 | a different, internally consistent lane | HCLK_CMT_L_X106Y26.HCLK_CMT_CK_BUFRCLK3_USED | none |
| mbi3/a200 | a different, internally consistent lane | HCLK_CMT_L_X256Y130.HCLK_CMT_CK_BUFRCLK3_USED, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q4 | none |
| mbi3/a35 | a different, internally consistent lane | HCLK_CMT_L_X106Y26.HCLK_CMT_CK_BUFRCLK0_USED, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | none |
| mi0/a200 | identical pips | LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q4 | MMCME2_ADV.CLKOUT3_CLKOUT1_HIGH_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT1_LOW_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT2_NO_COUNT[0] |
| mi0/a35 | identical pips | LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | MMCME2_ADV.CLKOUT3_CLKOUT1_HIGH_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT1_LOW_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT2_NO_COUNT[0] |
| mi0/s50 | identical pips | LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | MMCME2_ADV.CLKOUT3_CLKOUT1_HIGH_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT1_LOW_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT2_NO_COUNT[0] |
| mi0/z010 | identical pips | RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | MMCME2_ADV.CLKOUT3_CLKOUT1_HIGH_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT1_LOW_TIME[0], MMCME2_ADV.CLKOUT3_CLKOUT2_NO_COUNT[0] |
| mi3/a200 | identical pips | LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y147.ILOGIC_Y1.IFF.ZSRVAL_Q4 | none |
| mi3/a35 | identical pips | LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | none |
| mi3/s50 | identical pips | LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, LIOI3_X0Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | none |
| mi3/z010 | identical pips | RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q1, RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q2, RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q3, RIOI3_X31Y47.ILOGIC_Y1.IFF.ZSRVAL_Q4 | none |
Reading of the lists (each point was checked on every row they appear in):
- The clock path itself: in the 14 MMCM → BUFR/BUFIO runs the only Vivado-only SITE features in the path tiles are the
CLKOUT3defaults below; theHCLK_CMT_CK_BUFRCLKn_USED,ENABLE_BUFFER.HCLK_CK_BUFRCLKn,BUFR_Yn.IN_USEandBUFR_DIVIDE.BYPASSfeatures are written by both. The pips differ only in WHICH of the four performance lanes (PERF0..3) the router picked; each tool's lane is consistent fromCLKOUTnto the BUFR/BUFIO (the same index in the four tiles). - nextpnr-only
HCLK_CMT_L.HCLK_CMT_CK_BUFRCLKn_USED(the HCLK_CMT tile on the other side of the die): present with db master and in the pad-fed control, so cmt, hclk_cmt: CLK_PERF and PHSR_PERFCLK rows with all their bits #30 does not cause it. Vivado does not write it. Whether it matters on silicon is not known. - nextpnr-only
ILOGIC_Y1.IFF.ZSRVAL_Q1..Q4: the IDDR of the stimulus, also in the pad-fed control; unrelated to the clock lanes. - Vivado-only
CLKOUT3_*of the MMCM in mb0 and mi0: these designs do not useCLKOUT3, and Vivado writes the defaults of the unused outputs (the control shows the same 22 features for the outputs it does not use). CCIO1_ACTIVEonly Vivado, in the pad-fed control, and theBUFHCLKrows of the MMCM → BUFG control: the global clock path, which cmt, hclk_cmt: CLK_PERF and PHSR_PERFCLK rows with all their bits #30 does not touch.- The 22 MMCM features Vivado writes and nextpnr does not (
CLKOUTndefault timing registers andZINV_*) are the same in the MMCM → BUFG control.
With db master, the 11 runs that build show the same classes of difference against Vivado; the lists are in the artifacts.
Read back
Features nextpnr wrote in the CMT, HCLK_CMT, HCLK_IOI and HCLK tiles, against what bit2fasm reads back from the .bit (20 runs): 1181 written, 0 lost (a feature with a row whose bits are not read back), 150 not read back because they have no row in the db (pips that set no bit, e.g. HCLK_IOI_RCLK2RCLK3 → HCLK_IOI_RCLK_OUT3).
What this does not cover: only CLKOUT0 and CLKOUT3 of the MMCM, BUFR in BYPASS only (no divider), no PLLE2, the lower-half CMT only, the artix7 parts a35 and a200 for BUFR (spartan7 and zynq7 for BUFIO only), and nothing on silicon. Timing is not modelled. The rows of #30 for CLKOUT1/2/4/5/6 and CLKFBOUT were read from the diff, not exercised.
prjxray #27 and #28 — xc7frames2bit
#27 touches lib/include/prjxray/xilinx/frames.h, lib/xilinx/tests/xc7series/frames_test.cc and tools/xc7frames2bit.cc; #28 touches tools/xc7frames2bit.cc only. Neither touches fasm2frames or bitread.
xc7frames2bit of master, of #27, of #28 and of both, on the same .frames file, the same --part_file and the same relative path for --frm_file. Frames files: every design of the suite in both db arms, the 37-part e2e, and every case of the table above that reached fasm2frames.
| source | frames files | rc 0 in all four tools | .bit equal to master's (every field) with #27 / #28 / both |
"not in the part" |
|---|---|---|---|---|
| suite | 116 | 116 | 116 / 116 / 116 | 0 |
| e2e | 37 | 37 | 37 / 37 / 37 | 0 |
| MMCM → BUFR/BUFIO cases | 31 | 31 | 31 / 31 / 31 | 0 |
| total | 184 | 184 |
The suite designs include bram, dsp48, pll, srl, srl-cascade, lutram, tristate, carry64, congestion-local, demo-zybo, spartan7-blinky; the parts are artix7, spartan7 and zynq7. No frames file was rejected.
What this does not cover: kintex7 and virtex7 frames (no part of the manifest and no design here); a .frames file with an address that really is not in the part (the PRs' own unit tests cover the rejection); the loaded .bit on a board.
What was not measured, in one list
- Silicon. The only board evidence for the new rows is the AX7203 test in nextpnr#24, which used the classic engine.
- Timing and the BUFR divider values (only BYPASS), PLLE2, upper-half CMTs, kintex7 and virtex7.
- The rows of cmt, hclk_cmt: CLK_PERF and PHSR_PERFCLK rows with all their bits #30 for the outputs and lanes not listed above, and the DSP rows of artix7, kintex7, spartan7, zynq7: DSP48E1 AREG_1 and BREG_1 #31 against Vivado.
- The far-side
HCLK_CMT_L…BUFRCLKn_USEDnextpnr writes and Vivado does not: present before the PRs; its effect is unknown. - The CI run of cmt, hclk_cmt: CLK_PERF and PHSR_PERFCLK rows with all their bits #30 (it sits in
action_required).
Follows openXC7/nextpnr#24 and cavearr's two PERFCLK populations:
CLK_PERFnandPERFCLKnsource is forced.The checking scripts are at https://gist.github.com/gHashTag/3c9216880b77946385dfc5bea317d927.
What changes
The third commit (
c030ed6) supersedes the rows of the first two. The rows below are the same in all four families (artix7, kintex7, spartan7, zynq7) and on both sides.CMT_TOP_{L,R}_LOWER_B: 20 rows per tile. EachCLK_PERFnmux has an enable bit E, two code bits A and B, and a feedback bit F:CLK_PERF029_102328_99729_99729_996CLK_PERF128_102329_99528_99628_995CLK_PERF229_102228_99429_99429_993CLK_PERF328_102229_99228_99328_992The rows are
CLKFBOUT = E F,CLKOUT0 = E !A !B !F,CLKOUT1 = E !A B,CLKOUT2 = E A !BandCLKOUT3 = E A B. The!bits keep the rows exclusive.This replaces three wrong rows:
CLK_PERF0.CLKOUT2 = 28_997 29_1023(master since ae4770b) also fires on everyCLKOUT3route: 268 tile samples in 2026-10.CLK_PERF1.CLKOUT3 = 28_996andCLK_PERF2.CLKOUT3 = 29_994leave the enable bit and one code bit clear.29_994alone also fires on everyCLKOUT1route ofCLK_PERF2: 204 samples in 2026-09.The other 17 rows are new, among them the remaining
CLK_PERF0andCLK_PERF1positions. zynq7CMT_TOP_R_LOWER_Bhad noCLK_PERF0row at all.HCLK_CMT/HCLK_CMT_L: 8 rows per tile.PERFCLKp <- MUXEDmsets three bits:(26+p)_(176+(m&1));(26+p)_180;29_134,28_134,29_133or28_133forMUXED0..3.There are rows for
PERFCLK0/1 <- MUXED0/1and forPERFCLK2/3 <- MUXED2/3. Before this PR, kintex7, spartan7 and zynq7 had noPHSR_PERFCLKrows, and artix7 had six rows: some left out the used or the select bit, andPERFCLK0.MUXED0andPERFCLK3.MUXED2were missing.No ppips. Every position sets its enable bit, so no position is a default.
Rows that the third commit adds or changes carry origin
039c-perfclk01-forced-mux. Rows from the first two commits that it leaves alone keep039b.How it was checked
This check is independent of the campaigns' own scripts and segdata.
design.bitwas read withbitreadand mapped to tile bits through this repo's tilegrid.CMT_TOP_*_LOWER_BandHCLK_CMT*tile of every specimen, used or not.bit2fasmdoes: a row fires when its bits are set and its!bits are clear. The result is compared with the pips Vivado routed.fasm2framesdoes: it takes the positive bits of the rows for the routed pips. The result is compared with the bitstream over all 16 bits of the mux group.Under the same check, the rows at
0a07070(the head of this PR beforec030ed6) give these results on 2026-10:A correction to this description's earlier version. It said that encode was exact "over every bit any row mentions" in all 2888 HCLK samples. That was true, but it was measured over the wrong set: a bit that no row names cannot show up as missing. Over all 16 bits, those HCLK rows are short in 1230 of the 2888 samples. The difference was always missing bits, never extra ones. The check now compares the whole group.
Negative control. I removed
29_1022fromCLK_PERF2.CLKOUT1. Decode stays clean, and encode flags 80/80/44/56 samples.utils/parsedb.py --strictpasses on all 16 changedsegbits_*.db.Not measured
bit2fasm/fasm2framesround trip with these rows. The check models those tools; it does not call them.PHASERIN_RCLKside of PERFCLK.CLK_PERF0.CLKOUT3 = 28_997looks like a subset row of the same kind.mask_hclk_cmt{,_l}.db. It lists none of the 16 PERFCLK bits, and master is the same. It is left as it is.🤖 Generated with Claude Code