Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/website-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,12 @@ jobs:
- name: Queen WIDGETS gallery
run: npm run check:widgets && npm run test:widgets-spec

# The widget tools: each specs/widgets/<id>.t27 writes its own page under
# public/widgets/<id>/ (og card, words, the spec copy), runs its own test
# blocks, and must declare that it sends the reader's data nowhere.
- name: Widget tool pages
run: npm run check:widget-pages && npm run test:widget-pages

# The IGLA board on WARS: specs/queen/igla_board.t27 is generated in
# gHashTag/igla-coder-gpu from committed artifacts. The gate recompiles it,
# re-derives every McNemar p from its discordants, and proves the public
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ build_zig13_old.zig
!test/**/*.sh
*.vcd
*.tvc
# A widget's demo data ships with its page: the page's ?v= stamp hashes it.
!apps/website/public/widgets/**/*.vcd

# Core dumps
core
Expand Down
2 changes: 2 additions & 0 deletions apps/website/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Logs
logs
*.log
# A widget's sample logs ship with its page (synth-smells reads yosys logs).
!public/widgets/**/*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
Expand Down
6 changes: 4 additions & 2 deletions apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"check:queen-evidence": "node scripts/queen-evidence-from-spec.mjs --check",
"predev": "node scripts/queen-evidence-from-spec.mjs --check",
"prebuild:ci": "npm run core -- index && node scripts/skills-core.mjs index && node scripts/agents-from-specs.mjs && node scripts/docs-from-specs.mjs && node scripts/viewport-from-spec.mjs && node scripts/onboarding-from-spec.mjs && node scripts/play-from-spec.mjs && node scripts/queen-wars-from-spec.mjs && node scripts/widgets-from-spec.mjs && node scripts/igla-board-from-spec.mjs && node scripts/queen-evidence-from-spec.mjs --check",
"prebuild:ci": "npm run core -- index && node scripts/skills-core.mjs index && node scripts/agents-from-specs.mjs && node scripts/docs-from-specs.mjs && node scripts/viewport-from-spec.mjs && node scripts/onboarding-from-spec.mjs && node scripts/play-from-spec.mjs && node scripts/queen-wars-from-spec.mjs && node scripts/widget-pages-from-spec.mjs && node scripts/widgets-from-spec.mjs && node scripts/igla-board-from-spec.mjs && node scripts/queen-evidence-from-spec.mjs --check",
"atlas": "node --experimental-strip-types scripts/universe-atlas.mjs",
"discover": "node scripts/discover-t27-worlds.mjs",
"check:discovery": "node --experimental-strip-types qa/t27-world-discovery.mjs",
Expand All @@ -21,7 +21,7 @@
"check:traffic-arrival": "node --experimental-strip-types qa/traffic-arrival-contract.mjs",
"core": "node scripts/spec-core.mjs",
"check:shared-core": "node --experimental-strip-types qa/shared-spec-core.mjs",
"prebuild": "npm run core -- index && node scripts/skills-core.mjs index && node scripts/agents-from-specs.mjs && node scripts/docs-from-specs.mjs && node scripts/viewport-from-spec.mjs && node scripts/onboarding-from-spec.mjs && node scripts/play-from-spec.mjs && node scripts/queen-wars-from-spec.mjs && node scripts/widgets-from-spec.mjs && node scripts/igla-board-from-spec.mjs",
"prebuild": "npm run core -- index && node scripts/skills-core.mjs index && node scripts/agents-from-specs.mjs && node scripts/docs-from-specs.mjs && node scripts/viewport-from-spec.mjs && node scripts/onboarding-from-spec.mjs && node scripts/play-from-spec.mjs && node scripts/queen-wars-from-spec.mjs && node scripts/widget-pages-from-spec.mjs && node scripts/widgets-from-spec.mjs && node scripts/igla-board-from-spec.mjs",
"dev": "vite",
"build": "vite build",
"build:ci": "vite build",
Expand Down Expand Up @@ -120,6 +120,8 @@
"test:wars-spec": "node --test scripts/queen-wars-from-spec.test.mjs",
"check:widgets": "node scripts/widgets-from-spec.mjs --check",
"test:widgets-spec": "node --test scripts/widgets-from-spec.test.mjs",
"check:widget-pages": "node scripts/widget-pages-from-spec.mjs --check",
"test:widget-pages": "node --test scripts/widget-pages-from-spec.test.mjs",
"check:igla-board": "node scripts/igla-board-from-spec.mjs --check && node qa/igla-board-contract.mjs",
"check:roadmap-game": "node --experimental-strip-types qa/roadmap-game-contract.mjs",
"check:og-preview": "node --experimental-strip-types qa/og-preview-contract.mjs",
Expand Down
148 changes: 148 additions & 0 deletions apps/website/public/widgets/bit-diff/bit-diff.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: Apache-2.0
; specs/widgets/bit-diff.t27 -- two Xilinx 7-series bitstreams compared frame by frame
; Source of truth for public/widgets/bit-diff/ (gHashTag/trinity): scripts/widget-pages-from-spec.mjs
; compiles this file, checks its constants, evaluates the tests below and writes the page; the page
; hands every constant to tool.js as window.T27_WIDGET. tool.js holds no English of its own: every
; word on screen is a SAY_ constant here, every number the tool relies on is a K_ constant.
; ASCII only (L3), English only (LANG-EN).

; WHAT IT DOES: reads two bitstreams the reader drops or picks (.bit with its header, or a raw
; .bin), in the reader's browser, with FileReader. It reads the .bit header (design, part, date,
; time), finds the sync word, walks the type 1 and type 2 configuration packets, collects the FDRI
; frame data, gives each 101-word frame its frame address (FAR) from the die's row and column
; layout, and reports: byte-identical or not, the header side by side, the packet and command
; sequence side by side, the first frame that differs with its FAR decoded, and a map of which
; frames differ. The file never leaves the page; nothing is uploaded.

; DATA PROVENANCE: the two demo pairs are summaries computed by the same parser
; (public/widgets/bit-diff/bitparse.js) run in node by scripts/widget-data/bit-diff.mjs on the
; real files; the bitstreams themselves are not shipped (about 9.7 MB each). Pair one is the
; x7-board recording (t27.ai/term/x7-board/): ours.bit, written by bitwalk from frames t27 placed,
; against trinet_node0.bit, written by openXC7's xc7frames2bit, both for xc7a200tfbg484-2. Pair two
; is two real Ethernet builds of the AX7203 node from trinity-fpga artifacts/bitstreams (E2 PHY
; status, E3 ARP and ICMP), so the demo also shows what a difference looks like. The row and column
; layout (geometry.json) is read from prjxray-db ab1fc60 part.json for the four Artix-7 dies; the
; frame mapping was checked against bitwalk's .frames file: all 20230 listed frames sit at their
; addresses in the .bit, word for word apart from the ECC word the .bit writer fills in.

; WHAT IT DOES NOT CLAIM: that two identical bitstreams were built from the same sources, or that
; two different ones behave differently on a board. It does not read compressed (MFWR) or encrypted
; (CBC) bitstreams, readback files, or devices other than 7-series; a part with no geometry gets
; frames in stream order with only the first address known. Frame addresses come from prjxray-db,
; not from AMD documentation.
; phi^2 + 1/phi^2 = 3 | TRINITY

module widget_bit_diff;

pub const KIND : str = "widget-tool";
pub const ID : str = "bit-diff";
pub const TITLE : str = "Bitstream diff: two 7-series .bit files, frame by frame";
pub const DESCRIPTION : str = "Drop two Xilinx 7-series bitstreams: header, packets and every 101-word frame compared in your browser, the first differing frame address decoded. Nothing is uploaded.";
pub const IMAGE_ALT : str = "Bitstream diff card: t27's ours.bit against openXC7's trinet_node0.bit for the XC7A200T, byte-identical across all 24,080 configuration frames, with the same sha256 68249475b57e623f; beside it a frame map of two Ethernet builds where 590 frames differ.";
pub const HOOK : str = "Check the byte-identical claim yourself: drop t27's .bit and openXC7's and see every frame compared, or the first one that is not.";
pub const CATEGORY : str = "fpga";
pub const DATA_SOURCES : [5]str = ["t27.ai/term/x7-board/ recording: /tmp/x7board/node0/ours.bit (bitwalk) and trinet_node0.bit (openXC7 xc7frames2bit), sha256 68249475b57e623f05564e3d839cfb0c7e7b3e21fe89a014953f12fdd53f95b3", "trinity-fpga artifacts/bitstreams: e2_eth_phy_status_zinv_t1.bit (sha256 501ab904...) and e3_eth_arp_icmp_zinv_t1.bit (sha256 e75a6ff7...)", "prjxray-db ab1fc60 artix7 part.json: rows, columns and frames per column of xc7a35t, xc7a50t, xc7a100t, xc7a200t", "AMD UG470 7 Series FPGAs Configuration: packet header, register and command codes, frame address fields", "scripts/widget-data/bit-diff.mjs: the summaries, computed by public/widgets/bit-diff/bitparse.js in node"];
pub const READS_LOCAL_FILES : bool = true;
pub const SENDS_NOTHING : bool = true;

; --- Numbers the tool relies on ------------------------------------------------------------
; 0xAA995566, the word after which the configuration logic reads packets.
pub const K_SYNC_WORD : u32 = 2862175590;
pub const K_FRAME_WORDS : u8 = 101;
; Word 50 of a frame carries the frame ECC in bits 0..12; the rest of it is configuration.
pub const K_ECC_WORD : u8 = 50;
pub const K_ECC_MASK : u16 = 8191;
; Every configuration row in the FDRI stream ends with two pad frames.
pub const K_PAD_FRAMES_PER_ROW : u8 = 2;
; XC7A200T: IDCODE 0x03636093, five clock-region rows (two top, three bottom), each with 3660
; CLB/IO/CLK frames and 1152 block RAM frames (prjxray-db part.json).
pub const K_XC7A200T_IDCODE : u32 = 56844435;
pub const K_XC7A200T_ROWS : u8 = 5;
pub const K_XC7A200T_CLB_ROW_FRAMES : u16 = 3660;
pub const K_XC7A200T_BRAM_ROW_FRAMES : u16 = 1152;
pub const K_XC7A200T_FRAMES : u32 = 24080;
; Cells per band in the frame map.
pub const K_STRIP_BUCKETS : u16 = 160;
; Frames compared between two pauses that let the page draw.
pub const K_CHUNK_FRAMES : u16 = 2000;

; --- Words on screen ------------------------------------------------------------------------
; Templates take {0}, {1}, ... in order.
pub const SAY_DEMO_LABEL : str = "Real pairs, precomputed";
pub const SAY_DEMO_IDS : [2]str = ["x7-board", "e2-e3"];
pub const SAY_DEMO_NAMES : [2]str = ["t27 vs openXC7", "E2 vs E3 Ethernet"];
pub const SAY_DEMO_LINES : [2]str = ["ours.bit, written by bitwalk from t27's frames, against trinet_node0.bit from openXC7's xc7frames2bit: the x7-board recording.", "Two real builds of the AX7203 node: E2 (PHY status) and E3 (ARP and ICMP), from trinity-fpga artifacts."];
pub const SAY_DEMO_NOTE : str = "Computed in node by this page's own parser on the real files; the 9.7 MB bitstreams are not shipped. Drop them below to compute it again here.";
pub const SAY_OWN_LABEL : str = "Your two files";
pub const SAY_DROP_A : str = "A: drop or pick a .bit or .bin";
pub const SAY_DROP_B : str = "B: drop or pick a .bit or .bin";
pub const SAY_PICKED : str = "{0}: {1} bytes";
pub const SAY_COMPARE : str = "Compare";
pub const SAY_CLEAR : str = "Clear";
pub const SAY_READING : str = "Reading {0}";
pub const SAY_COMPARING : str = "Comparing frames: {0} of {1}";
pub const SAY_LOCAL_NOTE : str = "Read in this tab with FileReader; nothing is uploaded.";
pub const SAY_IDENTICAL : str = "Byte-identical";
pub const SAY_FRAMES_SAME : str = "Frames identical";
pub const SAY_DIFFERS : str = "Not identical";
pub const SAY_SAME_LINE : str = "{0} configuration frames, every byte the same; sha256 {1}";
pub const SAY_FRAMES_SAME_LINE : str = "All {0} configuration frames are the same; the files differ outside them.";
pub const SAY_DIFF_LINE : str = "{0} of {1} frames differ";
pub const SAY_ONLY_ONE_LINE : str = "{0} frames are in one file only";
pub const SAY_BY_POSITION : str = "Frames paired by position: no shared frame-address layout for these files.";
pub const SAY_HEADER_TITLE : str = "Header and stream";
pub const SAY_COL_FIELD : str = "field";
pub const SAY_COL_A : str = "A";
pub const SAY_COL_B : str = "B";
pub const SAY_FIELDS : [13]str = ["file", "bytes", "sha256", "design", "part", "date", "time", "IDCODE", "sync word at byte", "frames", "FDRI writes", "bytes after DESYNC", "notes"];
pub const SAY_NO_HEADER : str = "none (raw .bin)";
pub const SAY_FIRST_TITLE : str = "First differing frame";
pub const SAY_FAR_FIELDS : [6]str = ["frame address", "block type", "half", "row", "column", "minor"];
pub const SAY_BLOCKS : [3]str = ["CLB, IO, CLK", "block RAM content", "CFG CLB"];
pub const SAY_BLOCKS_SHORT : [3]str = ["CLB", "BRAM", "CFG"];
pub const SAY_HALVES : [2]str = ["top", "bottom"];
pub const SAY_FIRST_LINE : str = "Frame {0} of the stream: {1} words and {2} bits differ, {3} of those bits in the ECC field.";
pub const SAY_ONLY_ONE_FIRST : str = "Frame {0} of the stream is in one file only.";
pub const SAY_NO_FAR : str = "unknown";
pub const SAY_WORD_HEAD : [3]str = ["word", "A", "B"];
pub const SAY_MAP_TITLE : str = "Frame map";
pub const SAY_MAP_LINE : str = "One band per configuration row, in frame-address order from left to right; each cell is a run of frames.";
pub const SAY_LEGEND : [3]str = ["same", "differs", "in one file only"];
pub const SAY_PACKETS_TITLE : str = "Packets and commands";
pub const SAY_PACKETS_SAME : str = "The same {0} packet lines in both files (repeats folded).";
pub const SAY_PACKETS_DIFF : str = "{0} packet lines differ.";
pub const SAY_SHOW_PACKETS : str = "Show packets";
pub const SAY_HIDE_PACKETS : str = "Hide packets";
pub const SAY_WARN_IDS : [6]str = ["nosync", "encrypted", "compressed", "truncated", "badheader", "partialframe"];
pub const SAY_WARN_TEXT : [6]str = ["no sync word 0xAA995566 found", "encrypted (writes CBC): frames not readable", "compressed (writes MFWR): frames not all present", "file ends inside a packet", "words that are not packet headers", "FDRI data is not a whole number of frames"];
pub const SAY_ERR_READ : str = "Could not read {0}.";
pub const SAY_ERR_DEMO : str = "The demo summary did not load.";

; --- Tests ----------------------------------------------------------------------------------
test the_sync_word_is_aa995566 {
assert K_SYNC_WORD == 2862175590;
assert K_SYNC_WORD == 170 * 16777216 + 153 * 65536 + 85 * 256 + 102;
}

test a_frame_is_101_words_and_ecc_sits_inside_it {
assert K_FRAME_WORDS == 101;
assert K_ECC_WORD < K_FRAME_WORDS;
assert K_ECC_MASK == 8191;
}

test the_xc7a200t_stream_holds_24080_frame_slots {
assert K_XC7A200T_FRAMES == K_XC7A200T_ROWS * (K_XC7A200T_CLB_ROW_FRAMES + K_PAD_FRAMES_PER_ROW) + K_XC7A200T_ROWS * (K_XC7A200T_BRAM_ROW_FRAMES + K_PAD_FRAMES_PER_ROW);
assert K_XC7A200T_FRAMES != K_XC7A200T_ROWS * (K_XC7A200T_CLB_ROW_FRAMES + K_XC7A200T_BRAM_ROW_FRAMES);
assert K_XC7A200T_IDCODE == 56844435;
}

test the_demo_opens_on_the_x7_board_pair {
assert SAY_DEMO_IDS[0] == "x7-board";
assert SAY_DEMO_IDS[1] == "e2-e3";
}

test the_page_reads_files_and_sends_nothing {
assert READS_LOCAL_FILES == true;
assert SENDS_NOTHING == true;
assert CATEGORY == "fpga";
}
Loading
Loading