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