From 9c08273c5f77ec734732f06f86dc38d501314d23 Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Sun, 28 Jun 2026 16:27:00 +0800 Subject: [PATCH] refactor(kg): registered read-ahead for ST_M load (bank_a + bank_se) Second per-consumer step of stage 2b. m_ld becomes a read-ahead pointer; both poly_mul load reads (bank_a A_hat, bank_se s_hat) are registered into pm_a_rd/pm_b_rd and fed one cycle later (pm_valid delayed 1 cyc), same pattern as ST_N. 11/11 KAT PASS, byte-exact. --- sync_rtl/top/mlkem_top.v | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/sync_rtl/top/mlkem_top.v b/sync_rtl/top/mlkem_top.v index 5fe295c..fe81a4f 100644 --- a/sync_rtl/top/mlkem_top.v +++ b/sync_rtl/top/mlkem_top.v @@ -483,11 +483,14 @@ module mlkem_top #( wire [11:0] pm_coeff; wire pm_vo; // pm_a: A_hat[i][j] in bank_a (abs slot m_aslot). pm_b: s_hat[j] in - // bank_se (relative slot = m_sslot - slot_s_rt = m_j). + // bank_se (relative slot = m_sslot - slot_s_rt = m_j). m_ld is a read-ahead + // pointer; both bank reads are registered into pm_a_rd/pm_b_rd and fed to + // poly_mul one cycle later (pm_valid delayed 1 cyc), like ST_N. wire [13:0] pm_a_full = m_aslot*256 + m_ld[7:0]; wire [13:0] pm_b_full = m_j*256 + m_ld[7:0]; - wire [11:0] pm_a_in = bank_a [pm_a_full[PA_AW-1:0]]; - wire [11:0] pm_b_in = bank_se[pm_b_full[PSE_AW-1:0]]; + reg [11:0] pm_a_rd, pm_b_rd; // registered bank reads (sd_bram timing) + wire [11:0] pm_a_in = pm_a_rd; + wire [11:0] pm_b_in = pm_b_rd; poly_mul_sync u_pmul ( .clk(clk), .rst_n(rst_n), @@ -561,6 +564,8 @@ module mlkem_top #( m_loading <= 1'b0; m_pending <= 1'b0; pm_valid <= 1'b0; + pm_a_rd <= 12'd0; + pm_b_rd <= 12'd0; e_poly <= 3'd0; e_pair <= 8'd0; e_byte <= 2'd0; @@ -732,7 +737,9 @@ module mlkem_top #( end end - // Arm M stage when N finishes: start first (i=0,j=0) poly_mul load + // Arm M stage when N finishes: prime first (i=0,j=0) poly_mul load. + // m_ld read-ahead pointer; pm_a_rd/pm_b_rd registered, pm_valid + // asserted one cycle after an address is presented (like ST_N). if (st == ST_N && st_next == ST_M) begin m_i <= 2'd0; m_j <= 2'd0; @@ -740,20 +747,26 @@ module mlkem_top #( m_oidx <= 8'd0; m_loading <= 1'b1; m_pending <= 1'b0; - pm_valid <= 1'b1; + pm_valid <= 1'b0; end // ---- ST_M: t_hat[i] = e_hat[i] + sum_j A[i][j] o s_hat[j] ---- if (st == ST_M) begin - // LOAD: stream 256 (A,shat) pairs into poly_mul - if (m_loading && pm_valid && pm_ready) begin - if (m_ld == 9'd255) begin - pm_valid <= 1'b0; // last pair presented + // LOAD: present read-ahead addr to bank_a/bank_se; the pair + // registered last cycle (pm_a_rd/pm_b_rd) is consumed by + // poly_mul this cycle (pm_valid). poly_mul holds ready high + // through LOAD, so a fixed 1-cycle skew suffices. + if (m_loading) begin + if (m_ld == 9'd256) begin + pm_valid <= 1'b0; // 256th pair consumed this cycle m_loading <= 1'b0; m_ld <= 9'd0; m_oidx <= 8'd0; end else begin - m_ld <= m_ld + 9'd1; + pm_a_rd <= bank_a [pm_a_full[PA_AW-1:0]]; + pm_b_rd <= bank_se[pm_b_full[PSE_AW-1:0]]; + m_ld <= m_ld + 9'd1; + pm_valid <= 1'b1; // pair presented last cycle is valid end end @@ -776,12 +789,12 @@ module mlkem_top #( end end - // Start next (i,j) poly_mul load once core is IDLE again + // Start next (i,j) poly_mul load once core is IDLE again (re-prime) if (m_pending && pm_ready && !pm_vo) begin - pm_valid <= 1'b1; m_loading <= 1'b1; m_ld <= 9'd0; m_oidx <= 8'd0; + pm_valid <= 1'b0; m_pending <= 1'b0; end end