// SPDX-License-Identifier: Apache-2.0 ; specs/widgets/csa-tree.t27 -- carry-save trees: k numbers squeezed to two by 3:2 counters, then one adder ; Source of truth for public/widgets/csa-tree/ (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 and NO FORMULA of ; its own: every value it draws comes from public/widgets/csa-tree/logic.js -- the fn bodies of ; gHashTag/t27 specs/fpga/dsp/adders.t27 (t27#8985) compiled to wasm, beside its copy logic.t27. ; Lesson 3 of the course arithmetic-and-dsp. ASCII only (L3), English only (LANG-EN). ; WHAT IT DOES: the reader sets how many numbers to add (3 to 64) and their width, and sees the rows ; shrink layer by layer through 3:2 counters (the Wallace reduction) under the Dadda heights, then one ; carry-propagate adder; tiles give the layers, the full adders and the delay against a chain of adders. ; Below, one 3:2 counter on three 8-bit numbers: a sum word and a carry word whose sum is a + b + c. ; WHAT IT DOES NOT CLAIM: the delay counts full-adder delays and assumes no overlap between chained adders; wiring is not modelled. ; phi^2 + 1/phi^2 = 3 | TRINITY module widget_csa_tree; pub const KIND : str = "widget-tool"; pub const ID : str = "csa-tree"; pub const TITLE : str = "Carry-save adders: add many numbers with almost no carries"; pub const DESCRIPTION : str = "Set how many numbers to add and watch 3:2 counters squeeze them to two, layer by layer, before a single carry-propagate adder. Then try one counter on three numbers."; pub const IMAGE_ALT : str = "Carry-save tree card: 9 operands of 16 bits reduce to 6, 4, 3 and 2 rows in 4 layers of 3:2 counters under the Dadda heights 6, 4, 3, 2, then one adder: 20 full-adder delays against 128 for a chain of adders."; pub const HOOK : str = "Nine numbers, four layers of full adders and one carry chain at the end: why multipliers never add their rows one by one."; pub const CATEGORY : str = "fpga"; pub const DATA_SOURCES : [3]str = ["gHashTag/t27 specs/fpga/dsp/adders.t27 (t27#8985): every value on the page is its fn bodies, compiled to wasm (logic.js)", "L. Dadda, Some schemes for parallel multipliers, Alta Frequenza 34, 1965: heights 2, 3, 4, 6, 9, 13, 19, 28, 42, 63", "C. S. Wallace, A suggestion for a fast multiplier, IEEE Trans. Electronic Computers EC-13, 1964"]; pub const READS_LOCAL_FILES : bool = false; pub const SENDS_NOTHING : bool = true; pub const K_CARD_WIDTH : u16 = 1200; pub const K_CARD_HEIGHT : u16 = 630; ; --- Numbers: ranges, presets, and the logic spec's own constants (held equal by widget-logic.mjs) pub const K_MIN_OPERANDS : u8 = 3; pub const K_MAX_OPERANDS : u8 = 64; pub const K_MIN_BITS : u8 = 4; pub const K_MAX_BITS : u8 = 32; pub const K_DEMO_MAX : u16 = 255; pub const K_DADDA_FIRST : u16 = 2; pub const K_PRESET_OPERANDS : [4]u8 = [3, 9, 28, 64]; pub const K_PRESET_BITS : [4]u8 = [8, 16, 16, 32]; pub const K_PRESET_A : [4]u16 = [11, 200, 255, 170]; pub const K_PRESET_B : [4]u16 = [6, 100, 255, 85]; pub const K_PRESET_C : [4]u16 = [13, 50, 255, 255]; pub const K_START_PRESET : u8 = 1; ; --- Words on screen ------------------------------------------------------------------------ pub const SAY_PRESETS_LABEL : str = "Start from"; pub const SAY_PRESET_NAMES : [4]str = ["3 numbers: one layer", "9 numbers: four layers", "28 numbers: a Dadda height", "64 numbers: ten layers"]; pub const SAY_OPERANDS : str = "Numbers to add"; pub const SAY_BITS : str = "Width, bits"; pub const SAY_A : str = "a"; pub const SAY_B : str = "b"; pub const SAY_C : str = "c"; pub const SAY_TREE_LABEL : str = "Rows left after each layer of 3:2 counters, then one carry-propagate adder"; pub const SAY_COUNTER_LABEL : str = "One 3:2 counter on three numbers: the sum word and the carry word"; pub const SAY_INPUT : str = "input"; pub const SAY_LAYER : str = "layer {0}"; pub const SAY_DADDA : str = "at most {0}"; pub const SAY_CPA : str = "adder"; pub const SAY_ONE_CARRY : str = "carries here"; pub const SAY_LEVELS : str = "layers of 3:2"; pub const SAY_ADDERS : str = "full adders"; pub const SAY_TREE_DELAY : str = "tree + one adder"; pub const SAY_CHAIN_DELAY : str = "chain of adders"; pub const SAY_FA : str = "{0} FA delays"; pub const SAY_COUNTER_NOTE : str = "One 3:2 counter: a full adder per bit, each bit on its own. The sum word is the XOR, the carry word the majority moved up a bit."; pub const SAY_SUM_WORD : str = "sum"; pub const SAY_CARRY_WORD : str = "carry"; pub const SAY_TOTAL : str = "sum {0} + carry {1} = {2} = a + b + c"; pub const SAY_SOURCE : str = "Logic: t27 spec fpga/dsp/adders.t27, compiled"; test the_card_is_the_share_size { assert K_CARD_WIDTH == 1200; assert K_CARD_HEIGHT == 630; assert K_CARD_WIDTH * 21 == K_CARD_HEIGHT * 40; } test the_presets_sit_on_dadda_heights { assert K_PRESET_OPERANDS[0] == 3; assert K_PRESET_OPERANDS[1] == 9; assert K_PRESET_OPERANDS[2] == 28; assert K_PRESET_OPERANDS[3] == K_MAX_OPERANDS; } test the_demo_fits_eight_bits { assert K_DEMO_MAX == 255; assert K_PRESET_A[2] <= K_DEMO_MAX; assert K_DADDA_FIRST == 2; assert K_MIN_OPERANDS == K_DADDA_FIRST + 1; }