Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions apps/website/src/pages/GFT.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand All @@ -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 = {
Expand Down Expand Up @@ -81,14 +88,23 @@ 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: 'Где он проигрывает',
limits: [
['Диапазон ограничен — и это плата', '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, независимую эталонную модель и векторы, которые её доказывают, — чтобы вы проверяли заявленное, а не верили на слово.',
Expand Down Expand Up @@ -220,6 +236,26 @@ value = (-1)^sign · (1 + M/2^9) · 2^e, e = Σ tᵢ·3ⁱ ∈ [−40, +40]`}
</div>
</motion.div>

{/* The ladder */}
<motion.div className="premium-card" initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.6 }} style={{ marginBottom: '2rem' }}>
<h2 style={{ fontSize: 'clamp(1.3rem, 3.5vw, 1.7rem)', marginTop: 0, marginBottom: '0.6rem' }}>
{c ? c.ladderTitle : 'The whole ladder'}
</h2>
<p style={{ fontSize: '0.9rem', lineHeight: 1.6, opacity: 0.85, maxWidth: '64ch', margin: '0 auto 1.2rem' }}>
{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.'}
</p>
<div style={{ overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse', minWidth: '360px' }}>
<thead><tr>{(c ? c.ladderCols : ['Rung', 'LUTs', 'Fmax']).map((h) => <th key={h} style={th}>{h}</th>)}</tr></thead>
<tbody>
{(c ? c.ladder : LADDER).map((row) => (
<tr key={row[0]}>{row.map((cell, i) => <td key={i} style={td}>{cell}</td>)}</tr>
))}
</tbody>
</table>
</div>
</motion.div>

{/* The width finding */}
<motion.div className="premium-card" initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.6 }} style={{ marginBottom: '2rem' }}>
<h2 style={{ fontSize: 'clamp(1.2rem, 3.5vw, 1.55rem)', marginTop: 0, marginBottom: '0.7rem' }}>
Expand Down
32 changes: 32 additions & 0 deletions fpga/gft/tb32.v
Original file line number Diff line number Diff line change
@@ -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
51 changes: 51 additions & 0 deletions fpga/gft/tb_rung.v
Original file line number Diff line number Diff line change
@@ -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; ai<MMAX; ai=ai+MSTEP)
for (bi=0; bi<MMAX; bi=bi+(MSTEP*8>0?MSTEP*8:1))
cmp(a_, b_, ai, bi);
for (ai=0; ai<MMAX; ai=ai+(MMAX/2>0?MMAX/2:1))
for (bi=0; bi<MMAX; bi=bi+(MMAX/2>0?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
Loading