Commit Graph

67 Commits

Author SHA1 Message Date
c4d36515cc fix samples ntt bugs & set PLL & optimize matmul 2026-07-15 10:36:38 +08:00
fc91511950 feat: optimize sram controller 2026-07-15 10:03:39 +08:00
4857016b42 update reports & add mlkem cdc test result & update pll 2026-07-11 10:09:45 +08:00
e30a65bd72 perf(mlkem): pipeline CBD->bank write to cut 100 MHz critical path
At 100 MHz the worst path (WNS -1.58 ns) was CBD sample: squeeze_buf[buf_ptr]
extraction -> CBD add/sub -> mod-Q -> bank_t/bank_se write, all combinational
in one cycle and routing-dominated (squeeze_buf and the banks place far apart).
Register the CBD write (data/addr/enable) so the bank write commits one cycle
later; the registered write takes priority in the bank_se/bank_t mux so the
1-cycle spillover into the next state uses the correct addr/data. No consumer
reads these coeffs until the following stage (>1 cycle later), so no RAW hazard.

Verified byte-exact vs NIST KAT: Encaps 9/9, Decaps 9/9, KeyGen 11/11,
hello_world e2e -- all PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 07:42:35 +08:00
4538ec496f perf(mlkem): register butterfly inputs to cut the 100 MHz NTT critical path
At mlkem_clk=100 MHz the worst path (WNS -2.14 ns) was coeff_bram read ->
butterfly diff (b-a) -> barrett first multiply stage, all in one cycle. The
butterfly took its operands combinationally from the BRAM read (unlike
poly_mul's basecase, which already registers them). Add an input register
stage (a/b/zeta/mode/valid) in butterfly_unit_pipe so the BRAM read and the
first multiply land in separate cycles; feed the a/b/mode alignment delay
lines from the registered inputs. Butterfly latency 8->9; ntt_core writeback
address delay lines deepened 9->10 to match.

Verified byte-exact vs NIST KAT: NTT standalone TB 19/19 (fwd+inv), Encaps
9/9, Decaps 9/9, hello_world e2e — all PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 07:05:12 +08:00
b2c8d6eaf3 perf(mlkem): move poly_mul coeff storage to even/odd banked BRAM
Replace poly_mul_sync's two 256x12 LUT register arrays (mem_A/mem_B, ~8k LUT)
with four sd_bram banks (A_even/A_odd/B_even/B_odd, 128x12). The base-case
reads mem[2k] and mem[2k+1] together, so an even/odd split gives each bank a
single read port. This removes the multi-port LUT mux and the long
BRAM->register-file route that was the mlkem_clk critical path.

sd_bram reads are synchronous (1-cycle); the existing 2-cycle issue cadence
absorbs it (address on the gap cycle, data on the issue cycle), with a
one-cycle priming gap at LOAD->RUN. Interface and behavior unchanged.

Verified byte-exact vs NIST KAT: poly_mul standalone TB 11/11, Encaps 9/9,
Decaps 9/9 (incl. reject + DECOMP), KeyGen, hello_world e2e — all PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 05:41:27 +08:00
78ccc34578 perf(mlkem): move NTT coeff storage to 4-way banked BRAM
Replace ntt_core's 256x12 LUT register file (multi-port async read, ~18.5k
LUT) with coeff_bram_4way: 4 sd_bram banks, conflict-free banking function
bank(a)={a[0], ^a[7:1]}, local(a)=a[7:1]. The dual-butterfly's four accesses
{j, j+1, j+len, j+1+len} map to four distinct banks for every layer_len in
{2..128}, so each bank needs only 1 read + 1 write/cycle (single buffer, no
ping-pong). Trades ~13k LUT for +4 BRAM (device BRAM at ~6%).

Pipeline gains one stage for the synchronous BRAM read; writeback address
delay deepened to 9. coeff_out is driven combinationally from the BRAM read
during OUTPUT; unused read ports mirror port 0 outside compute so the read
crossbar arbitration is not polluted by stale addresses.

Verified byte-exact vs NIST KAT: NTT standalone TB 19/19 (fwd+inv), Encaps
9/9, Decaps 9/9 (incl. reject + DECOMP), KeyGen, hello_world e2e — all PASS.
Cycle counts unchanged (ENC_N +4 for BRAM latency).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 05:16:58 +08:00
be2e54c8ab revert(mlkem): drop poly_mul ping-pong (B2) to reclaim ~7k LUT
B2 (ping-pong poly_mul + decoupled MAC load) doubled the 256x12 coeff
register file (mem_A/B -> 4 arrays) costing ~7k LUT for only ~2.8% Encaps
latency (K=2) — the worst area/latency ratio of the optimization set.
Revert restores single-buffer poly_mul and serial MAC. B1 (compress
streaming) and R1 (dual-butterfly NTT) are kept.

Verified byte-exact vs NIST KAT: Encaps 9/9, Decaps 9/9, KeyGen, hello
end-to-end, poly_mul standalone TB 11/11 — all PASS.

ENC_U K=2 4177->4689, ENC_V 2089->2345 (B2's hidden load reappears).
2026-07-11 03:48:50 +08:00
454c3e559d perf(mlkem): dual-butterfly NTT core (R1) — ~12% fewer Encaps cycles
Issue 2 butterflies/cycle from the same NTT group (positions p,p+1).
ML-KEM's 7 layers have layer_len in {128..2} (always even, never 1),
so each pair shares one zeta and touches 4 distinct coefficient indices
— no intra-group RAW conflict, single zeta ROM. Compute per transform
~966->~490 cycles.

Verified: standalone ntt TB 19/19 (fwd+inv), full KAT Encaps 9/9 +
Decaps 9/9 + KeyGen + hello_world all PASS (all K).
2026-07-11 03:05:35 +08:00
975903000e perf(mlkem): ping-pong poly_mul + decoupled MAC load/accumulate (B2)
Double-buffer poly_mul_sync so the next MAC term's 256-cycle load overlaps
the current term's accumulate. Decouple the top-level MAC load index (u_ldj)
from the accumulate index (u_j) in the shared ENC_U/ENC_V/DEC_W engine; load
reads bank_a/bank_se while accumulate reads bank_t (disjoint ports, no
conflict). Accumulate stays strictly serial (psum order-dependent); only the
load is hidden.

Verified byte-exact vs NIST KAT in ~/Dev/mlkem: Encaps 9/9, Decaps 9/9
(incl. implicit-reject + DECOMP), KeyGen all, hello_world end-to-end.

ENC_U 5585->5073, ENC_V 2793->2537 (K=2). Larger relative win at K=4
(K^2 terms). poly_mul contract unchanged (standalone TB 11/11).
2026-07-11 02:37:28 +08:00
ce40a6df42 perf(mlkem): stream compress feed (B1) — ~27% fewer Encaps cycles
Decouple the ENC_C1/C2 compress micro-sequence into a streaming
producer/collector instead of feeding one coeff and draining the whole
6-stage comp_decomp pipeline per coeff.

- comp_decomp_sync: ready_o = 1'b1 (fully pipelined, consumer never
  backpressures since ready_i is tied high), so feeders can issue a new
  coeff every cycle.
- mlkem_top ENC_C1/C2: producer feeds one coeff every 2 cycles
  (<=5.5 bit/cyc, under the single-port ct drain of 8 bit/cyc so the bit
  buffer stays bounded); a per-cycle collector appends compressed bits
  and drains one ct byte/cycle.

Verified byte-exact against NIST KAT (Vivado 2019.2 XSIM) for KeyGen,
Encaps (9/9), Decaps (9/9 incl. reject path + DECOMP), hello_world e2e.

K=2 Encaps: ENC_C1 6273->1035, ENC_C2 2945->522, total 27851->20190.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 02:00:03 +08:00
6a1b374bc1 set mlkem_clk to 50Mhz 2026-07-08 17:01:46 +08:00
4229652659 fix: add use_dsp=no to FFT Multiply and fft_mlkem_axi_slave
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-08 03:57:39 +08:00
b003fc057f fix(mlkem): verilator lint fixes — BLKLOOPINIT and UNUSEDSIGNAL
ntt_core.v / poly_mul_sync.v: <= → = in array for loops
mlkem_top.v / sha3_top.v: UNUSEDSIGNAL → UNUSED

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-08 03:36:52 +08:00
1b494fe44d add use_dsp=no for matmul 2026-07-08 03:20:34 +08:00
83473b66aa remove dsp usage 2026-07-08 03:18:10 +08:00
0c85a20b4e mlkem test diagnostics and allocator updates 2026-07-08 02:35:56 +08:00
088a9bd5b8 fix(fft): update SdfUnit, Twiddle, and axi wrapper
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-05 23:25:51 +08:00
54ec54d421 feat: add prng 2026-07-05 21:04:25 +08:00
19751b9d18 add no dsp hint for FFT 2026-07-05 20:37:19 +08:00
2b7c43edcb Add DMA-friendly MLKEM windows 2026-07-05 20:07:14 +08:00
7e72bd455a feat: add fft module 2026-07-05 19:30:51 +08:00
423ff32b49 feat: optimize sram read channel 2026-07-05 17:12:38 +08:00
f735f789d6 remove dsp usage 2026-07-04 21:20:32 +08:00
d3a08b1f9d Split CDMA matmul endpoint engines 2026-07-04 20:42:31 +08:00
2725f6eb57 Reduce CDMA matmul bridge request latency 2026-07-04 20:12:45 +08:00
27cdfb713a Optimize CDMA matmul bridge scheduling 2026-07-04 19:59:49 +08:00
c37f493bcb Compute matmul CRC before result store 2026-07-04 19:45:22 +08:00
bf6051c8c6 Add standalone CDMA matmul bridge 2026-07-04 19:35:42 +08:00
b7553418fa Add direct CDMA matmul path 2026-07-04 19:15:34 +08:00
3f7c9b7a37 feat: optimize sram write channel 2026-07-04 18:54:05 +08:00
58f99d82ba chore: typo 2026-07-04 18:53:23 +08:00
3d39fc2f5e doc(mlkem): add mlkem user guide 2026-06-30 15:23:13 +08:00
29313653a9 fix(mlkem): replace Barrett division with direct / and % in comp_decomp_sync
The previous Barrett multiplication-based division was incorrect. Both
compress and decompress used the same wrong implementation, so they
happened to be consistent with each other, but the math was wrong.

Replace with synthesizer-native / and % operators. This is cleaner
and the synthesis tool handles integer division/remainder correctly
for these small operand widths (12-bit dividend, 12-bit divisor).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-30 03:32:20 +08:00
3617ee7656 fix: change <= to = in array for loops for verilator BLKLOOPINIT 2026-06-30 02:15:14 +08:00
99e6c884d7 chore: untrack auto-generated PLL files, add .gitignore 2026-06-30 02:10:29 +08:00
542495cb52 fix: replace UNUSEDPARAM/UNUSEDSIGNAL with UNUSED for verilator lint
Verilator does not recognize UNUSEDPARAM or UNUSEDSIGNAL.
Correct suppression code is UNUSED.
2026-06-30 02:10:07 +08:00
92777efd30 fix: drive dbg_dk_idx_i only during full-dk readback
The core's ek_rd_addr/dkp_rd_addr muxes give dbg_dk_idx_i priority over
dbg_byte_idx_i whenever it falls in the ek (768..1567) or dk_pke (<768)
region. The wrapper drove both dbg_byte_idx_i and dbg_dk_idx_i from the
same rdb_addr, so an ek readback of the rho tail (bytes 768..799) was
hijacked to read ek[0..31] instead — corrupting the public key fed to
Encaps and causing Decaps implicit rejection (full 32-byte ss mismatch).

Present rdb_addr on dbg_dk_idx_i only when rdb_sel==2 (full-dk); hold it
at 0xFFF otherwise so ek/dk_pke readbacks aren't corrupted. Verified by
KeyGen->Encaps->Decaps round trip (MLKEM_RESULT=PASS).
2026-06-30 02:00:50 +08:00
c5072d7170 feat: add ML-KEM accelerator with AXI slave wrapper
Wrap mlkem_top in an AXI4 burst slave (mlkem_axi_slave) mapped to the
freed FFT slot 6 at 0x1f400000 (virtual 0xbf400000). The core runs on
sys_clk/2 (25 MHz); the wrapper handles the clock-domain crossing:
start toggle->pulse, wait-stated byte-preload handshake, busy/done
sync, and direct readback taps (ek/dk/ct/ss). CPU drives it via a
register map (CTRL/STATUS/CONFIG, d/z/msg, preload + readback windows).

Wire into soc_top on the existing axiOut_6 nets (no crossbar change),
add mlkem_intr on intrpt[3]. Add sdk mlkem_test example running a
KeyGen->Encaps->Decaps self-consistency round trip.
2026-06-30 01:39:35 +08:00
8bc3d42ac6 Fix pipe_cnt range: issue 0-15 (16 rounds), acc 4-19, done at 20 2026-06-25 22:26:07 +08:00
db9997b473 Pipelined multiplier: 3-stage LUT-based replaces shift_add, FSM simplified to 2-state 2026-06-25 22:09:20 +08:00
b3c0db19b9 Fix CRC32: use combinational stream_valid (was stuck-high causing repeated processing) 2026-06-25 20:53:56 +08:00
f8459f2478 Hardware CRC32 engine in matmul IP: 4-byte/cycle combinational, register at 0x010 2026-06-25 20:40:08 +08:00
956cd67773 Interrupt-driven wait: matmul HWI2 + DMA HWI1 direct CPU lines 2026-06-25 20:03:53 +08:00
57ba5d271d Remove all debug and printf 2026-06-25 15:44:18 +08:00
4aba830a7d Add for B1_C read channel 2026-06-25 04:04:18 +08:00
b5ec0d2926 Fix escaped quotes in display 2026-06-25 03:45:18 +08:00
9c6b321d59 Add in read channel to debug C register readback 2026-06-25 03:44:54 +08:00
3fb93131e5 Simplify ACCUM debug: show expression value only 2026-06-25 03:43:46 +08:00
86eab428a7 Use parenthesized pairwise addition to prevent synthesis truncation 2026-06-25 03:41:58 +08:00