// SPDX-License-Identifier: Apache-2.0 ; specs/widgets/lut-explain.t27 -- a Xilinx 7-series LUT6 INIT read as logic, and the FASM line that sets it ; Source of truth for public/widgets/lut-explain/ (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, and every number is a K_ constant or a field of the two ; data files the script below wrote. ASCII only (L3), English only (LANG-EN). ; WHAT IT DOES: three views. Decode: the reader pastes a 64-bit INIT or FASM lines (or drops a ; .fasm file, read in the tab and sent nowhere); the page shows the 64-row truth table (tap a row ; to flip that bit and the INIT follows), the inputs that matter, a minimal sum of products from a ; small Quine-McCluskey in lut.js, the function's name when it has one, the two LUT5 halves, and ; each FASM line split into tile, site, BEL and feature with what prjxray-db says it sets. Guess ; the gate: an INIT from our own routed design and four names to pick from. Our design: the ; histogram of what all 4738 LUTs of that design are. ; THE BIT CONVENTION (UG474; prjxray-db segbits name the bits INIT[00]..INIT[63]): INIT[i] is the ; LUT output when the six inputs, read as a binary number, equal i, with input 0 as the least ; significant bit. In FASM the inputs are the pins A1..A6, so A1 = I0 and A6 = I5, and a 64'b value ; lists INIT[63] first. The tests below hold the INITs as four 16-bit words, word 0 = INIT[15:0], ; because the test evaluator has no 64-bit integers. ; DATA PROVENANCE: design.json and prjxray.json are written by scripts/widget-data/lut-explain.mjs, ; which runs the page's own decoder (public/widgets/lut-explain/lut.js) in node over node.fasm and ; over prjxray-db; its --selftest compares every K_DESIGN_ number and every K_EXAMPLE_ line here ; with that output and with the real file. node.fasm is the TRI-NET node v2 for the AX7203 board ; (xc7a200tfbg484-2), synthesised and routed by the tools and commands named in DATA_SOURCES. ; WHAT IT DOES NOT CLAIM: that the names are complete. A LUT with no short name here may still be ; a familiar gate of more inputs; the decoder knows the families listed in SAY_CLASS_ and no more. ; It does not claim the design came from t27: the node is hand-written Verilog. It does not claim ; the O5/O6 split was used: no LUT in this design routes O5, and the page says so. It does not ship ; the interconnect tiles' bits, only the CLBLL and CLBLM part of prjxray-db. ; phi^2 + 1/phi^2 = 3 | TRINITY module widget_lut_explain; pub const KIND : str = "widget-tool"; pub const ID : str = "lut-explain"; pub const TITLE : str = "LUT explain: a 7-series LUT6 INIT and its FASM line, read as logic"; pub const DESCRIPTION : str = "Paste a 64-bit LUT6 INIT or FASM lines: truth table, minimal expression, the gate's name, what each feature sets. Then guess the gate on 4738 LUTs from a routed design."; pub const IMAGE_ALT : str = "LUT explain card: INIT 64'h6996966996696996 is XOR6, the parity of six inputs. Beside it, the functions of 4738 LUTs routed by nextpnr-xilinx: XOR2 520, XNOR2 457, 2:1 mux 189, and 2251 with no short name."; pub const HOOK : str = "One routed design, 4738 LUTs: 1305 are XOR or XNOR, 2251 have no short name. Guess the gate from its 64 INIT bits."; pub const CATEGORY : str = "fpga"; pub const DATA_SOURCES : [6]str = ["node.fasm (sha256 e413fb51f92e88cb...), TRI-NET node v2 for the AX7203 board: part xc7a200tfbg484-2, top trinet_node_v2_ax7203, built in /tmp/x7board/node0 and recorded in its manifest.json", "Yosys 0.67+post (git b8e7da6f): synth_xilinx -flatten -abc9 -nocarry -nodsp -arch xc7. nextpnr-xilinx 0.9.2-107-g7037c948: --freq 50 --seed 1 --placer heap --router router1 --timing-allow-fail", "prjxray-db ab1fc60, artix7: segbits, ppips and tile_type JSON of CLBLL_L, CLBLL_R, CLBLM_L and CLBLM_R, extracted to prjxray.json", "prjxray c9f02d85, CLB fuzzer READMEs 011 to 019 (ffconfig, n5ffmux, ncy0, nffmux, noutmux, precyinit, ram, ndi1mux): what each CLB feature sets", "Xilinx UG474, 7 Series FPGAs CLB User Guide: a LUT6 is two LUT5s on shared inputs with outputs O5 and O6", "scripts/widget-data/lut-explain.mjs: runs this page's decoder (lut.js) over node.fasm, writes design.json and prjxray.json, and --selftest checks this spec's K_ numbers against them"]; pub const READS_LOCAL_FILES : bool = true; pub const SENDS_NOTHING : bool = true; ; --- Numbers --------------------------------------------------------------------------------- pub const K_N_INPUTS : u8 = 6; pub const K_N_BITS : u8 = 64; pub const K_DATA_PRJXRAY : str = "./prjxray.json"; pub const K_DATA_DESIGN : str = "./design.json"; pub const K_DESIGN_SHA256 : str = "e413fb51f92e88cbee0cdd82d588aaaed8313d5ddbc3b5c25177c465329995f4"; pub const K_DESIGN_LUTS : u16 = 4738; pub const K_DESIGN_DISTINCT : u16 = 2109; pub const K_DESIGN_NAMED : u16 = 2487; pub const K_DESIGN_OTHER : u16 = 2251; pub const K_DESIGN_XOR_FAMILY : u16 = 1305; pub const K_DESIGN_PINS_AGREE : u16 = 4738; pub const K_DESIGN_O5_USED : u16 = 0; pub const K_DESIGN_LUT_RAM_SRL : u16 = 0; pub const K_DESIGN_INEXACT : u16 = 1; pub const K_DESIGN_MAX_TERMS : u16 = 22; pub const K_DESIGN_TOP_KEY : str = "xor/2/0"; pub const K_DESIGN_TOP_COUNT : u16 = 520; pub const K_DESIGN_ROUNDS : u16 = 197; pub const K_ROUNDS_PER_CLASS : u8 = 4; pub const K_GAME_ROUNDS : u8 = 10; pub const K_GAME_CHOICES : u8 = 4; pub const K_HIST_SHOWN : u8 = 14; pub const K_DEFAULT_LOC : str = "CLBLM_L_X10Y248.SLICEM_X0.C"; ; The four INITs of the tests, as 16-bit words, word 0 = INIT[15:0]. pub const K_XOR6_WORDS : [4]u16 = [27030, 38505, 38505, 27030]; pub const K_AND6_WORDS : [4]u16 = [0, 0, 0, 32768]; pub const K_A1_WORDS : [4]u16 = [43690, 43690, 43690, 43690]; pub const K_A6_WORDS : [4]u16 = [0, 0, 65535, 65535]; ; Example buttons. The class keys are what lut.js says (checked by --selftest); the two FASM ; examples are lines of node.fasm, byte for byte (checked too). pub const K_EXAMPLE_INITS : [6]str = ["6996966996696996", "8000000000000000", "AAAAAAAAAAAAAAAA", "FFFFFFFF00000000", "E8E8E8E8E8E8E8E8", "CACACACACACACACA"]; pub const K_EXAMPLE_CLASSES : [6]str = ["xor/6/0", "and/6/0", "buf/1/0", "buf/1/0", "maj/3/0", "mux2/3/0"]; pub const K_EXAMPLE_N : [6]u8 = [6, 6, 1, 1, 3, 3]; pub const K_EXAMPLE_FASM_CARRY : [7]str = ["CLBLM_L_X10Y248.SLICEM_X0.CLUT.INIT[63:0] = 64'b1111111111101000111010000000000011111111111010001110100000000000", "CLBLM_L_X10Y248.CLBLM_M_C1.CLBLM_IMUX32", "CLBLM_L_X10Y248.CLBLM_M_C2.CLBLM_IMUX29", "CLBLM_L_X10Y248.CLBLM_M_C3.CLBLM_IMUX22", "CLBLM_L_X10Y248.CLBLM_M_C4.CLBLM_IMUX28", "CLBLM_L_X10Y248.CLBLM_M_C5.CLBLM_IMUX31", "CLBLM_L_X10Y248.CLBLM_LOGIC_OUTS14.CLBLM_M_C"]; pub const K_EXAMPLE_FASM_FF : [12]str = ["CLBLM_L_X10Y248.SLICEM_X0.ALUT.INIT[63:0] = 64'b1111101001010000111110100101000011111010010100001111101001010000", "CLBLM_L_X10Y248.SLICEM_X0.AOUTMUX.O6", "CLBLM_L_X10Y248.SLICEM_X0.AFFMUX.O6", "CLBLM_L_X10Y248.SLICEM_X0.AFF.ZINI", "CLBLM_L_X10Y248.SLICEM_X0.AFF.ZRST", "CLBLM_L_X10Y248.SLICEM_X0.NOCLKINV", "CLBLM_L_X10Y248.SLICEM_X0.SRUSEDMUX", "CLBLM_L_X10Y248.CLBLM_M_A1.CLBLM_IMUX7", "CLBLM_L_X10Y248.CLBLM_M_A3.CLBLM_IMUX1", "CLBLM_L_X10Y248.CLBLM_M_A4.CLBLM_IMUX11", "CLBLM_L_X10Y248.CLBLM_LOGIC_OUTS4.CLBLM_M_AQ", "CLBLM_L_X10Y248.CLBLM_M_CLK.CLBLM_CLK1"]; ; --- Words: the frame ------------------------------------------------------------------------ ; {name} is filled by tool.js from the data files or from the reader's paste; nothing else is. pub const SAY_TABS : [3]str = ["Decode", "Guess the gate", "Our design"]; pub const SAY_LOADING : str = "Reading the data files..."; pub const SAY_LOAD_FAILED : str = "A data file could not be read: {file}"; pub const SAY_LIMITS : str = "The names are this page's own: a LUT with no short name may still be a familiar gate with more inputs. The design is hand-written Verilog, not generated from t27."; ; --- Words: decode --------------------------------------------------------------------------- pub const SAY_INPUT_LABEL : str = "Paste a LUT6 INIT (64'h..., 64'b..., 0x..., or 16 hex digits) or FASM lines"; pub const SAY_INPUT_PLACEHOLDER : str = "64'h6996966996696996"; pub const SAY_DROP : str = "or drop a .fasm file here: it is read in this tab and sent nowhere"; pub const SAY_EXAMPLES : str = "Examples"; pub const SAY_EXAMPLE_NAMES : [8]str = ["XOR6", "AND6", "A1 only", "A6 only", "majority", "2:1 mux", "carry LUT, our design", "LUT and flip-flop, our design"]; pub const SAY_NOTHING : str = "Nothing to read yet: paste an INIT or a FASM LUT line."; pub const SAY_FILE_LUTS : str = "{name}: {n} LUT INIT lines. This is LUT {i} of {n}, {loc}."; pub const SAY_PREV : str = "Previous LUT"; pub const SAY_NEXT : str = "Next LUT"; pub const SAY_NAME_LABEL : str = "Recognised as"; pub const SAY_INPUTS_LABEL : str = "Inputs that matter"; pub const SAY_DONT_CARE : str = "don't-care"; pub const SAY_NONE : str = "none"; pub const SAY_EXPR_LABEL : str = "Minimal sum of products: {terms} terms, from the Quine-McCluskey in this page"; pub const SAY_EXPR_INEXACT : str = "The search ran out of its node budget: this cover is correct but may not be the smallest."; pub const SAY_EXPR_CHECK : str = "Checked: the expression gives the same 64 outputs as the INIT."; pub const SAY_OP_AND : str = "&"; pub const SAY_OP_OR : str = " | "; pub const SAY_OP_NOT : str = "~"; pub const SAY_PIN : str = "A{n}"; pub const SAY_CONST_0 : str = "0"; pub const SAY_CONST_1 : str = "1"; pub const SAY_INIT_LABEL : str = "INIT"; pub const SAY_FASM_REBUILT : str = "The FASM line for this INIT"; pub const SAY_LOC_ASSUMED : str = "The paste names no LUT, so the line uses {loc}, a real SLICEM LUT of our design."; pub const SAY_TABLE_LABEL : str = "Truth table: row i is input vector i, A1 the lowest bit. Tap a row to flip its output. Faded columns are don't-care."; pub const SAY_TABLE_HEAD : [3]str = ["i", "A6 A5 A4 A3 A2 A1", "O"]; pub const SAY_FLIPPED : str = "INIT[{i}] is now {v}. prjxray-db puts it at frame offset {frame}, bit {bit} of a {tt} tile, {site} {lut}LUT."; pub const SAY_RESET : str = "Undo my flips"; ; --- Words: the two LUT5 halves --------------------------------------------------------------- pub const SAY_HALVES_TITLE : str = "LUT5 halves: O5 and O6"; pub const SAY_HALVES_BODY : str = "A LUT6 is two LUT5s on A1-A5 and a 2:1 mux on A6 (UG474). INIT[31:0] is the A6 = 0 half and is also the O5 output. INIT[63:32] is the A6 = 1 half. With A6 tied high and O5 routed, one LUT gives two functions of the same five inputs."; pub const SAY_HALF_LOW : str = "INIT[31:0], A6 = 0, the O5 output"; pub const SAY_HALF_HIGH : str = "INIT[63:32], A6 = 1"; pub const SAY_HALVES_SAME : str = "Both halves are the same function: A6 is don't-care and this LUT needs only five inputs."; pub const SAY_HALVES_DIFF : str = "The halves differ: A6 picks between them."; pub const SAY_HALVES_DESIGN : str = "In our design {o5} of {luts} LUTs route O5 (node.fasm has no OUTMUX.O5, FFMUX.O5, 5FFMUX.IN_A or CARRY4 CY0 feature): every LUT there is used as one LUT6."; ; --- Words: FASM lines ------------------------------------------------------------------------- pub const SAY_FASM_TITLE : str = "FASM lines, read against prjxray-db"; pub const SAY_FASM_NONE : str = "No FASM lines in the paste."; pub const SAY_PART_NAMES : [5]str = ["tile", "site", "BEL", "feature", "value"]; pub const SAY_BITS : str = "config bits, as frame offset _ bit in the tile"; pub const SAY_BITS_INIT : str = "64 bits: INIT[00] at {first}, INIT[63] at {last}"; pub const SAY_BIT_NEG : str = "a bit written !x must be 0"; pub const SAY_TILE_CLBLL : str = "CLBLL: a logic tile with two SLICEL sites (LUTs, flip-flops, carry chain)."; pub const SAY_TILE_CLBLM : str = "CLBLM: a SLICEM site, whose LUTs can also be RAM or shift registers, and a SLICEL site."; pub const SAY_TILE_SIDE : str = "In this db the {a} and {b} tiles have the same feature names and the same bits."; pub const SAY_TILE_OTHER : str = "{tt} is not a CLB tile: this page ships only the CLBLL and CLBLM part of prjxray-db."; pub const SAY_TILE_NO_FEATURE : str = "{tt} has no feature {feature} in prjxray-db ab1fc60."; pub const SAY_F_LUT_INIT : str = "{L}LUT truth table: INIT[i] is the output for input vector i, A1 the lowest bit."; pub const SAY_F_LUT_RAM : str = "{L}LUT is distributed RAM (a RAM32, RAM64, RAM128 or RAM256 primitive), not logic."; pub const SAY_F_LUT_SMALL : str = "{L}LUT holds a smaller primitive (SRL16E or a RAM32 one), per the prjxray ram fuzzer."; pub const SAY_F_LUT_SRL : str = "{L}LUT is a shift register (SRL16E or SRLC32E)."; pub const SAY_F_DI1MUX : str = "{L}LUT RAM data input DI1 comes from {src}."; pub const SAY_F_ZINI : str = "{ff} starts at 0 after configuration (GSR). Without this bit a flip-flop starts at 1."; pub const SAY_F_ZRST : str = "{ff}: for FDRE and FDCE this bit makes reset store 0."; pub const SAY_F_5FFMUX_IN_A : str = "{ff} D input comes from the {L}LUT O5 output."; pub const SAY_F_5FFMUX_IN_B : str = "{ff} D input comes from the {L}X bypass pin."; pub const SAY_F_FFMUX : str = "{ff} D input comes from {src}."; pub const SAY_F_OUTMUX : str = "The {L}MUX site output carries {src}."; pub const SAY_F_CY0 : str = "CARRY4 stage {L} takes its DI from the {L}LUT O5. Without this bit it takes {L}X."; pub const SAY_F_PRECYINIT : str = "The first carry input of the CARRY4 is {src}."; pub const SAY_F_CEUSEDMUX : str = "Clock enable is a routed signal. Without this bit CE is always 1. Whole slice."; pub const SAY_F_SRUSEDMUX : str = "Set/reset is a routed signal. Without this bit the flip-flops are never reset. Whole slice."; pub const SAY_F_CLKINV : str = "The clock into the slice is inverted. Whole slice."; pub const SAY_F_NOCLKINV : str = "The clock into the slice is not inverted: NOCLKINV is the inverse of CLKINV, one bit that must be 0. Whole slice."; pub const SAY_F_FFSYNC : str = "Set/reset is synchronous (FDRE, FDSE). Without this bit it is asynchronous. Whole slice."; pub const SAY_F_LATCH : str = "The LUT6 storage elements are latches and the LUT5 ones cannot be used. Whole slice."; pub const SAY_F_WA7USED : str = "RAM address bit WA7 comes from the CX pin."; pub const SAY_F_WA8USED : str = "RAM address bit WA8 comes from the BX pin."; pub const SAY_F_WEMUX_CE : str = "RAM write enable comes from the CE pin instead of WE."; pub const SAY_F_UNKNOWN : str = "A {tt} feature this page has no words for."; pub const SAY_SRC_KEYS : [13]str = ["O6", "O5", "XOR", "CY", "F7", "F8", "NX", "N5Q", "MC31", "C0", "C1", "CIN", "NI"]; pub const SAY_SRC_WORDS : [13]str = ["the LUT6 output O6", "the LUT5 output O5", "the carry chain sum (CARRY4 XOR)", "the carry chain carry (CARRY4 CO)", "the F7 wide mux", "the F8 wide mux", "the {L}X bypass pin", "the {L}5FF output", "the shift-register cascade output MC31", "constant 0", "constant 1", "the carry in from the CLB below", "the {L}I data pin"]; pub const SAY_PIP_LUTPIN : str = "Input A{n} of the {site} {L}LUT comes from {src}."; pub const SAY_PIP_ALWAYS : str = "Always connected inside the tile (prjxray-db ppip 'always'): no config bits."; pub const SAY_PIP_HINT : str = "A path through the LUT from an input to its output (prjxray-db ppip 'hint'): no config bits."; pub const SAY_PIP_DEFAULT : str = "Connected when nothing else drives this wire (prjxray-db ppip 'default')."; pub const SAY_PIP_CLB : str = "Inside the CLB tile: wire {dst} from {src}."; pub const SAY_PIP_OTHER : str = "Routing pip: wire {dst} driven from {src}. Its bits are in the segbits of {tt}, which this page does not ship."; pub const SAY_BAD_LINE : str = "Not read: {line}"; ; --- Words: function names --------------------------------------------------------------------- ; {n} inputs matter, {k} of them inverted (or, for the XOR-with forms, {k} inputs enter only through ; the XOR), {inner} is the name of the rest. Keys in design.json are id/n/k. pub const SAY_CLASS_ZERO : str = "constant 0"; pub const SAY_CLASS_ONE : str = "constant 1"; pub const SAY_CLASS_BUF : str = "buffer: copies one input"; pub const SAY_CLASS_NOT : str = "inverter: NOT of one input"; pub const SAY_CLASS_AND : str = "AND{n}"; pub const SAY_CLASS_NAND : str = "NAND{n}"; pub const SAY_CLASS_OR : str = "OR{n}"; pub const SAY_CLASS_NOR : str = "NOR{n}"; pub const SAY_CLASS_ANDX : str = "AND{n} with {k} inverted"; pub const SAY_CLASS_ORX : str = "OR{n} with {k} inverted"; pub const SAY_CLASS_XOR : str = "XOR{n}: parity of {n} inputs"; pub const SAY_CLASS_XNOR : str = "XNOR{n}: inverted parity of {n}"; pub const SAY_CLASS_MAJ : str = "majority of 3"; pub const SAY_CLASS_MAJX : str = "majority of 3, {k} inverted"; pub const SAY_CLASS_CARRY2 : str = "2-bit carry out: MAJ(a, b, MAJ(c, d, e))"; pub const SAY_CLASS_CARRY2X : str = "2-bit carry out, {k} inverted"; pub const SAY_CLASS_MUX2 : str = "2:1 mux"; pub const SAY_CLASS_MUX4 : str = "4:1 mux"; pub const SAY_CLASS_XORWITH : str = "XOR of {k} inputs with ({inner})"; pub const SAY_CLASS_XNORWITH : str = "XNOR of {k} inputs with ({inner})"; pub const SAY_CLASS_OTHER : str = "no short name, {n} inputs"; pub const SAY_DETAIL_BUF : str = "The output is {pin}."; pub const SAY_DETAIL_NOT : str = "The output is NOT {pin}."; pub const SAY_DETAIL_MUX2 : str = "Select {s}: {d0} when {s} = 0, {d1} when {s} = 1."; pub const SAY_DETAIL_MUX4 : str = "Selects {s1} {s0}: data {d} for select values 0, 1, 2, 3."; pub const SAY_DETAIL_CARRY2 : str = "MAJ({a}, {b}, MAJ({c}, {d}, {e})): the carry out of a two-bit add."; pub const SAY_DETAIL_LINEAR : str = "{list} enter only through the XOR."; ; --- Words: the game --------------------------------------------------------------------------- pub const SAY_GAME_INTRO : str = "A real LUT from our routed design. Which function is it? The answer comes from this page's decoder."; pub const SAY_GAME_LOC : str = "{loc} in node.fasm"; pub const SAY_GAME_SCORE : str = "Round {round} of {rounds}. Score {right}."; pub const SAY_GAME_RIGHT : str = "Right."; pub const SAY_GAME_WRONG : str = "No: it is {answer}."; pub const SAY_GAME_NEXT : str = "Next LUT"; pub const SAY_GAME_OPEN : str = "Open it in the decoder"; pub const SAY_GAME_DONE : str = "{right} of {rounds} right."; pub const SAY_GAME_AGAIN : str = "Play again"; pub const SAY_GAME_SAMPLE : str = "Rounds come from {pool} INITs: at most {per} distinct ones per named function, so rare functions turn up as often as XOR2. The {other} LUTs with no short name are left out."; ; --- Words: our design ------------------------------------------------------------------------- pub const SAY_HIST_TITLE : str = "What the LUTs of one routed design are"; pub const SAY_HIST_INTRO : str = "{luts} LUT6 INIT lines in node.fasm ({distinct} distinct INITs), the TRI-NET node v2 for the AX7203 board ({part}). {named} have a short name in this decoder, {other} do not."; pub const SAY_HIST_REST : str = "{kinds} more named kinds"; pub const SAY_HIST_OURS : str = "our design"; pub const SAY_HIST_YOURS : str = "your file"; pub const SAY_FACT_PINS : str = "{agree} of {luts}: for every LUT the inputs its INIT depends on are exactly the A1-A6 pins the router connected. That is the A1 = bit 0 convention, checked on real data."; pub const SAY_FACT_O5 : str = "{o5} LUTs route O5 and {ram} are RAM or shift registers: every LUT here is plain logic used as one LUT6."; pub const SAY_FACT_QM : str = "Quine-McCluskey finds the proven minimum for all but {inexact} of them. The longest cover has {terms} terms."; pub const SAY_FACT_TOOLS : str = "Built with {yosys}: {ycmd}. Placed and routed with {nextpnr}. Read with prjxray {prjxray} and {db}."; pub const SAY_YOUR_FILE : str = "Your file {name}: {luts} LUTs, {named} with a short name. Read in this tab only."; ; --- Tests ------------------------------------------------------------------------------------- ; INIT[i] is the output for input vector i, I0 = A1 the least significant bit. If the output is A1, ; every odd row is 1 and every even row 0 (0xAAAA in each word). If the output is A6, rows 0..31 ; are 0 and rows 32..63 are 1: INIT[31] is bit 15 of word 1, INIT[32] bit 0 of word 2. test bit_index_convention_i0_is_the_lsb { assert K_A1_WORDS[0] % 2 == 0; assert 1 == (K_A1_WORDS[0] / 2) % 2; assert 1 == (K_A1_WORDS[3] / 32768) % 2; assert K_A1_WORDS[0] == 43690; assert K_A1_WORDS[1] == K_A1_WORDS[0]; assert K_A1_WORDS[3] == K_A1_WORDS[0]; assert 0 == (K_A6_WORDS[1] / 32768) % 2; assert K_A6_WORDS[2] % 2 == 1; assert K_A6_WORDS[0] + K_A6_WORDS[1] == 0; assert K_A6_WORDS[2] == 65535; assert K_A6_WORDS[3] == 65535; assert 31 / 16 == 1; assert 32 / 16 == 2; } ; 64'h6996966996696996 is XOR6. Nibble 0 of word 0 is rows 0..3 (A1, A2 vary): 6 = 0110, the parity ; of A1 and A2. A3 = 1 (nibble 1) and A4 = 1 (nibble 2) invert it, both together (nibble 3) do not. ; A5 = 1 (word 1) and A6 = 1 (word 2) invert the whole word, both together (word 3) do not. test init_6996966996696996_is_xor6_the_parity_of_six_inputs { assert K_XOR6_WORDS[0] % 16 == 6; assert 6 % 2 == 0; assert 1 == (6 / 2) % 2; assert 1 == (6 / 4) % 2; assert 0 == (6 / 8) % 2; assert 15 - 6 == (K_XOR6_WORDS[0] / 16) % 16; assert 15 - 6 == (K_XOR6_WORDS[0] / 256) % 16; assert K_XOR6_WORDS[0] / 4096 == 6; assert K_XOR6_WORDS[1] == 65535 - K_XOR6_WORDS[0]; assert K_XOR6_WORDS[2] == 65535 - K_XOR6_WORDS[0]; assert K_XOR6_WORDS[3] == K_XOR6_WORDS[0]; assert K_EXAMPLE_INITS[0] == "6996966996696996"; assert K_EXAMPLE_CLASSES[0] == "xor/6/0"; assert K_EXAMPLE_N[0] == K_N_INPUTS; } ; 64'h8000000000000000 is AND6: one 1, at bit 15 of word 3, which is INIT[63], the row where all ; six inputs are 1. test init_8000000000000000_is_and6 { assert K_AND6_WORDS[0] + K_AND6_WORDS[1] + K_AND6_WORDS[2] == 0; assert K_AND6_WORDS[3] == 32768; assert 3 * 16 + 15 == K_N_BITS - 1; assert K_N_BITS - 1 == 32 + 16 + 8 + 4 + 2 + 1; assert K_EXAMPLE_INITS[1] == "8000000000000000"; assert K_EXAMPLE_CLASSES[1] == "and/6/0"; assert K_EXAMPLE_N[1] == 6; } test the_design_numbers_add_up { assert K_DESIGN_NAMED + K_DESIGN_OTHER == K_DESIGN_LUTS; assert K_DESIGN_PINS_AGREE == K_DESIGN_LUTS; assert K_DESIGN_XOR_FAMILY <= K_DESIGN_NAMED; assert K_DESIGN_TOP_COUNT <= K_DESIGN_XOR_FAMILY; assert K_DESIGN_DISTINCT <= K_DESIGN_LUTS; assert K_DESIGN_O5_USED == 0; assert K_DESIGN_ROUNDS >= K_GAME_ROUNDS; assert K_GAME_CHOICES == 4; } test the_page_sends_nothing { assert SENDS_NOTHING == true; assert READS_LOCAL_FILES == true; assert K_DATA_DESIGN == "./design.json"; assert K_DATA_PRJXRAY == "./prjxray.json"; assert CATEGORY == "fpga"; }