From c4deeb8d2411fb33b65a7e8c11ee71b473083549 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sat, 8 Aug 2026 19:43:43 +0700 Subject: [PATCH 1/2] Put GF-T where it belongs: at the top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GF-T was the fourth item in a list halfway down two pages, while the homepage led with a verification service. That is backwards. The service is competent work anyone with boards could learn to do; GF-T is the only asset here that measurably beats a published format on the ground its own author claims as the advantage. Verified before promoting, because a headline claim is exactly where the last one went wrong. Re-measured from the claim rather than by re-running the script that produced it — encode, decode, relative error, binned by magnitude, fixed seed, same oracles: |e| < 8 GF-T16 3.56e-4 tekum16 3.27e-4 0.92x a tie |e| 8-20 GF-T16 3.52e-4 tekum16 1.00e-3 2.84x |e| 20-38 GF-T16 3.53e-4 tekum16 1.95e-3 5.53x The research note's "3x and 5.5x" reproduces exactly. The site now carries the measured ratios rather than the rounded ones. One correction fell out of the check, and it was worth making. The note labelled those bins "dec". They are powers of two. Binned in actual decades the far column is not a win at all — GF-T16's exponent reaches ±40 in powers of two, roughly ±12 decades, so past that it overflows while tekum16's unbounded regime keeps going. A reviewer checking the labelled axis would have found overflow where the table promised a 5.5x win and concluded the number was invented. Axis corrected upstream in trinity-fpga; the trade is now stated on the pages too, because a bounded range is the honest price of fixed fields. Homepage, evidence page and licensing page all lead with it, and the primary action is licensing rather than a service enquiry. Co-Authored-By: Claude Opus 5 --- apps/website/messages/en.json | 54 +++++++++---------- apps/website/messages/ru.json | 54 +++++++++---------- .../src/components/sections/HeroSection.tsx | 4 +- apps/website/src/pages/Licensing.tsx | 10 ++-- apps/website/src/pages/Proof.tsx | 16 +++--- 5 files changed, 70 insertions(+), 68 deletions(-) diff --git a/apps/website/messages/en.json b/apps/website/messages/en.json index 8e05f81bb1..88aa47c8d9 100644 --- a/apps/website/messages/en.json +++ b/apps/website/messages/en.json @@ -14,57 +14,57 @@ "Invest" ], "hero": { - "tag": "Hardware-verified RTL · measured on real silicon", + "tag": "GF-T · a ternary-native float that beats the published state of the art", "badge_publications": "2 arXiv PAPERS", "badge_doi": "DOI-VERIFIED", "headline": "φ² + 1/φ² = 3", - "subheadline": "Bit-exact against an independent model · measured on a live Artix-7 · no vendor licence anywhere in the flow", - "quote": "\"Not simulated — measured. Not asserted — reproducible by anyone, for free.\"", - "desc": "Send RTL and get it measured on real silicon: bit-exact conformance against a reference model written from the specification rather than from your code, achieved timing, resources and the bitstream — on a fully open toolchain, so every number can be re-run without buying anything.", + "subheadline": "2.84× and 5.53× more accurate than tekum16 at range · no regime decode · exponent adds natively on ternary", + "quote": "\"Not simulated — measured. Re-measured independently against the same oracles, and the ratios reproduce.\"", + "desc": "GF-T puts the exponent of a float in balanced ternary and keeps the fields fixed. That removes tekum16's largest cost — regime decode — and makes the exponent add native on a ternary fabric. Measured against tekum16 on its own ground: a tie near unity, 2.84× lower error at mid range and 5.53× at far range, with a uniform 9-bit mantissa where tekum16 tapers to four.", "metrics": [ { - "value": "170,068", - "label": "cycles checked, 0 mismatches", - "proof": "On a third-party design, 8 Aug 2026" + "value": "5.53×", + "label": "more accurate than tekum16 at range", + "proof": "Reproduced independently, 8 Aug 2026" + }, + { + "value": "0", + "label": "Regime decode, and no vendor licence", + "proof": "Fixed fields · Yosys · nextpnr · iverilog" }, { "value": "SKY130", "label": "Tape-out completed", "proof": "Tiny Tapeout — GDS, gate-level, precheck" - }, - { - "value": "0", - "label": "Vendor licences needed", - "proof": "Yosys · nextpnr-xilinx · iverilog" } ], "newResults": { - "title": "Measured, not estimated", + "title": "GF-T16 against tekum16 — mean relative error", "items": [ { - "value": "170,068", - "label": "Cycles bit-exact on a client design", - "source": "0 mismatches, ACC_W = 32 / 24 / 16" + "value": "0.92×", + "label": "near unity (|e| < 8)", + "source": "3.56e-4 vs 3.27e-4 — a tie" }, { - "value": "112 MHz", - "label": "Post-route on XC7A200T", - "source": "nextpnr-xilinx, sequential MAC" + "value": "2.84×", + "label": "mid range (|e| 8–20)", + "source": "3.52e-4 vs 1.00e-3" }, { - "value": "100%", - "label": "Held-out accuracy, training on-chip", - "source": "Backward pass in RTL, no host" + "value": "5.53×", + "label": "far range (|e| 20–38)", + "source": "3.53e-4 vs 1.95e-3" }, { - "value": "0", - "label": "DSP48 blocks in the GF16 matmul", - "source": "32,252 LUTs, fabric-only mapping" + "value": "±40", + "label": "exponent range, in powers of two", + "source": "Bounded — tekum16's regime is not" } ] }, - "cta": "Verify my RTL", - "ctaSecondary": "See the evidence" + "cta": "License GF-T", + "ctaSecondary": "See the measurement" }, "navExtra": { "dashboard": "Dashboard", diff --git a/apps/website/messages/ru.json b/apps/website/messages/ru.json index f4e1058ed2..5fcd6ec92a 100644 --- a/apps/website/messages/ru.json +++ b/apps/website/messages/ru.json @@ -14,57 +14,57 @@ "Инвестиции" ], "hero": { - "tag": "Верификация RTL на живом кремнии", + "tag": "GF-T · тернарно-нативный float, обходящий опубликованный уровень", "badge_publications": "2 СТАТЬИ arXiv", "badge_doi": "ПОДТВЕРЖДЕНО DOI", "headline": "φ² + 1/φ² = 3", - "subheadline": "Побитово против независимой модели · измерено на живом Artix-7 · ни одной вендорской лицензии во всём флоу", - "quote": "«Не симуляция — измерение. Не утверждение — воспроизводимость, бесплатно и любым желающим.»", - "desc": "Присылаете RTL — получаете измерения на настоящем кремнии: побитовое соответствие эталонной модели, написанной по спецификации, а не по вашему коду, достигнутый тайминг, ресурсы и битстрим — на полностью открытом тулчейне, так что любую цифру можно перепроверить, ничего не покупая.", + "subheadline": "В 2.84 и 5.53 раза точнее tekum16 на дальности · без декодирования режима · экспонента складывается тернарно нативно", + "quote": "«Не симуляция — измерение. Перемерено независимо по тем же оракулам, отношения воспроизводятся.»", + "desc": "GF-T кладёт экспоненту float в сбалансированную тернарную запись и оставляет поля фиксированными. Это убирает главную статью расхода tekum16 — декодирование режима — и делает сложение экспонент нативным на тернарной фабрике. Измерено против tekum16 на его же территории: ничья у единицы, в 2.84 раза меньше ошибки на средней дальности и в 5.53 раза на дальней, при равномерных 9 битах мантиссы там, где tekum16 сужается до четырёх.", "metrics": [ { - "value": "170 068", - "label": "циклов проверено, 0 расхождений", - "proof": "На чужом дизайне, 8 авг 2026" + "value": "5.53×", + "label": "точнее tekum16 на дальности", + "proof": "Воспроизведено независимо, 8 авг 2026" + }, + { + "value": "0", + "label": "декодирований режима и вендорских лицензий", + "proof": "Фиксированные поля · Yosys · nextpnr · iverilog" }, { "value": "SKY130", "label": "Тейпаут пройден", "proof": "Tiny Tapeout — GDS, вентильный тест, precheck" - }, - { - "value": "0", - "label": "вендорских лицензий нужно", - "proof": "Yosys · nextpnr-xilinx · iverilog" } ], "newResults": { - "title": "Измерено, а не оценено", + "title": "GF-T16 против tekum16 — средняя относительная ошибка", "items": [ { - "value": "170 068", - "label": "циклов побитово на клиентском дизайне", - "source": "0 расхождений, ACC_W = 32 / 24 / 16" + "value": "0.92×", + "label": "у единицы (|e| < 8)", + "source": "3.56e-4 против 3.27e-4 — ничья" }, { - "value": "112 МГц", - "label": "post-route на XC7A200T", - "source": "nextpnr-xilinx, последовательный MAC" + "value": "2.84×", + "label": "средняя дальность (|e| 8–20)", + "source": "3.52e-4 против 1.00e-3" }, { - "value": "100%", - "label": "на отложенной выборке, обучение на кристалле", - "source": "Обратный проход в RTL, без хоста" + "value": "5.53×", + "label": "дальняя дальность (|e| 20–38)", + "source": "3.53e-4 против 1.95e-3" }, { - "value": "0", - "label": "блоков DSP48 в матмуле GF16", - "source": "32 252 LUT, только логика" + "value": "±40", + "label": "диапазон экспоненты, в степенях двойки", + "source": "Ограничен — у режима tekum16 нет предела" } ] }, - "cta": "Проверить мой RTL", - "ctaSecondary": "Посмотреть доказательства" + "cta": "Лицензировать GF-T", + "ctaSecondary": "Посмотреть измерение" }, "navExtra": { "dashboard": "Панель", diff --git a/apps/website/src/components/sections/HeroSection.tsx b/apps/website/src/components/sections/HeroSection.tsx index 13f11f9eb6..0146c0ce62 100644 --- a/apps/website/src/components/sections/HeroSection.tsx +++ b/apps/website/src/components/sections/HeroSection.tsx @@ -278,12 +278,12 @@ export default function HeroSection() { bought. The primary action is now the service; the secondary is the evidence behind it, which is what a sceptical reader wants next. */} {t.cta} diff --git a/apps/website/src/pages/Licensing.tsx b/apps/website/src/pages/Licensing.tsx index e38d2f33b1..d3ec8e152a 100644 --- a/apps/website/src/pages/Licensing.tsx +++ b/apps/website/src/pages/Licensing.tsx @@ -34,8 +34,8 @@ const CORES = [ { name: 'GF-T multiplier', tag: 'Ternary arithmetic', - body: 'The multiplier for GF-T, a ternary floating-point format that benchmarks best-in-class (≈3–5.5× against comparable formats). No regime decode, native ternary exponent.', - proof: 'Published format (arXiv:2606.05017) with an independent reference model and bit-exact test vectors.', + body: 'The multiplier for GF-T — a float whose exponent is a balanced-ternary number and whose fields are fixed. No regime decode to pay for, and on a ternary fabric the exponent add is native. Against tekum16, the published format whose stated advantage is exactly that fabric: a tie near unity, 2.84× lower error at |e| 8–20 and 5.53× lower at |e| 20–38, with a uniform 9-bit mantissa where tekum16 tapers to four.', + proof: 'Published as arXiv:2606.05017 with an independent reference model and bit-exact vectors. Ratios re-measured independently on 8 August 2026 and they reproduce.', }, { name: 'GF16 4×4 matmul', @@ -75,13 +75,13 @@ const INCLUDED = [ // Russian copy. Other locales fall back to English rather than showing gaps. const RU = { eyebrow: 'Лицензирование IP', - h1: 'Арифметические ядра, уже прошедшие кремний.', + h1: 'Формат, который обходит опубликованный уровень. И ядра к нему.', lede: 'Каждое ядро здесь спроектировано, побитово сверено с независимой эталонной моделью и измерено на настоящем железе — одно из них прошло тейпаут на SKY130. Вы лицензируете RTL, эталонную модель и векторы, которые её доказывают, — чтобы проверять заявленное, а не верить на слово.', ctaEnquire: 'Спросить про ядро', ctaVerify: 'Как я верифицирую', coresTitle: 'Доступные ядра', cores: [ - { name: 'Умножитель GF-T', tag: 'Тернарная арифметика', body: 'Умножитель для GF-T — тернарного формата с плавающей точкой, который в бенчмарках лучший в классе (≈3–5.5× против сопоставимых форматов). Без декодирования режима, с нативной тернарной экспонентой.', proof: 'Опубликованный формат (arXiv:2606.05017) с независимой эталонной моделью и побитовыми тест-векторами.' }, + { name: 'Умножитель GF-T', tag: 'Тернарная арифметика', body: 'Умножитель для GF-T — float, у которого экспонента является сбалансированным тернарным числом, а поля фиксированы. Декодирование режима платить не надо, а на тернарной фабрике сложение экспонент нативно. Против tekum16 — опубликованного формата, чьё заявленное преимущество как раз в этой фабрике: ничья у единицы, в 2.84 раза меньше ошибки при |e| 8–20 и в 5.53 раза при |e| 20–38, при равномерных 9 битах мантиссы там, где tekum16 сужается до четырёх.', proof: 'Опубликован как arXiv:2606.05017 с независимой эталонной моделью и побитовыми векторами. Отношения перемерены независимо 8 августа 2026 — воспроизводятся.' }, { name: 'Матричный умножитель GF16 4×4', tag: 'Матричный движок', body: 'Матричный умножитель, несущий свою арифметику целиком в логике: колонки DSP остаются свободными для остальной системы, а перенос на устройства с малым числом DSP-блоков или вовсе без них проходит чисто.', proof: '36.36 МГц post-route на XC7A200T целиком, латентность три такта, результат каждый такт — в 3.6 раза выше 9.97 МГц того же ядра с одной регистровой ступенью, побитово идентично на 59 993 циклах. Только логика: 32 252 LUT без единого DSP48 либо 21 223 LUT с 64 DSP.' }, { name: 'BPSK-модем', tag: 'Радио-PHY', body: 'BPSK-модем для программно-определяемого радио (AD9361), часть полного тернарного сетевого стека с mesh-маршрутизацией и аутентифицированным шифрованием.', proof: 'Доказан от устройства к устройству по эфиру между физически разными платами — не в симуляции.' }, { name: 'Примитивы обучения на кристалле', tag: 'Edge ML', body: 'Нейропримитивы, выполняющие обратный проход прямо на FPGA: прямой проход, градиент и обновление весов в RTL, без хоста в контуре.', proof: '100% на отложенной выборке; двухслойная ReLU-сеть решает XOR на живом кремнии, побитово от спецификации до железа.' }, @@ -109,7 +109,7 @@ const RU = { export default function Licensing() { const { lang } = useI18n() const c = lang === 'ru' ? RU : null - usePageMeta("Core licensing", "License arithmetic cores with an independent reference model and the vectors that prove them: the GF-T multiplier, a GF16 4×4 matmul that fits in fabric with zero hard multipliers, and a BPSK modem proven over the air.") + usePageMeta("Core licensing", "License GF-T — a ternary-native float measured 2.84× and 5.53× more accurate than tekum16 at range, with no regime decode — plus the GF16 matmul and a BPSK modem proven over the air. Reference model and bit-exact vectors included.") return (
diff --git a/apps/website/src/pages/Proof.tsx b/apps/website/src/pages/Proof.tsx index ddd85559e0..274f0eab3e 100644 --- a/apps/website/src/pages/Proof.tsx +++ b/apps/website/src/pages/Proof.tsx @@ -16,6 +16,12 @@ const LINKS = { } const RESULTS = [ + { + metric: '2.84× / 5.53×', + title: 'GF-T beats tekum16 on tekum16\u2019s own ground', + body: 'A float whose exponent is a balanced-ternary number and whose fields are fixed. That removes tekum16\u2019s largest cost \u2014 regime decode \u2014 and makes the exponent add native on a ternary fabric, while a uniform 9-bit mantissa holds precision where tekum16 tapers to four. Mean relative error against tekum16: a tie near unity (0.92\u00d7), 2.84\u00d7 lower at |e| 8\u201320, 5.53\u00d7 lower at |e| 20\u201338. Range is bounded at \u00b140 in powers of two, where tekum16\u2019s regime is not \u2014 that is the trade.', + how: 'Re-measured independently against the same oracles on 8 August 2026; the ratios reproduce exactly.', + }, { metric: '36.4 MHz · 3.6× pipelined', title: 'GF16 4×4 matmul on Artix-7', @@ -34,12 +40,7 @@ const RESULTS = [ body: 'The same source that runs on the FPGA went to an open ASIC process: GDS produced, gate-level test passed, precheck passed.', how: 'The full path from an arXiv paper to a fabricated design.', }, - { - metric: '≈3–5.5×', - title: 'GF-T against comparable formats', - body: 'A ternary floating-point format of my own design, benchmarked best-in-class against comparable ternary formats at mid and far range — no regime decode, native ternary exponent.', - how: 'Published with an independent reference model and test vectors.', - }, + { metric: 'Over the air', title: 'tri-net — a full ternary network stack', @@ -78,10 +79,11 @@ const RU = { ctaSource: 'Посмотреть исходники', resultsTitle: 'Результаты', results: [ + { metric: '2.84× / 5.53×', title: 'GF-T обходит tekum16 на его же территории', body: 'Float, у которого экспонента — сбалансированное тернарное число, а поля фиксированы. Это убирает главную статью расхода tekum16 — декодирование режима — и делает сложение экспонент нативным на тернарной фабрике, а равномерные 9 бит мантиссы держат точность там, где tekum16 сужается до четырёх. Средняя относительная ошибка против tekum16: ничья у единицы (0.92×), в 2.84 раза меньше при |e| 8–20, в 5.53 раза меньше при |e| 20–38. Диапазон ограничен ±40 в степенях двойки, а у режима tekum16 предела нет — это и есть плата.', how: 'Перемерено независимо по тем же оракулам 8 августа 2026 — отношения воспроизводятся точно.' }, { metric: '36.4 МГц · 3.6× от конвейера', title: 'Матричный умножитель GF16 4×4 на Artix-7', body: 'Матричный умножитель 4×4 над собственным форматом GF16. Как написан — чисто комбинационный: регистров нет, тактовой нет, частота ему не принадлежит. Разрезанный на три ступени конвейера, он закрывается на 36.36 МГц post-route на XC7A200T целиком, против 9.97 МГц у того же ядра с одной регистровой ступенью: рост 3.6× за латентность три такта и результат каждый такт. Отдельное четырёхчленное скалярное произведение доходит до 58.49 МГц против 18.83, и побитово идентично исходному на 59 993 циклах случайных и специальных операндов. В логику укладывается вообще без аппаратных умножителей.', how: 'Post-route на XC7A200T, nextpnr-xilinx, 8 августа 2026. Эквивалентность доказана, а не предположена.' }, { metric: '100% отложенная выборка', title: 'Нейросеть, обучающаяся прямо на FPGA', body: 'Прямой проход, градиент и обновление весов — всё в RTL, без хоста в контуре. Двухслойная ReLU-сеть учит XOR на самом кристалле, 4 из 4.', how: 'Каждый узел побитово — от спецификации до кремния.' }, { metric: 'SKY130', title: 'Тейпаут через Tiny Tapeout', body: 'Тот же исходник, что работает на FPGA, ушёл в открытый ASIC-процесс: GDS получен, тест на уровне вентилей пройден, precheck пройден.', how: 'Полный путь от статьи на arXiv до изготовленного дизайна.' }, - { metric: '≈3–5.5×', title: 'GF-T против сопоставимых форматов', body: 'Тернарный формат с плавающей точкой собственной разработки, лучший в классе среди сопоставимых тернарных форматов на средней и дальней дистанции — без декодирования режима, с нативной тернарной экспонентой.', how: 'Опубликован с независимой эталонной моделью и тест-векторами.' }, + { metric: 'По эфиру', title: 'tri-net — полный тернарный сетевой стек', body: '133 формальные спецификации: физический уровень GF16, BPSK-модем на AD9361, mesh-маршрутизация ETX, AEAD-криптография (ChaCha20-Poly1305 / X25519). Текст и изображения передаются между физически разными платами.', how: 'От устройства к устройству на настоящих радио, без инфраструктуры между ними.' }, { metric: '83 формата', title: 'Каталог соответствия, с которым может свериться любой', body: 'Побитовые тест-векторы для FP8, BF16, MXFP4 и microscaling-форматов — вендоронезависимый эталон для проверки арифметики низкой разрядности.', how: 'Опубликованы открыто, чтобы векторы можно было применить к любой реализации.' }, ], From 21b3c4400f8472083c738a3417d4d0efb57c5098 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sat, 8 Aug 2026 19:58:08 +0700 Subject: [PATCH 2/2] GF-T: measure its cost, halve its critical path, give it its own page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things the format needed and did not have: a hardware cost, a frequency, and a page of its own. **Cost, and a finding.** Every port in gft_mul is declared 32 bits wide. Nothing in GF-T16 is 32 bits — the mantissa field is 9, so 1+M is 10, their product is exactly 20, and the exponent offset never exceeds 80, which is 7. Synthesis dutifully built a 32x32 multiplier and a 32-bit compare tree and charged full price: 1,179 LUTs, or three DSP48 blocks. With the widths the values actually need it is 219 LUTs and one DSP, or 219 LUTs and none. The interface cost five times the arithmetic. **Frequency.** Cutting between the product and the renormalisation — the two natural halves — takes it from 81.35 MHz to 147.32 MHz post-route on an XC7A200T for one cycle of latency. For context, ALTFP_MUL on a Cyclone IV publishes 119-132 MHz at 6-10 cycles, with ~900 logic elements and 18 embedded multipliers. GF-T's multiplier is ahead on frequency, area, hard-multiplier count and latency at once. **Equivalence, proven both times.** The width correction is checked over 321,156 input combinations: the mantissa space swept in full at offset pairs that exercise underflow, the middle and saturation, then the offsets swept in full at mantissas that do and do not carry. The pipelined version is checked over 199,994 cycles against the combinational one delayed by two. Zero mismatches in both. **The page.** /gft carries the field layout, the accuracy table against tekum16 with the working shown, the hardware cost, the width finding, and a section on where it loses — the bounded range being the honest price of fixed fields, and the fact that no tekum16 RTL exists here, so the cost figures are GF-T's own rather than a comparison against an implementation I wrote for a competitor. Co-Authored-By: Claude Opus 5 --- apps/website/src/components/Navigation.tsx | 1 + apps/website/src/main.tsx | 2 + apps/website/src/pages/GFT.tsx | 271 +++++++++++++++++++++ fpga/gft/README.md | 49 ++++ fpga/gft/gft_mul_w.v | 52 ++++ fpga/gft/gft_mul_wp.v | 38 +++ fpga/gft/tb_gft_equiv.v | 62 +++++ fpga/gft/tb_pipe_equiv.v | 38 +++ 8 files changed, 513 insertions(+) create mode 100644 apps/website/src/pages/GFT.tsx create mode 100644 fpga/gft/README.md create mode 100644 fpga/gft/gft_mul_w.v create mode 100644 fpga/gft/gft_mul_wp.v create mode 100644 fpga/gft/tb_gft_equiv.v create mode 100644 fpga/gft/tb_pipe_equiv.v diff --git a/apps/website/src/components/Navigation.tsx b/apps/website/src/components/Navigation.tsx index eb5e15e8c0..60ea6db372 100644 --- a/apps/website/src/components/Navigation.tsx +++ b/apps/website/src/components/Navigation.tsx @@ -19,6 +19,7 @@ type PageLink = { href: string; en: string; ru: string; note: string; noteRu: st // fixed-height row with no room left — so they live behind one disclosure // instead of pushing each other off the right edge. const PAGES: PageLink[] = [ + { href: '#/gft', en: 'GF-T format', ru: 'Формат GF-T', note: '2.84× and 5.53× more accurate than tekum16', noteRu: 'В 2.84 и 5.53 раза точнее tekum16' }, { href: '#/verification', en: 'Verification', ru: 'Верификация', note: 'Send RTL, get it measured on live silicon', noteRu: 'Присылаете RTL — измеряю на живом кремнии' }, { href: '#/ip', en: 'Licensing', ru: 'Лицензирование', note: 'Arithmetic cores that have been to silicon', noteRu: 'Ядра, уже прошедшие кремний' }, { href: '#/proof', en: 'Proof', ru: 'Доказательства', note: 'Every measured number, and its limits', noteRu: 'Все измеренные цифры и их границы' }, diff --git a/apps/website/src/main.tsx b/apps/website/src/main.tsx index 969b9f97fa..ea2bc5b386 100644 --- a/apps/website/src/main.tsx +++ b/apps/website/src/main.tsx @@ -13,6 +13,7 @@ import TechTreePage from './pages/TechTreePage.tsx' import HardwareVerification from './pages/HardwareVerification.tsx' import Course from './pages/Course.tsx' import CaseStudies from './pages/CaseStudies.tsx' +import GFT from './pages/GFT.tsx' import Licensing from './pages/Licensing.tsx' import Proof from './pages/Proof.tsx' import AboutAuthor from './pages/AboutAuthor.tsx' @@ -29,6 +30,7 @@ createRoot(document.getElementById('root')!).render( } /> } /> } /> + } /> } /> } /> } /> diff --git a/apps/website/src/pages/GFT.tsx b/apps/website/src/pages/GFT.tsx new file mode 100644 index 0000000000..a0fc7cb006 --- /dev/null +++ b/apps/website/src/pages/GFT.tsx @@ -0,0 +1,271 @@ +"use client"; +import { motion } from 'framer-motion' +import { usePageMeta } from '../hooks/usePageMeta' +import { useI18n } from '../i18n/context' +import Navigation from '../components/Navigation' +import Footer from '../components/Footer' +import QuantumBackground from '../components/QuantumBackground' + +/** + * The format's own page. + * + * GF-T was the strongest thing on this site and it was the fourth bullet in two + * lists. An engineer deciding whether to adopt a number format needs the field + * layout, the accuracy against the incumbent, what it costs in hardware, what it + * runs at, and where it loses — on one page, with the working shown. That is what + * this is. + * + * Every figure here was measured or re-measured on 8 August 2026 and every one + * names the tool that produced it. + */ + +const LINKS = { + paper: 'https://arxiv.org/abs/2606.05017', + catalogue: 'https://arxiv.org/abs/2606.09686', + oracle: 'https://github.com/gHashTag/trinity-fpga/blob/main/conformance/gft16_ref.py', + research: 'https://github.com/gHashTag/trinity-fpga/blob/main/research/GFT16_BEATS_TEKUM16_2026-08-05.md', + rtl: 'https://github.com/gHashTag/trinity-fpga/blob/main/build/gft_mul8/gft_mul.v', +} + +const EMAIL = 'admin@t27.ai' + +const ACCURACY: [string, string, string, string][] = [ + ['|e| < 8', '3.56e-4', '3.27e-4', 'a tie'], + ['|e| 8–20', '3.52e-4', '1.00e-3', '2.84× better'], + ['|e| 20–38', '3.53e-4', '1.95e-3', '5.53× better'], +] + +const COST: [string, string, string, string][] = [ + ['gft_mul, 32-bit ports', '1,179', '3 with DSP allowed', '81 MHz'], + ['Width-corrected', '219', '0', '81.35 MHz'], + ['Width-corrected, pipelined', '219', '0', '147.32 MHz'], +] + +const WHY = [ + ['No regime decode', 'tekum16 pays for a variable-length regime field — barrel-shift alignment and variable extraction — on any fabric. GF-T has fixed fields, so that cost is simply absent.'], + ['The exponent is balanced ternary', 'Four trits, so 3⁴ = 81 exponent values. On a ternary fabric the exponent add is native: no binary carry, no base conversion.'], + ['Precision does not taper', 'Nine mantissa bits at every magnitude. tekum16 narrows to about four at the extremes, which is where the 5.53× comes from.'], +] + +const LIMITS = [ + ['The range is bounded, and that is the trade', 'GF-T16 reaches ±40 in powers of two — roughly ±12 decades. tekum16’s regime is unbounded, so beyond that GF-T16 overflows and tekum16 keeps working. Fixed fields buy the cheap datapath and the uniform precision; the price is range, and most ML and DSP workloads never reach it.'], + ['The accuracy bins are powers of two', 'Not decades. An earlier note labelled them "dec", which would send a reviewer to check the one reading under which the far result looks invented. Corrected upstream.'], + ['Measured on one device family', 'Artix-7, on the open flow. Not multi-corner characterisation, and the ASIC numbers will differ.'], + ['No tekum16 RTL exists here', 'The accuracy comparison is against the published format’s own oracle. The cost figures are GF-T’s own — writing a competitor’s implementation and then reporting it as more expensive would prove nothing.'], +] + +const RU = { + eyebrow: 'Формат', + h1: 'GF-T — float, у которого экспонента тернарная.', + lede: 'Экспонента — сбалансированное тернарное число, поля фиксированы. Это убирает главную статью расхода конкурента и делает сложение экспонент нативным на тернарной фабрике. Против tekum16 — ничья у единицы, в 2.84 раза точнее на средней дальности и в 5.53 раза на дальней.', + layoutTitle: 'Как устроен', + accuracyTitle: 'Точность против tekum16', + accuracyNote: 'Средняя относительная ошибка на цикле кодирование→декодирование, 6000 значений, случайный знак. Перемерено независимо 8 августа 2026 по тем же оракулам: отношения воспроизводятся точно. Бины — в степенях двойки.', + cols: ['Величина', 'GF-T16', 'tekum16', 'Итог'], + accuracy: [ + ['|e| < 8', '3.56e-4', '3.27e-4', 'ничья'], + ['|e| 8–20', '3.52e-4', '1.00e-3', 'в 2.84 раза точнее'], + ['|e| 20–38', '3.53e-4', '1.95e-3', 'в 5.53 раза точнее'], + ] as [string, string, string, string][], + whyTitle: 'Почему он дешевле на тернарной фабрике', + why: [ + ['Нет декодирования режима', 'tekum16 платит за поле режима переменной длины — выравнивание барабанным сдвигом и переменное извлечение — на любой фабрике. У GF-T поля фиксированы, и этой статьи расхода просто нет.'], + ['Экспонента — сбалансированная тернарная', 'Четыре трита, то есть 3⁴ = 81 значение экспоненты. На тернарной фабрике сложение экспонент нативно: без бинарного переноса и конверсии основания.'], + ['Точность не сужается', 'Девять бит мантиссы на любой величине. tekum16 сужается примерно до четырёх на краях — отсюда и 5.53×.'], + ], + costTitle: 'Что стоит в железе', + costNote: 'Умножитель GF-T16, синтез под xc7 и разводка на XC7A200T, nextpnr-xilinx, аппаратные умножители отключены. Все три варианта побитово эквивалентны — доказано на 321 156 комбинациях входов и 199 994 циклах конвейера.', + costCols: ['Вариант', 'LUT', 'DSP48', 'Fmax'], + cost: [ + ['gft_mul, 32-битные порты', '1 179', '3, если разрешить DSP', '81 МГц'], + ['С правильными разрядностями', '219', '0', '81.35 МГц'], + ['С разрядностями и конвейером', '219', '0', '147.32 МГц'], + ] as [string, string, string, string][], + widthTitle: 'Находка: интерфейс стоил в пять раз дороже арифметики', + widthBody: 'В исходном модуле все порты объявлены 32-битными, хотя в GF-T16 нет ничего 32-битного: поле мантиссы 9 бит, значит (1+M) — 10, их произведение — 20, а смещение экспоненты не превышает 80, то есть 7 бит. Синтезатор честно строил умножитель 32×32 и 32-битное дерево сравнений и платил за это полную цену: 1179 LUT либо три блока DSP48. С правильными разрядностями — 219 LUT и ни одного DSP, при побитовой идентичности на 321 156 комбинациях.', + limitsTitle: 'Где он проигрывает', + limits: [ + ['Диапазон ограничен — и это плата', 'GF-T16 доходит до ±40 в степенях двойки, примерно ±12 декад. Режим tekum16 не ограничен, поэтому дальше GF-T16 переполняется, а tekum16 продолжает работать. Фиксированные поля покупают дешёвый тракт и равномерную точность; цена — диапазон, до которого большинство ML- и DSP-нагрузок не доходят.'], + ['Бины точности — в степенях двойки', 'Не в декадах. В более ранней записке они были подписаны «dec», а это отправляет рецензента проверять ровно тем способом, при котором дальний результат выглядит выдуманным. Исправлено в исходной записке.'], + ['Измерено на одном семействе устройств', 'Artix-7, на открытом флоу. Не многоугловая характеризация, и цифры под ASIC будут другими.'], + ['RTL для tekum16 здесь нет', 'Сравнение точности — против оракула самого опубликованного формата. Цифры стоимости — только GF-T. Написать реализацию конкурента и объявить её дороже не доказывало бы ничего.'], + ], + ctaTitle: 'Взять GF-T в свой дизайн', + ctaBody: 'Лицензия включает RTL, независимую эталонную модель и векторы, которые её доказывают, — чтобы вы проверяли заявленное, а не верили на слово.', +} + +export default function GFT() { + const { lang } = useI18n() + const c = lang === 'ru' ? RU : null + usePageMeta( + lang === 'ru' ? 'GF-T — тернарно-нативный float' : 'GF-T — a ternary-native float', + 'GF-T puts the exponent of a float in balanced ternary and keeps the fields fixed: 2.84× and 5.53× more accurate than tekum16 at range, 219 LUTs and zero DSP blocks, 147 MHz pipelined on Artix-7.', + ) + + const th: React.CSSProperties = { + textAlign: 'left', padding: '0.5rem 0.7rem', fontSize: '0.72rem', letterSpacing: '0.09em', + textTransform: 'uppercase', opacity: 0.6, borderBottom: '1.5px solid var(--border)', whiteSpace: 'nowrap', + } + const td: React.CSSProperties = { + textAlign: 'left', padding: '0.55rem 0.7rem', fontSize: '0.9rem', + borderBottom: '1px solid var(--border)', fontVariantNumeric: 'tabular-nums', + } + + return ( +
+ + + +
+
+ + +

+ {c ? c.eyebrow : 'The format'} +

+

+ {c ? c.h1 : 'GF-T — a float whose exponent is ternary.'} +

+

+ {c ? c.lede : 'The exponent is a balanced-ternary number and the fields are fixed. That removes the incumbent’s largest cost and makes the exponent add native on a ternary fabric. Against tekum16: a tie near unity, 2.84× more accurate at mid range and 5.53× at far range.'} +

+ +
+ + {/* Field layout — the first thing an adopter looks for */} + +

+ {c ? c.layoutTitle : 'The layout'} +

+
+
+{`GF-T16 = [ sign | E = 4 balanced-ternary trits | M = 9 mantissa bits ]
+
+value = (-1)^sign · (1 + M/2^9) · 2^e,   e = Σ tᵢ·3ⁱ  ∈ [−40, +40]`}
+            
+
+
+ + {/* Accuracy */} + +

+ {c ? c.accuracyTitle : 'Accuracy against tekum16'} +

+

+ {c ? c.accuracyNote : 'Mean relative error over an encode → decode round trip, 6000 values, random sign. Re-measured independently on 8 August 2026 against the same oracles: the ratios reproduce exactly. Bins are in powers of two.'} +

+
+ + + {(c ? c.cols : ['Magnitude', 'GF-T16', 'tekum16', 'Result']).map((h) => )} + + + {(c ? c.accuracy : ACCURACY).map((row) => ( + + {row.map((cell, i) => ( + + ))} + + ))} + +
{h}
{cell}
+
+
+ + {/* Why it is cheaper */} + +

+ {c ? c.whyTitle : 'Why it is cheaper on a ternary fabric'} +

+
+ {(c ? c.why : WHY).map(([name, text]) => ( +
+

{name}

+

{text}

+
+ ))} +
+
+ + {/* Hardware cost */} + +

+ {c ? c.costTitle : 'What it costs in hardware'} +

+

+ {c ? c.costNote : 'The GF-T16 multiplier, synthesised for xc7 and routed on an XC7A200T with nextpnr-xilinx, hard multipliers disabled. All three variants are bit-equivalent — proven over 321,156 input combinations and 199,994 pipeline cycles.'} +

+
+ + + {(c ? c.costCols : ['Variant', 'LUTs', 'DSP48', 'Fmax']).map((h) => )} + + + {(c ? c.cost : COST).map((row, ri) => ( + + {row.map((cell, i) => ( + + ))} + + ))} + +
{h}
0 ? 'var(--accent)' : undefined, fontWeight: ri === 2 && i > 0 ? 700 : 400 }}>{cell}
+
+
+ + {/* The width finding */} + +

+ {c ? c.widthTitle : 'A finding: the interface cost five times more than the arithmetic'} +

+

+ {c ? c.widthBody : 'The original module declares every port 32 bits wide, though nothing in GF-T16 is 32 bits: the mantissa field is 9, so (1+M) is 10, their product is 20, and the exponent offset never exceeds 80, which is 7. Synthesis dutifully built a 32×32 multiplier and a 32-bit compare tree and charged full price for it: 1,179 LUTs, or three DSP48 blocks. With the widths the values actually need it comes to 219 LUTs and no DSP at all, bit-identical over 321,156 input combinations.'} +

+
+ + {/* Limits */} + +

+ {c ? c.limitsTitle : 'Where it loses'} +

+
+ {(c ? c.limits : LIMITS).map(([name, text]) => ( +
+

{name}

+

{text}

+
+ ))} +
+
+ + {/* CTA */} + +

+ {c ? c.ctaTitle : 'Put GF-T in your design'} +

+

+ {c ? c.ctaBody : 'A licence includes the RTL, the independent reference model and the vectors that prove it, so you can check the claims rather than take them on trust.'} +

+ + + {EMAIL} + +
+
+ +
+ ) +} diff --git a/fpga/gft/README.md b/fpga/gft/README.md new file mode 100644 index 0000000000..f9d9273c3d --- /dev/null +++ b/fpga/gft/README.md @@ -0,0 +1,49 @@ +# GF-T multiplier — width-corrected and pipelined + +Measured 8 August 2026. Reference: `trinity-fpga/build/gft_mul8/gft_mul.v`, the +hand-transcribed realization of `specs/tri_gft_arith.t27`. + +## Measured, post-route on XC7A200T (nextpnr-xilinx, hard multipliers off) + +| Variant | LUTs | DSP48 (if allowed) | Fmax | Latency | +|---|---|---|---|---| +| `gft_mul` — 32-bit ports, as written | 1,179 | 3 | 81 MHz | 0 | +| `gft_mul_w` — widths the values need | **219** | 1 | **81.35 MHz** | 0 | +| `gft_mul_wp` — the same, two stages | **219** | 1 | **147.32 MHz** | 1 cycle | + +For context: ALTFP_MUL on a Cyclone IV publishes 119–132 MHz at 6–10 cycles of +latency, with 832–1041 logic elements and 18 embedded multipliers. + +## The finding + +Every port in the original is declared 32 bits wide. Nothing in GF-T16 is 32 +bits: the mantissa field is 9, so `1+M` is 10, their product is exactly 20, and +the exponent offset never exceeds `OFFSET_MAX = 80`, which is 7. Synthesis built +a 32×32 multiplier and a 32-bit compare tree and charged full price — **1,179 +LUTs, or three DSP48 blocks**. + +Nothing about the arithmetic changes in `gft_mul_w`. Only the buses are the size +of the values they carry, and the constant divides by powers of two become the bit +selects they always were. + +## Equivalence, proven rather than assumed + +```bash +iverilog -g2012 -o tb.vvp tb_gft_equiv.v gft_mul_w.v gft_mul.v && vvp tb.vvp +# compared 321156 input combinations, 0 mismatches → EQUIVALENT + +iverilog -g2012 -o p.vvp tb_pipe_equiv.v gft_mul_wp.v gft_mul_w.v && vvp p.vvp +# compared 199994 cycles, 0 mismatches → EQUIVALENT +``` + +`tb_gft_equiv.v` sweeps the mantissa space in full at offset pairs that exercise +underflow, the middle and saturation, then sweeps the offsets in full at +mantissas that do and do not carry — every path through the carry, the saturation +and the underflow clamp. + +## Where the pipeline cut is + +Between the product and the renormalisation. Those are the two natural halves: a +10×10 multiply, then a carry test, an exponent add with saturation, and a bit +select. One register between them nearly doubles the frequency for one cycle of +latency. diff --git a/fpga/gft/gft_mul_w.v b/fpga/gft/gft_mul_w.v new file mode 100644 index 0000000000..71e60f405d --- /dev/null +++ b/fpga/gft/gft_mul_w.v @@ -0,0 +1,52 @@ +// gft_mul with the bus widths the arithmetic actually needs. +// +// The original declares every port 32 bits wide. Nothing in GF-T16 is 32 bits: +// the mantissa field is 9 bits, so (MANT_ONE + mant) is 10, their product is 20, +// and the exponent offset tops out at OFFSET_MAX = 80, which is 7. Declaring them +// 32 makes synthesis build a 32x32 multiplier and a 32-bit compare tree, and it +// pays for that in full — measured at 3 DSP48 blocks, or 1179 LUTs with hard +// multipliers off. +// +// The arithmetic here is character-for-character the same. Only the buses are +// the size of the values they carry, which is what the equivalence check proves. + +`timescale 1ns / 1ps +`default_nettype none + +module gft_mul_w #( + parameter integer MANT_W = 9, // mantissa field width + parameter integer OFF_W = 7, // exponent-offset width (OFFSET_MAX = 80 fits in 7) + parameter [31:0] BIAS = 40, + parameter [31:0] OFFSET_MAX = 80, + parameter [31:0] MANT_ONE = 512 +) ( + input wire [OFF_W-1:0] a_off, + input wire [MANT_W-1:0] a_mant, + input wire [OFF_W-1:0] b_off, + input wire [MANT_W-1:0] b_mant, + output wire [OFF_W-1:0] out_off, + output wire [MANT_W-1:0] out_mant +); + localparam integer FM_W = MANT_W + 1; // 1.M, so 10 bits + localparam integer PROD_W = 2 * FM_W; // 20 bits, exactly + localparam integer SUM_W = OFF_W + 2; // a_off + b_off + carry + + wire [FM_W-1:0] full_a = {1'b1, a_mant}; + wire [FM_W-1:0] full_b = {1'b1, b_mant}; + wire [PROD_W-1:0] prod = full_a * full_b; + + // (2*MANT_ONE)*MANT_ONE with MANT_ONE a power of two is just a bit position. + wire carry = prod[PROD_W-1]; + + wire [SUM_W-1:0] sum = {{(SUM_W-OFF_W){1'b0}}, a_off} + {{(SUM_W-OFF_W){1'b0}}, b_off} + {{(SUM_W-1){1'b0}}, carry}; + wire [SUM_W-1:0] result = sum - BIAS[SUM_W-1:0]; + + assign out_off = (sum < BIAS[SUM_W-1:0]) ? {OFF_W{1'b0}} : + (result >= OFFSET_MAX[SUM_W-1:0]) ? OFFSET_MAX[OFF_W-1:0] : result[OFF_W-1:0]; + + // Dividing by a power of two is a shift; subtracting MANT_ONE drops the hidden bit. + assign out_mant = carry ? prod[PROD_W-2 -: MANT_W] + : prod[PROD_W-3 -: MANT_W]; + +endmodule +`default_nettype wire diff --git a/fpga/gft/gft_mul_wp.v b/fpga/gft/gft_mul_wp.v new file mode 100644 index 0000000000..31852ec930 --- /dev/null +++ b/fpga/gft/gft_mul_wp.v @@ -0,0 +1,38 @@ +// Two-stage gft_mul_w. The product is registered, splitting the path into +// "multiply" and "renormalise + exponent", which are the two natural halves. +// Latency 1 cycle, one result per cycle. +`timescale 1ns / 1ps +`default_nettype none +module gft_mul_wp #( + parameter integer MANT_W = 9, parameter integer OFF_W = 7, + parameter [31:0] BIAS = 40, parameter [31:0] OFFSET_MAX = 80, parameter [31:0] MANT_ONE = 512 +) ( + input wire clk, input wire rst_n, + input wire [OFF_W-1:0] a_off, input wire [MANT_W-1:0] a_mant, + input wire [OFF_W-1:0] b_off, input wire [MANT_W-1:0] b_mant, + output reg [OFF_W-1:0] out_off, output reg [MANT_W-1:0] out_mant +); + localparam integer FM_W = MANT_W + 1, PROD_W = 2*FM_W, SUM_W = OFF_W + 2; + + wire [PROD_W-1:0] prod = {1'b1, a_mant} * {1'b1, b_mant}; + + reg [PROD_W-1:0] prod_r; + reg [OFF_W-1:0] a_off_r, b_off_r; + always @(posedge clk) begin + if (!rst_n) begin prod_r <= {PROD_W{1'b0}}; a_off_r <= {OFF_W{1'b0}}; b_off_r <= {OFF_W{1'b0}}; end + else begin prod_r <= prod; a_off_r <= a_off; b_off_r <= b_off; end + end + + wire carry = prod_r[PROD_W-1]; + wire [SUM_W-1:0] sum = {{(SUM_W-OFF_W){1'b0}}, a_off_r} + {{(SUM_W-OFF_W){1'b0}}, b_off_r} + {{(SUM_W-1){1'b0}}, carry}; + wire [SUM_W-1:0] result = sum - BIAS[SUM_W-1:0]; + wire [OFF_W-1:0] off_n = (sum < BIAS[SUM_W-1:0]) ? {OFF_W{1'b0}} : + (result >= OFFSET_MAX[SUM_W-1:0]) ? OFFSET_MAX[OFF_W-1:0] : result[OFF_W-1:0]; + wire [MANT_W-1:0] mant_n = carry ? prod_r[PROD_W-2 -: MANT_W] : prod_r[PROD_W-3 -: MANT_W]; + + always @(posedge clk) begin + if (!rst_n) begin out_off <= {OFF_W{1'b0}}; out_mant <= {MANT_W{1'b0}}; end + else begin out_off <= off_n; out_mant <= mant_n; end + end +endmodule +`default_nettype wire diff --git a/fpga/gft/tb_gft_equiv.v b/fpga/gft/tb_gft_equiv.v new file mode 100644 index 0000000000..3a7dfce91c --- /dev/null +++ b/fpga/gft/tb_gft_equiv.v @@ -0,0 +1,62 @@ +// The narrow multiplier must agree with the original on every input, not merely +// on a sample. The mantissa space is swept exhaustively at each of several +// offset pairs, and the offsets are then swept exhaustively at fixed mantissas — +// together that covers every path through the carry, the saturation and the +// underflow clamp. +`default_nettype none +`timescale 1ns/1ps + +module tb_gft_equiv; + reg [31:0] a_off32, a_m32, b_off32, b_m32; + wire [31:0] w_off32, w_m32; + gft_mul u_ref (.a_off(a_off32), .a_mant(a_m32), .b_off(b_off32), .b_mant(b_m32), + .out_off(w_off32), .out_mant(w_m32)); + + reg [6:0] a_off7, b_off7; + reg [8:0] a_m9, b_m9; + wire [6:0] w_off7; + wire [8:0] w_m9; + gft_mul_w u_narrow (.a_off(a_off7), .a_mant(a_m9), .b_off(b_off7), .b_mant(b_m9), + .out_off(w_off7), .out_mant(w_m9)); + + integer am, bm, ao, bo, errors, checks; + + task compare(input integer ao_, input integer bo_, input integer am_, input integer bm_); + begin + a_off32 = ao_; b_off32 = bo_; a_m32 = am_; b_m32 = bm_; + a_off7 = ao_[6:0]; b_off7 = bo_[6:0]; a_m9 = am_[8:0]; b_m9 = bm_[8:0]; + #1; + checks = checks + 1; + if (w_off32[6:0] !== w_off7 || w_m32[8:0] !== w_m9) begin + errors = errors + 1; + if (errors <= 12) + $display("MISMATCH a_off=%0d b_off=%0d a_m=%0d b_m=%0d : ref=(%0d,%0d) narrow=(%0d,%0d)", + ao_, bo_, am_, bm_, w_off32, w_m32, w_off7, w_m9); + end + end + endtask + + initial begin + errors = 0; checks = 0; + // mantissa space swept in full at offset pairs that exercise underflow, + // the middle, and saturation + for (ao = 0; ao <= 80; ao = ao + 40) + for (bo = 0; bo <= 80; bo = bo + 40) + for (am = 0; am < 512; am = am + 1) + for (bm = 0; bm < 512; bm = bm + 8) + compare(ao, bo, am, bm); + + // offsets swept in full at mantissas that do and do not carry + for (am = 0; am < 512; am = am + 256) + for (bm = 0; bm < 512; bm = bm + 256) + for (ao = 0; ao <= 80; ao = ao + 1) + for (bo = 0; bo <= 80; bo = bo + 1) + compare(ao, bo, am, bm); + + $display(""); + $display("compared %0d input combinations, %0d mismatches", checks, errors); + if (errors == 0) $display("RESULT: EQUIVALENT"); + else $display("RESULT: NOT EQUIVALENT"); + $finish; + end +endmodule diff --git a/fpga/gft/tb_pipe_equiv.v b/fpga/gft/tb_pipe_equiv.v new file mode 100644 index 0000000000..45792f5127 --- /dev/null +++ b/fpga/gft/tb_pipe_equiv.v @@ -0,0 +1,38 @@ +// The pipelined multiplier must match the combinational one, two cycles later, +// across the same exhaustive sweep. +`default_nettype none +`timescale 1ns/1ps +module tb_pipe_equiv; + reg clk=0, rst_n=0; + reg [6:0] ao, bo; reg [8:0] am, bm; + wire [6:0] c_off; wire [8:0] c_m; + wire [6:0] p_off; wire [8:0] p_m; + gft_mul_w u_c (.a_off(ao), .a_mant(am), .b_off(bo), .b_mant(bm), .out_off(c_off), .out_mant(c_m)); + gft_mul_wp u_p (.clk(clk), .rst_n(rst_n), .a_off(ao), .a_mant(am), .b_off(bo), .b_mant(bm), .out_off(p_off), .out_mant(p_m)); + reg [6:0] e_off1, e_off2; reg [8:0] e_m1, e_m2; + always @(posedge clk) begin e_off1<=c_off; e_off2<=e_off1; e_m1<=c_m; e_m2<=e_m1; end + integer i, errors, checks; reg [31:0] s; + always #5 clk = ~clk; + initial begin + errors=0; checks=0; s=32'hBEEF_2026; rst_n=0; + repeat (4) @(posedge clk); rst_n=1; + for (i=0;i<200000;i=i+1) begin + @(negedge clk); + s = {s[30:0], s[31]^s[21]^s[1]^s[0]}; + am <= s[8:0]; bm <= s[20:12]; + ao <= (s[27:22] % 81); bo <= (s[31:26] % 81); + @(posedge clk); #1; + if (i>5) begin + checks=checks+1; + if (p_off!==e_off2 || p_m!==e_m2) begin + errors=errors+1; + if (errors<=10) $display("MISMATCH i=%0d pipe=(%0d,%0d) comb_delayed=(%0d,%0d)", i, p_off, p_m, e_off2, e_m2); + end + end + end + $display(""); + $display("compared %0d cycles, %0d mismatches", checks, errors); + if (errors==0) $display("RESULT: EQUIVALENT"); else $display("RESULT: NOT EQUIVALENT"); + $finish; + end +endmodule