From 3a4c33f77c3ad166feec281b486c01ca1fc14709 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sat, 8 Aug 2026 20:25:19 +0700 Subject: [PATCH] The GF-T ladder, and a correction: takum's RTL does exist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page said no such RTL existed. It does — takum-arithmetic/Takum-Codec-RTL, VHDL, public — and the page is corrected rather than softened. What follows from that is now stated exactly. Synthesising VHDL alongside GF-T needs a front end this bench does not have, so the cost figures remain GF-T's own. What their source does show, and it is the whole cost argument: their 16-bit codec pulls in a 725-line FloPoCo leading-zero-counter and barrel shifter, generated for a Kintex-7. That is the regime decode GF-T's fixed fields do not have. Named as structural rather than measured, because that is what it is. A second correction from reading the oracle: tekum (arXiv:2512.10964) is a descendant of takum adapted for balanced ternary, and the oracle it is measured against here is a reverse-engineered structural model of it. The ratios are as good as that model, and the page says so now. The ladder is measured on one harness so the rows compare: GF-T8 at 50 LUTs and 153.23 MHz, GF-T16 at 212 and 131.73, GF-T32 at 1,477 and 83.27, one cycle of latency each. Getting there turned up a defect worth the whole exercise. gft_mul declares its product wire 32 bits; GF-T32's product is 52. The header calls the module parametric per rung and names GF-T32, so instantiating it that way looks supported and silently truncates — 1,995,730 mismatches in 2,128,964 combinations against gft_mul32.v. gft_mul_w derives the width from the parameters and agrees with gft_mul32 over 300,000 combinations. Sent upstream as trinity-fpga#510. Co-Authored-By: Claude Opus 5 --- apps/website/src/pages/GFT.tsx | 40 ++++++++++++++++++++++++-- fpga/gft/tb32.v | 32 +++++++++++++++++++++ fpga/gft/tb_rung.v | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 fpga/gft/tb32.v create mode 100644 fpga/gft/tb_rung.v diff --git a/apps/website/src/pages/GFT.tsx b/apps/website/src/pages/GFT.tsx index a0fc7cb006..4ee9c50206 100644 --- a/apps/website/src/pages/GFT.tsx +++ b/apps/website/src/pages/GFT.tsx @@ -35,6 +35,12 @@ const ACCURACY: [string, string, string, string][] = [ ['|e| 20–38', '3.53e-4', '1.95e-3', '5.53× better'], ] +const LADDER: [string, string, string][] = [ + ['GF-T8', '50', '153.23 MHz'], + ['GF-T16', '212', '131.73 MHz'], + ['GF-T32', '1,477', '83.27 MHz'], +] + 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'], @@ -51,7 +57,8 @@ 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.'], + ['The comparison is against a model of tekum, not tekum itself', 'tekum (arXiv:2512.10964) is a descendant of takum adapted for balanced ternary. The oracle it is measured against here is a reverse-engineered structural model built from takum’s field scheme — the full per-trit specification needs the paper. The ratios are as good as that model.'], + ['No head-to-head in hardware yet', 'takum’s RTL is public and is VHDL (takum-arithmetic/Takum-Codec-RTL). Synthesising it alongside GF-T needs a VHDL front end this bench does not have, so the cost figures here are GF-T’s own. What can be said from their source: their 16-bit codec pulls in a 725-line FloPoCo leading-zero-counter and barrel shifter, generated for a Kintex-7. That is the regime decode GF-T’s fixed fields do not have — a structural difference, not a measured one.'], ] const RU = { @@ -81,6 +88,14 @@ const RU = { ['С правильными разрядностями', '219', '0', '81.35 МГц'], ['С разрядностями и конвейером', '219', '0', '147.32 МГц'], ] as [string, string, string, string][], + ladderTitle: 'Вся лестница', + ladderNote: 'Один модуль покрывает все ступени: разрядности выводятся из параметров. С конвейером, латентность один такт, измерено на одном и том же стенде — поэтому три строки сравнимы между собой. Эквивалентность доказана на каждой ступени против эталона этой ступени.', + ladderCols: ['Ступень', 'LUT', 'Fmax'], + ladder: [ + ['GF-T8', '50', '153.23 МГц'], + ['GF-T16', '212', '131.73 МГц'], + ['GF-T32', '1 477', '83.27 МГц'], + ] as [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: 'Где он проигрывает', @@ -88,7 +103,8 @@ const RU = { ['Диапазон ограничен — и это плата', 'GF-T16 доходит до ±40 в степенях двойки, примерно ±12 декад. Режим tekum16 не ограничен, поэтому дальше GF-T16 переполняется, а tekum16 продолжает работать. Фиксированные поля покупают дешёвый тракт и равномерную точность; цена — диапазон, до которого большинство ML- и DSP-нагрузок не доходят.'], ['Бины точности — в степенях двойки', 'Не в декадах. В более ранней записке они были подписаны «dec», а это отправляет рецензента проверять ровно тем способом, при котором дальний результат выглядит выдуманным. Исправлено в исходной записке.'], ['Измерено на одном семействе устройств', 'Artix-7, на открытом флоу. Не многоугловая характеризация, и цифры под ASIC будут другими.'], - ['RTL для tekum16 здесь нет', 'Сравнение точности — против оракула самого опубликованного формата. Цифры стоимости — только GF-T. Написать реализацию конкурента и объявить её дороже не доказывало бы ничего.'], + ['Сравнение против модели tekum, а не самого tekum', 'tekum (arXiv:2512.10964) — потомок takum, адаптированный под сбалансированную троичную логику. Оракул, против которого здесь измерено, — реконструированная структурная модель по полевой схеме takum; полная потритовая спецификация требует сверки со статьёй. Отношения ровно настолько хороши, насколько хороша эта модель.'], + ['Прямого сравнения в железе пока нет', 'RTL для takum открыт и написан на VHDL (takum-arithmetic/Takum-Codec-RTL). Чтобы синтезировать его рядом с GF-T, нужен VHDL-фронтенд, которого на этом стенде нет, поэтому цифры стоимости — только GF-T. Что видно из их исходника: их 16-битный кодек тянет 725-строчный FloPoCo-шифтер со счётчиком ведущих нулей, сгенерированный под Kintex-7. Это и есть то декодирование режима, которого у GF-T нет по построению — различие структурное, а не измеренное.'], ], ctaTitle: 'Взять GF-T в свой дизайн', ctaBody: 'Лицензия включает RTL, независимую эталонную модель и векторы, которые её доказывают, — чтобы вы проверяли заявленное, а не верили на слово.', @@ -220,6 +236,26 @@ value = (-1)^sign · (1 + M/2^9) · 2^e, e = Σ tᵢ·3ⁱ ∈ [−40, +40]`} + {/* The ladder */} + +

+ {c ? c.ladderTitle : 'The whole ladder'} +

+

+ {c ? c.ladderNote : 'One module covers every rung, with the widths derived from the parameters. Pipelined, one cycle of latency, measured on the same harness so the three rows compare. Equivalence proven at each rung against the reference for that rung.'} +

+
+ + {(c ? c.ladderCols : ['Rung', 'LUTs', 'Fmax']).map((h) => )} + + {(c ? c.ladder : LADDER).map((row) => ( + {row.map((cell, i) => )} + ))} + +
{h}
{cell}
+
+
+ {/* The width finding */}

diff --git a/fpga/gft/tb32.v b/fpga/gft/tb32.v new file mode 100644 index 0000000000..6dfe741246 --- /dev/null +++ b/fpga/gft/tb32.v @@ -0,0 +1,32 @@ +// gft_mul_w at the GF-T32 rung against gft_mul32 — the 64-bit module that exists +// precisely because the 32-bit one cannot hold this product. +`default_nettype none +`timescale 1ns/1ps +module tb32; + reg [31:0] ao, am, bo, bm; + wire [31:0] r_off, r_mant; + gft_mul32 u_ref (.a_off(ao), .a_mant(am), .b_off(bo), .b_mant(bm), .out_off(r_off), .out_mant(r_mant)); + + reg [9:0] wao, wbo; reg [24:0] wam, wbm; + wire [9:0] w_off; wire [24:0] w_mant; + gft_mul_w #(.MANT_W(25), .OFF_W(10), .BIAS(364), .OFFSET_MAX(728), .MANT_ONE(33554432)) u_w + (.a_off(wao), .a_mant(wam), .b_off(wbo), .b_mant(wbm), .out_off(w_off), .out_mant(w_mant)); + + integer i, errors, checks; reg [63:0] s; + initial begin + errors=0; checks=0; s=64'hFEED_FACE_1234_5678; + for (i=0;i<300000;i=i+1) begin + s = {s[62:0], s[63]^s[62]^s[60]^s[59]}; + ao = s[9:0] % 729; bo = s[25:16] % 729; + am = s[56:32]; bm = {s[24:10], s[41:32]}; + wao = ao[9:0]; wbo = bo[9:0]; wam = am[24:0]; wbm = bm[24:0]; + #1; checks=checks+1; + if (r_off[9:0]!==w_off || r_mant[24:0]!==w_mant) begin + errors=errors+1; + if (errors<=6) $display(" MISMATCH: ref=(%0d,%0d) w=(%0d,%0d)", r_off, r_mant, w_off, w_mant); + end + end + $display(" %0d combinations, %0d mismatches -> %s", checks, errors, errors==0?"EQUIVALENT":"NOT EQUIVALENT"); + $finish; + end +endmodule diff --git a/fpga/gft/tb_rung.v b/fpga/gft/tb_rung.v new file mode 100644 index 0000000000..ddc7c1ba0b --- /dev/null +++ b/fpga/gft/tb_rung.v @@ -0,0 +1,51 @@ +// Equivalence at one rung of the ladder: the width-corrected multiplier against +// the original, with both given the same rung parameters. Mantissa space swept in +// full where it is small enough, sampled densely where it is not. +`default_nettype none +`timescale 1ns/1ps +module tb_rung #( + parameter integer MANT_W = 9, parameter integer OFF_W = 7, + parameter [31:0] BIAS = 40, parameter [31:0] OFFSET_MAX = 80, parameter [63:0] MANT_ONE = 512, + parameter integer MSTEP = 1 +) (); + reg [31:0] ao32, am32, bo32, bm32; + wire [31:0] ro32, rm32; + gft_mul #(.BIAS(BIAS), .OFFSET_MAX(OFFSET_MAX), .MANT_ONE(MANT_ONE[31:0])) u_ref + (.a_off(ao32), .a_mant(am32), .b_off(bo32), .b_mant(bm32), .out_off(ro32), .out_mant(rm32)); + + reg [OFF_W-1:0] ao, bo; reg [MANT_W-1:0] am, bm; + wire [OFF_W-1:0] ro; wire [MANT_W-1:0] rm; + gft_mul_w #(.MANT_W(MANT_W), .OFF_W(OFF_W), .BIAS(BIAS), .OFFSET_MAX(OFFSET_MAX), .MANT_ONE(MANT_ONE[31:0])) u_w + (.a_off(ao), .a_mant(am), .b_off(bo), .b_mant(bm), .out_off(ro), .out_mant(rm)); + + integer a_, b_, ai, bi, errors, checks; + localparam integer MMAX = (1 << MANT_W); + + task cmp(input integer x, input integer y, input integer p, input integer q); + begin + ao32=x; bo32=y; am32=p; bm32=q; + ao=x[OFF_W-1:0]; bo=y[OFF_W-1:0]; am=p[MANT_W-1:0]; bm=q[MANT_W-1:0]; + #1; checks=checks+1; + if (ro32[OFF_W-1:0]!==ro || rm32[MANT_W-1:0]!==rm) begin + errors=errors+1; + if (errors<=8) $display(" MISMATCH off=(%0d,%0d) mant=(%0d,%0d): ref=(%0d,%0d) w=(%0d,%0d)", x,y,p,q, ro32,rm32, ro,rm); + end + end + endtask + + initial begin + errors=0; checks=0; + for (a_=0; a_<=OFFSET_MAX; a_=a_+(OFFSET_MAX/4>0?OFFSET_MAX/4:1)) + for (b_=0; b_<=OFFSET_MAX; b_=b_+(OFFSET_MAX/4>0?OFFSET_MAX/4:1)) + for (ai=0; ai0?MSTEP*8:1)) + cmp(a_, b_, ai, bi); + for (ai=0; ai0?MMAX/2:1)) + for (bi=0; bi0?MMAX/2:1)) + for (a_=0; a_<=OFFSET_MAX; a_=a_+1) + for (b_=0; b_<=OFFSET_MAX; b_=b_+1) + cmp(a_, b_, ai, bi); + $display(" %0d combinations, %0d mismatches -> %s", checks, errors, errors==0 ? "EQUIVALENT" : "NOT EQUIVALENT"); + $finish; + end +endmodule