// SPDX-License-Identifier: Apache-2.0 ; specs/widgets/uart-bucket.t27 -- the bucket under the tap: answers waiting in a 512-byte UART buffer ; Source of truth for public/widgets/uart-bucket/ (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 the buffer rule is K_ constants. ; ASCII only (L3), English only (LANG-EN). ; WHAT IT SHOWS: the Mac keeps a window of requests in flight to the AX7203 node; every answer the ; node sends back is 19 bytes and passes through a CP2102N USB-UART bridge with a 512-byte receive ; buffer. The node has no flow control, so while the Mac pauses reading, up to window x 19 bytes of ; answers wait in that buffer. The reader drags the window and the bucket fills; past 512 bytes it ; spills. Below it, the measured runs: two 2,016,000-job diagnostic arms (window 64 and window 24) ; and two single 403,200-job runs at the edge (window 26 and window 30), then what the link carried. ; WHERE THE NUMBERS COME FROM: scripts/widget-data/uart-bucket.mjs reads the record files of ; gHashTag/trinity-fpga with git show at the commits named in DATA_SOURCES, parses every number, ; checks the K_ constants below against the diagnostic's own spec, and writes data.json; the page ; reads only that file. scripts/widget-data/uart-bucket-card.py draws card.png from data.json. ; WHAT IT DOES NOT CLAIM: that the buffer is the cause. The diagnostic's own record says the pattern ; fits the buffer and that nothing proves it. One USB path, one host, one evening. The model run ; below used synthetic activation vectors; no text came out of it, and text generation ran on the Mac. ; phi^2 + 1/phi^2 = 3 | TRINITY module widget_uart_bucket; pub const KIND : str = "widget-tool"; pub const ID : str = "uart-bucket"; pub const TITLE : str = "The bucket under the tap: a 512-byte UART buffer and 19-byte answers"; pub const DESCRIPTION : str = "Drag the number of requests in flight and watch the answers fill a CP2102N's 512-byte receive buffer, then read the measured runs on the AX7203 board."; pub const IMAGE_ALT : str = "The bucket under the tap card: a CP2102N receive buffer holds 512 bytes and each answer is 19 bytes, so 26 answers fit. Window 64 (1216 bytes in flight) lost 574 of 2016000 answers in 424.3 s; window 24 (456 bytes) lost 0 in 427.5 s, on the AX7203 board."; pub const HOOK : str = "512 bytes of buffer, 19 bytes per answer: 26 fit. Window 64 lost 574 answers in 2,016,000 jobs; window 24 lost none and took the same time."; pub const CATEGORY : str = "fpga"; pub const DATA_SOURCES : [5]str = ["gHashTag/trinity-fpga conformance/UART_LOSS_DIAG.md at commit 5a3111806: the window-64 and window-24 diagnostic arms (2,016,000 jobs each), the 512 / 19 rule, the wire time of the requests and the caveat", "gHashTag/trinity-fpga specs/trinet/uart_loss_diag_ax7203.t27 at commit df78b3249: REQ_LEN, RESP_LEN, CP2102N_RX_BYTES, ARM_WINDOWS and JOBS_PER_PASS, checked against the K_ constants of this spec", "gHashTag/trinity-fpga conformance/TERN_TC_LAYER_RECEIPTS.md at commit e1834ee6e: the --all runs at window 24 (rerun step 1), window 26 and window 30 (rerun step 3), harness tern_tc_layer_ax7203.py", "gHashTag/trinity-fpga conformance/TERN_TC_GENERATE.md at commit b2bd5a30c: the layer run used synthetic activation vectors and generation ran on the Mac", "scripts/widget-data/uart-bucket.mjs parses those files with git show at those commits into public/widgets/uart-bucket/data.json; scripts/widget-data/uart-bucket-card.py draws card.png from it"]; pub const READS_LOCAL_FILES : bool = false; pub const SENDS_NOTHING : bool = true; ; --- The rule -------------------------------------------------------------------------------- ; The buffer and the frame sizes; uart-bucket.mjs fails if they drift from the diagnostic's spec. pub const K_RX_BYTES : u16 = 512; pub const K_ANSWER_BYTES : u16 = 19; pub const K_REQUEST_BYTES : u16 = 24; pub const K_LARGEST_FIT : u16 = 26; ; The two diagnostic arms and the two single runs at the edge. pub const K_ARM_WINDOWS : [2]u16 = [64, 24]; pub const K_EDGE_WINDOWS : [2]u16 = [26, 30]; ; The slider. pub const K_WINDOW_MIN : u16 = 1; pub const K_WINDOW_MAX : u16 = 64; pub const K_WINDOW_START : u16 = 64; ; One fill-and-drain cycle of the animation, in milliseconds; none when the reader asks for less motion. pub const K_CYCLE_MS : u16 = 3600; pub const K_DATA_FILE : str = "./data.json"; ; --- Words ----------------------------------------------------------------------------------- ; {name} is filled by tool.js from data.json or from the K_ constants; nothing else is. pub const SAY_LOADING : str = "Reading the measured runs..."; pub const SAY_LOAD_FAILED : str = "The data file could not be read."; pub const SAY_INTRO : str = "The Mac keeps a window of requests in flight to the {board} node. Every answer coming back is {answer} bytes. While the Mac pauses reading, answers wait in the USB-UART bridge's {rx}-byte receive buffer; the node has no flow control, so nothing tells it to wait."; pub const SAY_TAP : str = "node answers, {answer} B each"; pub const SAY_BUCKET : str = "CP2102N receive buffer"; pub const SAY_BRIM : str = "{rx} B"; pub const SAY_DRAIN : str = "the Mac reads"; pub const SAY_SPILL : str = "lost"; pub const SAY_WINDOW_LABEL : str = "Requests in flight (window)"; pub const SAY_FEWER : str = "One request fewer"; pub const SAY_MORE : str = "One request more"; pub const SAY_MINUS : str = "-"; pub const SAY_PLUS : str = "+"; pub const SAY_READOUT : str = "{w} x {answer} B = {bytes} B of answers can be waiting; the buffer holds {rx} B."; pub const SAY_FITS : str = "Fits, {spare} B to spare, however long the Mac pauses."; pub const SAY_OVER : str = "Over by {over} B: if the Mac pauses long enough, answer bytes are lost."; pub const SAY_RULE : str = "{rx} / {answer} = {ratio}, so {fit} is the largest window that fits."; pub const SAY_MOTION_OFF : str = "Animation off: your system asks for reduced motion. The bucket shows the full level."; pub const SAY_RUNS_TITLE : str = "Measured on the {board}: {jobs} jobs per arm, one arm each"; pub const SAY_ARM_HEAD : str = "window {w}"; pub const SAY_ARM_ROWS : [6]str = ["bytes in flight", "jobs sent", "answers accepted", "answers lost", "loss events", "elapsed"]; pub const SAY_SECONDS : str = "s"; pub const SAY_SHOW : str = "Put window {w} in the bucket"; pub const SAY_SAME_TIME : str = "The smaller window cost no time: {t64} s against {t24} s. The requests are the slow direction: {req} B x 10 bit at {baud} baud x {jobs} jobs = {wire} s on the wire."; pub const SAY_EDGE_TITLE : str = "Two single runs at the edge, {planned} jobs planned each"; pub const SAY_EDGE_PASS : str = "window {w} ({bytes} B): {ok} of {planned} receipts verified, no slip"; pub const SAY_EDGE_FAIL : str = "window {w} ({bytes} B): stopped at the first slip after {sent} jobs sent; {ok} of {planned} receipts verified"; pub const SAY_CAVEAT : str = "What this does not show: the diagnostic's own record says the pattern fits the buffer, but nothing proves the buffer is the cause. One USB path (a Genesys hub), one host, one evening; nothing about other hosts or a hub-free path."; pub const SAY_CARRIED_TITLE : str = "What the link then carried, at window {w}"; pub const SAY_CARRIED_LINE : str = "The {board} board multiplied every ternary matrix of a small language model (igla-coder, tern_tc). Every answer carried a signed receipt, checked by the Mac."; pub const SAY_CARRIED_ROWS : [6]str = ["ternary matrices", "rows", "ternary weights", "receipts verified", "rows bit-exact", "elapsed"]; pub const SAY_RATE : str = "{rate} answers/s"; pub const SAY_CARRIED_PLAIN : str = "Plainly: the inputs were synthetic test vectors and no text came out of this run. Text generation ran on the Mac. Even in later generation runs, the Mac does everything except the ternary dot products."; pub const SAY_SOURCES : str = "Every number on this page is parsed from these files in gHashTag/trinity-fpga:"; pub const SAY_AT : str = "at"; ; --- Tests ----------------------------------------------------------------------------------- test twenty_six_answers_fit { assert K_RX_BYTES / K_ANSWER_BYTES == K_LARGEST_FIT; assert K_LARGEST_FIT * K_ANSWER_BYTES <= K_RX_BYTES; assert K_ANSWER_BYTES * (K_LARGEST_FIT + 1) > K_RX_BYTES; assert K_LARGEST_FIT * K_ANSWER_BYTES == 494; } test the_two_arms_sit_either_side_of_the_buffer { assert K_ARM_WINDOWS[1] * K_ANSWER_BYTES <= K_RX_BYTES; assert K_RX_BYTES < K_ARM_WINDOWS[0] * K_ANSWER_BYTES; assert K_ARM_WINDOWS[0] * K_ANSWER_BYTES == 1216; assert K_ARM_WINDOWS[1] * K_ANSWER_BYTES == 456; } test the_edge_runs_bracket_the_buffer { assert K_EDGE_WINDOWS[0] == K_LARGEST_FIT; assert K_EDGE_WINDOWS[0] * K_ANSWER_BYTES <= K_RX_BYTES; assert K_EDGE_WINDOWS[1] * K_ANSWER_BYTES > K_RX_BYTES; assert K_EDGE_WINDOWS[1] * K_ANSWER_BYTES == 570; } test the_slider_reaches_every_measured_window { assert K_WINDOW_MIN == 1; assert K_WINDOW_MAX >= K_ARM_WINDOWS[0]; assert K_WINDOW_MIN <= K_ARM_WINDOWS[1]; assert K_WINDOW_START <= K_WINDOW_MAX; assert K_REQUEST_BYTES > K_ANSWER_BYTES; } test the_page_sends_nothing { assert SENDS_NOTHING == true; assert READS_LOCAL_FILES == false; assert K_DATA_FILE == "./data.json"; assert CATEGORY == "fpga"; }