mlkem test diagnostics and allocator updates

This commit is contained in:
2026-07-08 02:35:56 +08:00
parent 65607badd2
commit 0c85a20b4e
40 changed files with 37168 additions and 2093 deletions

View File

@@ -4,13 +4,15 @@
// maps do not overlap:
// ML-KEM: 0x0000..0x3fff
// FFT: 0x8000..0xcfff
// PRNG: 0xd000..0xd0ff
// Route the low ML-KEM block to ML-KEM, the high FFT block to FFT, and the
// following 0xdxxx block to PRNG.
// Route the low ML-KEM block to ML-KEM and the remaining accelerator window to
// FFT.
module fft_mlkem_axi_slave (
input clk,
input resetn,
input mlkem_clk,
input mlkem_resetn,
input [4:0] s_axi_awid,
input [31:0] s_axi_awaddr,
input [7:0] s_axi_awlen,
@@ -58,17 +60,12 @@ module fft_mlkem_axi_slave (
localparam SEL_MLKEM = 2'd0;
localparam SEL_FFT = 2'd1;
localparam SEL_PRNG = 2'd2;
wire aw_to_mlkem = (s_axi_awaddr[15:12] <= 4'h3);
wire aw_to_prng = (s_axi_awaddr[15:12] == 4'hd);
wire ar_to_mlkem = (s_axi_araddr[15:12] <= 4'h3);
wire ar_to_prng = (s_axi_araddr[15:12] == 4'hd);
wire [1:0] aw_sel = aw_to_mlkem ? SEL_MLKEM :
aw_to_prng ? SEL_PRNG : SEL_FFT;
wire [1:0] ar_sel = ar_to_mlkem ? SEL_MLKEM :
ar_to_prng ? SEL_PRNG : SEL_FFT;
wire [1:0] aw_sel = aw_to_mlkem ? SEL_MLKEM : SEL_FFT;
wire [1:0] ar_sel = ar_to_mlkem ? SEL_MLKEM : SEL_FFT;
reg [1:0] write_sel;
reg write_active;
@@ -83,6 +80,44 @@ module fft_mlkem_axi_slave (
wire [31:0] mlkem_rdata;
wire [1:0] mlkem_rresp;
wire mlkem_m_awvalid;
wire mlkem_m_awready;
wire [31:0] mlkem_m_awaddr;
wire [4:0] mlkem_m_awid;
wire [7:0] mlkem_m_awlen;
wire [2:0] mlkem_m_awsize;
wire [1:0] mlkem_m_awburst;
wire [0:0] mlkem_m_awlock;
wire [3:0] mlkem_m_awcache;
wire [2:0] mlkem_m_awprot;
wire mlkem_m_wvalid;
wire mlkem_m_wready;
wire [31:0] mlkem_m_wdata;
wire [3:0] mlkem_m_wstrb;
wire mlkem_m_wlast;
wire mlkem_m_bvalid;
wire mlkem_m_bready;
wire [4:0] mlkem_m_bid;
wire [1:0] mlkem_m_bresp;
wire mlkem_m_arvalid;
wire mlkem_m_arready;
wire [31:0] mlkem_m_araddr;
wire [4:0] mlkem_m_arid;
wire [7:0] mlkem_m_arlen;
wire [2:0] mlkem_m_arsize;
wire [1:0] mlkem_m_arburst;
wire [0:0] mlkem_m_arlock;
wire [3:0] mlkem_m_arcache;
wire [2:0] mlkem_m_arprot;
wire mlkem_m_rvalid;
wire mlkem_m_rready;
wire [31:0] mlkem_m_rdata;
wire [4:0] mlkem_m_rid;
wire [1:0] mlkem_m_rresp;
wire mlkem_m_rlast;
wire mlkem_intr_m;
(* async_reg = "true" *) reg [1:0] mlkem_intr_sync;
wire fft_awready, fft_wready, fft_bvalid;
wire [4:0] fft_bid;
wire [1:0] fft_bresp;
@@ -91,52 +126,33 @@ module fft_mlkem_axi_slave (
wire [31:0] fft_rdata;
wire [1:0] fft_rresp;
wire prng_awready, prng_wready, prng_bvalid;
wire [4:0] prng_bid;
wire [1:0] prng_bresp;
wire prng_arready, prng_rvalid, prng_rlast;
wire [4:0] prng_rid;
wire [31:0] prng_rdata;
wire [1:0] prng_rresp;
wire [1:0] sel_w = write_active ? write_sel : aw_sel;
wire [1:0] sel_r = read_active ? read_sel : ar_sel;
assign s_axi_awready = !write_active && (
(aw_sel == SEL_MLKEM) ? mlkem_awready :
(aw_sel == SEL_PRNG) ? prng_awready :
fft_awready);
assign s_axi_wready = (sel_w == SEL_MLKEM) ? mlkem_wready :
(sel_w == SEL_PRNG) ? prng_wready :
fft_wready;
assign s_axi_bvalid = (sel_w == SEL_MLKEM) ? mlkem_bvalid :
(sel_w == SEL_PRNG) ? prng_bvalid :
fft_bvalid;
assign s_axi_bid = (sel_w == SEL_MLKEM) ? mlkem_bid :
(sel_w == SEL_PRNG) ? prng_bid :
fft_bid;
assign s_axi_bresp = (sel_w == SEL_MLKEM) ? mlkem_bresp :
(sel_w == SEL_PRNG) ? prng_bresp :
fft_bresp;
assign s_axi_arready = !read_active && (
(ar_sel == SEL_MLKEM) ? mlkem_arready :
(ar_sel == SEL_PRNG) ? prng_arready :
fft_arready);
assign s_axi_rvalid = (sel_r == SEL_MLKEM) ? mlkem_rvalid :
(sel_r == SEL_PRNG) ? prng_rvalid :
fft_rvalid;
assign s_axi_rlast = (sel_r == SEL_MLKEM) ? mlkem_rlast :
(sel_r == SEL_PRNG) ? prng_rlast :
fft_rlast;
assign s_axi_rid = (sel_r == SEL_MLKEM) ? mlkem_rid :
(sel_r == SEL_PRNG) ? prng_rid :
fft_rid;
assign s_axi_rdata = (sel_r == SEL_MLKEM) ? mlkem_rdata :
(sel_r == SEL_PRNG) ? prng_rdata :
fft_rdata;
assign s_axi_rresp = (sel_r == SEL_MLKEM) ? mlkem_rresp :
(sel_r == SEL_PRNG) ? prng_rresp :
fft_rresp;
always @(posedge clk or negedge resetn) begin
@@ -162,52 +178,140 @@ module fft_mlkem_axi_slave (
end
end
always @(posedge clk or negedge resetn) begin
if (!resetn)
mlkem_intr_sync <= 2'b00;
else
mlkem_intr_sync <= {mlkem_intr_sync[0], mlkem_intr_m};
end
assign mlkem_intr = mlkem_intr_sync[1];
Axi_CDC u_mlkem_axi_cdc (
.axiInClk (clk),
.axiInRstn (resetn),
.axiOutClk (mlkem_clk),
.axiOutRstn (mlkem_resetn),
.axiIn_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_MLKEM)),
.axiIn_awready (mlkem_awready),
.axiIn_awaddr (s_axi_awaddr),
.axiIn_awid (s_axi_awid),
.axiIn_awlen (s_axi_awlen),
.axiIn_awsize (s_axi_awsize),
.axiIn_awburst (s_axi_awburst),
.axiIn_awlock (s_axi_awlock),
.axiIn_awcache (s_axi_awcache),
.axiIn_awprot (s_axi_awprot),
.axiIn_wvalid (s_axi_wvalid && (sel_w == SEL_MLKEM)),
.axiIn_wready (mlkem_wready),
.axiIn_wdata (s_axi_wdata),
.axiIn_wstrb (s_axi_wstrb),
.axiIn_wlast (s_axi_wlast),
.axiIn_bvalid (mlkem_bvalid),
.axiIn_bready (s_axi_bready && (sel_w == SEL_MLKEM)),
.axiIn_bid (mlkem_bid),
.axiIn_bresp (mlkem_bresp),
.axiIn_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_MLKEM)),
.axiIn_arready (mlkem_arready),
.axiIn_araddr (s_axi_araddr),
.axiIn_arid (s_axi_arid),
.axiIn_arlen (s_axi_arlen),
.axiIn_arsize (s_axi_arsize),
.axiIn_arburst (s_axi_arburst),
.axiIn_arlock (s_axi_arlock),
.axiIn_arcache (s_axi_arcache),
.axiIn_arprot (s_axi_arprot),
.axiIn_rvalid (mlkem_rvalid),
.axiIn_rready (s_axi_rready && (sel_r == SEL_MLKEM)),
.axiIn_rdata (mlkem_rdata),
.axiIn_rid (mlkem_rid),
.axiIn_rresp (mlkem_rresp),
.axiIn_rlast (mlkem_rlast),
.axiOut_awvalid (mlkem_m_awvalid),
.axiOut_awready (mlkem_m_awready),
.axiOut_awaddr (mlkem_m_awaddr),
.axiOut_awid (mlkem_m_awid),
.axiOut_awlen (mlkem_m_awlen),
.axiOut_awsize (mlkem_m_awsize),
.axiOut_awburst (mlkem_m_awburst),
.axiOut_awlock (mlkem_m_awlock),
.axiOut_awcache (mlkem_m_awcache),
.axiOut_awprot (mlkem_m_awprot),
.axiOut_wvalid (mlkem_m_wvalid),
.axiOut_wready (mlkem_m_wready),
.axiOut_wdata (mlkem_m_wdata),
.axiOut_wstrb (mlkem_m_wstrb),
.axiOut_wlast (mlkem_m_wlast),
.axiOut_bvalid (mlkem_m_bvalid),
.axiOut_bready (mlkem_m_bready),
.axiOut_bid (mlkem_m_bid),
.axiOut_bresp (mlkem_m_bresp),
.axiOut_arvalid (mlkem_m_arvalid),
.axiOut_arready (mlkem_m_arready),
.axiOut_araddr (mlkem_m_araddr),
.axiOut_arid (mlkem_m_arid),
.axiOut_arlen (mlkem_m_arlen),
.axiOut_arsize (mlkem_m_arsize),
.axiOut_arburst (mlkem_m_arburst),
.axiOut_arlock (mlkem_m_arlock),
.axiOut_arcache (mlkem_m_arcache),
.axiOut_arprot (mlkem_m_arprot),
.axiOut_rvalid (mlkem_m_rvalid),
.axiOut_rready (mlkem_m_rready),
.axiOut_rdata (mlkem_m_rdata),
.axiOut_rid (mlkem_m_rid),
.axiOut_rresp (mlkem_m_rresp),
.axiOut_rlast (mlkem_m_rlast)
);
mlkem_axi_slave u_mlkem_axi_slave (
.clk (clk),
.resetn (resetn),
.clk (mlkem_clk),
.resetn (mlkem_resetn),
.s_axi_awid (s_axi_awid),
.s_axi_awaddr (s_axi_awaddr),
.s_axi_awlen (s_axi_awlen),
.s_axi_awsize (s_axi_awsize),
.s_axi_awburst (s_axi_awburst),
.s_axi_awlock (s_axi_awlock),
.s_axi_awcache (s_axi_awcache),
.s_axi_awprot (s_axi_awprot),
.s_axi_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_MLKEM)),
.s_axi_awready (mlkem_awready),
.s_axi_awid (mlkem_m_awid),
.s_axi_awaddr (mlkem_m_awaddr),
.s_axi_awlen (mlkem_m_awlen),
.s_axi_awsize (mlkem_m_awsize),
.s_axi_awburst (mlkem_m_awburst),
.s_axi_awlock (mlkem_m_awlock[0]),
.s_axi_awcache (mlkem_m_awcache),
.s_axi_awprot (mlkem_m_awprot),
.s_axi_awvalid (mlkem_m_awvalid),
.s_axi_awready (mlkem_m_awready),
.s_axi_wid (s_axi_wid),
.s_axi_wdata (s_axi_wdata),
.s_axi_wstrb (s_axi_wstrb),
.s_axi_wlast (s_axi_wlast),
.s_axi_wvalid (s_axi_wvalid && (sel_w == SEL_MLKEM)),
.s_axi_wready (mlkem_wready),
.s_axi_wid (5'd0),
.s_axi_wdata (mlkem_m_wdata),
.s_axi_wstrb (mlkem_m_wstrb),
.s_axi_wlast (mlkem_m_wlast),
.s_axi_wvalid (mlkem_m_wvalid),
.s_axi_wready (mlkem_m_wready),
.s_axi_bid (mlkem_bid),
.s_axi_bresp (mlkem_bresp),
.s_axi_bvalid (mlkem_bvalid),
.s_axi_bready (s_axi_bready && (sel_w == SEL_MLKEM)),
.s_axi_bid (mlkem_m_bid),
.s_axi_bresp (mlkem_m_bresp),
.s_axi_bvalid (mlkem_m_bvalid),
.s_axi_bready (mlkem_m_bready),
.s_axi_arid (s_axi_arid),
.s_axi_araddr (s_axi_araddr),
.s_axi_arlen (s_axi_arlen),
.s_axi_arsize (s_axi_arsize),
.s_axi_arburst (s_axi_arburst),
.s_axi_arlock (s_axi_arlock),
.s_axi_arcache (s_axi_arcache),
.s_axi_arprot (s_axi_arprot),
.s_axi_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_MLKEM)),
.s_axi_arready (mlkem_arready),
.s_axi_arid (mlkem_m_arid),
.s_axi_araddr (mlkem_m_araddr),
.s_axi_arlen (mlkem_m_arlen),
.s_axi_arsize (mlkem_m_arsize),
.s_axi_arburst (mlkem_m_arburst),
.s_axi_arlock (mlkem_m_arlock[0]),
.s_axi_arcache (mlkem_m_arcache),
.s_axi_arprot (mlkem_m_arprot),
.s_axi_arvalid (mlkem_m_arvalid),
.s_axi_arready (mlkem_m_arready),
.s_axi_rid (mlkem_rid),
.s_axi_rdata (mlkem_rdata),
.s_axi_rresp (mlkem_rresp),
.s_axi_rlast (mlkem_rlast),
.s_axi_rvalid (mlkem_rvalid),
.s_axi_rready (s_axi_rready && (sel_r == SEL_MLKEM)),
.s_axi_rid (mlkem_m_rid),
.s_axi_rdata (mlkem_m_rdata),
.s_axi_rresp (mlkem_m_rresp),
.s_axi_rlast (mlkem_m_rlast),
.s_axi_rvalid (mlkem_m_rvalid),
.s_axi_rready (mlkem_m_rready),
.intr (mlkem_intr)
.intr (mlkem_intr_m)
);
fft_controller u_fft_controller (
@@ -258,50 +362,4 @@ module fft_mlkem_axi_slave (
.fft_finish (fft_finish)
);
prng_axi_slave u_prng_axi_slave (
.clk (clk),
.resetn (resetn),
.s_axi_awid (s_axi_awid),
.s_axi_awaddr (s_axi_awaddr),
.s_axi_awlen (s_axi_awlen),
.s_axi_awsize (s_axi_awsize),
.s_axi_awburst (s_axi_awburst),
.s_axi_awlock (s_axi_awlock),
.s_axi_awcache (s_axi_awcache),
.s_axi_awprot (s_axi_awprot),
.s_axi_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_PRNG)),
.s_axi_awready (prng_awready),
.s_axi_wid (s_axi_wid),
.s_axi_wdata (s_axi_wdata),
.s_axi_wstrb (s_axi_wstrb),
.s_axi_wlast (s_axi_wlast),
.s_axi_wvalid (s_axi_wvalid && (sel_w == SEL_PRNG)),
.s_axi_wready (prng_wready),
.s_axi_bid (prng_bid),
.s_axi_bresp (prng_bresp),
.s_axi_bvalid (prng_bvalid),
.s_axi_bready (s_axi_bready && (sel_w == SEL_PRNG)),
.s_axi_arid (s_axi_arid),
.s_axi_araddr (s_axi_araddr),
.s_axi_arlen (s_axi_arlen),
.s_axi_arsize (s_axi_arsize),
.s_axi_arburst (s_axi_arburst),
.s_axi_arlock (s_axi_arlock),
.s_axi_arcache (s_axi_arcache),
.s_axi_arprot (s_axi_arprot),
.s_axi_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_PRNG)),
.s_axi_arready (prng_arready),
.s_axi_rid (prng_rid),
.s_axi_rdata (prng_rdata),
.s_axi_rresp (prng_rresp),
.s_axi_rlast (prng_rlast),
.s_axi_rvalid (prng_rvalid),
.s_axi_rready (s_axi_rready && (sel_r == SEL_PRNG))
);
endmodule

View File

@@ -1,16 +1,13 @@
// mlkem_axi_slave.v — AXI4 (burst) slave wrapper for the ML-KEM core.
// Makes the ML-KEM accelerator (KeyGen / Encaps / Decaps) CPU-controllable.
//
// The bus runs at sys_clk (50 MHz). The ML-KEM core cannot close timing at
// 50 MHz, so it is clocked by mlkem_clk = sys_clk / 2 (25 MHz), produced by a
// toggle flip-flop in this wrapper. mlkem_clk is a phase-aligned synchronous
// divide of sys_clk; every signal crossing between the two domains still goes
// through an explicit synchronizer or toggle handshake.
// NOTE (FPGA): for real silicon route mlkem_clk through a BUFG/BUFGCE rather
// than a logic-generated net; kept as a plain toggle here for portability.
// This slave is placed behind an AXI clock-domain converter. Its AXI side and
// mlkem_top both run in mlkem_clk; sys_clk masters reach it through Axi_CDC in
// fft_mlkem_axi_slave.
//
// Register map (byte offsets from base, e.g. virtual 0xbf400000):
// 0x000 CTRL W bit0 = start (launches op selected in CONFIG)
// bit1 = soft_reset (resets ML-KEM core state)
// 0x004 STATUS R bit0 busy, bit1 done, bit2 preload_busy
// W1C write bit1=1 to clear the latched done flag
// 0x008 CONFIG RW [2:0] k (2/3/4), [5:4] op (0=KeyGen 1=Encaps 2=Decaps)
@@ -27,9 +24,11 @@
// 0x1000..0x1FFF EK W: preload ek_in, R: read generated ek
// 0x2000..0x2FFF DK W: preload dk_in, R: read generated full dk
// 0x3000..0x3FFF CT W: preload c_in, R: read generated ciphertext
(* use_dsp = "no" *)
module mlkem_axi_slave (
input clk, // sys_clk (AXI bus clock, 50 MHz)
input resetn, // sys_resetn (active low, already synchronized)
input clk, // mlkem_clk AXI-side clock after Axi_CDC
input resetn, // mlkem_resetn, active low
// AXI Write Address Channel
input [4:0] s_axi_awid,
@@ -153,20 +152,7 @@ module mlkem_axi_slave (
endfunction
// ==========================================
// mlkem_clk = sys_clk / 2 (25 MHz) via toggle FF.
// ==========================================
reg mlkem_clk;
always @(posedge clk or negedge resetn) begin
if (!resetn) mlkem_clk <= 1'b0;
else mlkem_clk <= ~mlkem_clk;
end
// Reset for the mlkem domain: reuse sys_resetn (async-assert, and the core's
// own rst_n is sampled on mlkem_clk edges).
wire mlkem_rstn = resetn;
// ==========================================
// sys_clk-domain config / data registers (quasi-static; fed to the core
// combinationally — written long before start, stable across the op).
// AXI/core clock-domain config / data registers.
// ==========================================
reg [2:0] cfg_k; // 2/3/4
reg [1:0] cfg_op; // 0=KeyGen 1=Encaps 2=Decaps
@@ -188,55 +174,79 @@ module mlkem_axi_slave (
reg [11:0] rdb_addr; // output byte index
// ==========================================
// CDC: start pulse (sys toggle -> mlkem edge-detect -> 1-cyc start_i)
// Start pulse: CTRL.start flips a toggle, edge-detected into start_i.
// ==========================================
reg start_tg; // sys-domain toggle, flips on CTRL.start write
reg [2:0] start_sync; // mlkem-domain 2FF sync (+1 for edge)
wire mlkem_start = start_sync[2] ^ start_sync[1]; // 1 mlkem_clk pulse
wire mlkem_start = start_sync[2] ^ start_sync[1]; // 1 clk pulse
// ==========================================
// CDC: busy / done back to sys
// Software reset pulse: CTRL.soft_reset flips a toggle and stretches reset.
// ==========================================
wire core_busy; // busy_o (mlkem domain)
wire core_done; // done_o pulse (mlkem domain)
reg done_latch; // sticky done in mlkem domain
reg [1:0] busy_sync; // -> sys
reg [1:0] done_sync; // -> sys
// done-clear: sys toggle -> mlkem edge -> clears done_latch
reg dclr_tg; // sys-domain toggle (STATUS W1C of done)
reg [2:0] dclr_sync; // mlkem-domain 2FF sync (+1 for edge)
reg srst_tg; // flips on CTRL.soft_reset
reg [2:0] srst_sync; // edge detector shift register
reg [3:0] srst_cnt; // reset stretcher in clk domain
wire mlkem_srst_edge = srst_sync[2] ^ srst_sync[1];
wire mlkem_srst_active = (srst_cnt != 4'd0);
wire core_resetn = resetn && !mlkem_srst_active;
// ==========================================
// Busy / done status.
// ==========================================
wire core_busy;
wire core_done;
reg done_latch;
reg [1:0] busy_sync;
reg [1:0] done_sync;
// done-clear: STATUS W1C flips a toggle, edge-detected to clear done_latch.
reg dclr_tg;
reg [2:0] dclr_sync;
wire mlkem_dclr = dclr_sync[2] ^ dclr_sync[1];
// ==========================================
// CDC: preload byte write handshake.
// sys: latch {sel,addr,byte}, flip pre_req_tg, hold wready low.
// mlkem: 2FF sync pre_req_tg, on edge pulse the selected *_in_we 1 cycle,
// flip pre_ack_tg.
// sys: 2FF sync pre_ack_tg, on edge release the bus (addr++).
// Preload byte write handshake.
// Latch {sel,addr,byte}, flip pre_req_tg, pulse the selected *_in_we for
// one cycle, then flip pre_ack_tg to release the AXI write beat.
// ==========================================
reg pre_req_tg; // sys toggle: a byte is pending
reg [2:0] pre_req_sync; // mlkem 2FF (+1 for edge)
reg pre_req_tg; // a byte is pending
reg [2:0] pre_req_sync; // edge detector shift register
wire mlkem_pre_we = pre_req_sync[2] ^ pre_req_sync[1];
reg pre_ack_tg; // mlkem toggle: byte consumed
reg [2:0] pre_ack_sync; // sys 2FF (+1 for edge)
reg pre_ack_tg; // byte consumed
reg [2:0] pre_ack_sync; // edge detector shift register
wire pre_ack_edge = pre_ack_sync[2] ^ pre_ack_sync[1];
reg pre_busy; // sys: a preload handshake is in flight
// latched byte/port for the in-flight preload (sys, stable while pre_busy)
reg pre_busy; // a preload handshake is in flight
// latched byte/port for the in-flight preload, stable while pre_busy
reg [1:0] pre_sel_l;
reg [11:0] pre_addr_l;
reg [7:0] pre_byte_l;
reg pre_auto_inc_l;
// ==========================================
// Bulk readback byte handshake.
// Hold {sel,addr}, flip rdb_req_tg, let the BRAM read settle, latch one
// byte, then flip rdb_ack_tg.
// ==========================================
reg rdb_req_tg; // one readback byte request
reg [2:0] rdb_req_sync; // edge detector shift register
wire mlkem_rdb_req = rdb_req_sync[2] ^ rdb_req_sync[1];
reg rdb_ack_tg; // readback byte ready
reg [2:0] rdb_ack_sync; // edge detector shift register
wire rdb_ack_edge = rdb_ack_sync[2] ^ rdb_ack_sync[1];
reg [1:0] rdb_req_sel_l; // stable while request in flight
reg [11:0] rdb_req_addr_l; // stable while request in flight
reg [1:0] rdb_sel_m; // captured request
reg [11:0] rdb_addr_m; // captured request
reg [1:0] rdb_wait_m; // waits for BRAM registered read
reg rdb_busy_m;
reg [7:0] rdb_data_m; // held stable until next ack
// ==========================================
// mlkem_top instance
// ==========================================
wire [7:0] dbg_byte_o, dbg_dk_o, dbg_ct_o;
wire [255:0] ss_o;
wire bulk_read_active;
wire [1:0] bulk_rdb_sel;
wire [11:0] bulk_rdb_addr;
wire [1:0] eff_rdb_sel = bulk_read_active ? bulk_rdb_sel : rdb_sel;
wire [11:0] eff_rdb_addr = bulk_read_active ? bulk_rdb_addr : rdb_addr;
wire [1:0] eff_rdb_sel = rdb_busy_m ? rdb_sel_m : rdb_sel;
wire [11:0] eff_rdb_addr = rdb_busy_m ? rdb_addr_m : rdb_addr;
wire dbg_byte_sel = (eff_rdb_sel == 2'd1); // 0=ek, 1=dk_pke
// The core's ek/dkp read-address muxes give dbg_dk_idx_i priority over
// dbg_byte_idx_i whenever it lands in the ek (768..1567) or dk_pke (<768)
@@ -245,21 +255,20 @@ module mlkem_axi_slave (
// it out of range (0xFFF) so an ek/dk_pke readback isn't corrupted.
wire [11:0] dbg_dk_idx = (eff_rdb_sel == 2'd2) ? eff_rdb_addr : 12'hFFF;
// one-cycle write-enable pulses into the core (combinational off the synced
// edge; pre_sel_l/pre_addr_l/pre_byte_l are stable in sys, sampled by core).
wire ek_in_we = mlkem_pre_we && (pre_sel_l == 2'd0);
wire dk_in_we = mlkem_pre_we && (pre_sel_l == 2'd1);
wire c_in_we = mlkem_pre_we && (pre_sel_l == 2'd2);
// one-cycle write-enable pulses into the core.
wire ek_in_we = core_resetn && mlkem_pre_we && (pre_sel_l == 2'd0);
wire dk_in_we = core_resetn && mlkem_pre_we && (pre_sel_l == 2'd1);
wire c_in_we = core_resetn && mlkem_pre_we && (pre_sel_l == 2'd2);
mlkem_top #(.KMAX(4)) u_mlkem (
.clk (mlkem_clk),
.rst_n (mlkem_rstn),
.clk (clk),
.rst_n (core_resetn),
.k_i (cfg_k),
.op_i (cfg_op),
.d_i (d_bus),
.z_i (z_bus),
.msg_i (msg_bus),
.start_i (mlkem_start),
.start_i (core_resetn ? mlkem_start : 1'b0),
.busy_o (core_busy),
.done_o (core_done),
// ek preload
@@ -302,44 +311,82 @@ module mlkem_axi_slave (
);
// ==========================================
// mlkem_clk domain: synchronizers, done latch, preload-ack toggle.
// Core/AXI clock domain: edge detectors, done latch, preload/readback acks.
// ==========================================
always @(posedge mlkem_clk or negedge mlkem_rstn) begin
if (!mlkem_rstn) begin
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
start_sync <= 3'd0;
srst_sync <= 3'd0;
srst_cnt <= 4'd0;
dclr_sync <= 3'd0;
pre_req_sync <= 3'd0;
pre_ack_tg <= 1'b0;
rdb_req_sync <= 3'd0;
rdb_ack_tg <= 1'b0;
rdb_sel_m <= 2'd0;
rdb_addr_m <= 12'd0;
rdb_wait_m <= 2'd0;
rdb_busy_m <= 1'b0;
rdb_data_m <= 8'd0;
done_latch <= 1'b0;
end else begin
// 2FF (+edge) synchronizers of sys-domain toggles
// Edge-detect request toggles.
start_sync <= {start_sync[1:0], start_tg};
srst_sync <= {srst_sync[1:0], srst_tg};
dclr_sync <= {dclr_sync[1:0], dclr_tg};
pre_req_sync <= {pre_req_sync[1:0], pre_req_tg};
rdb_req_sync <= {rdb_req_sync[1:0], rdb_req_tg};
if (mlkem_srst_edge)
srst_cnt <= 4'd8;
else if (srst_cnt != 4'd0)
srst_cnt <= srst_cnt - 4'd1;
// acknowledge a consumed preload byte (write-enable pulsed this cycle)
if (mlkem_pre_we) pre_ack_tg <= ~pre_ack_tg;
if (core_resetn && mlkem_pre_we) pre_ack_tg <= ~pre_ack_tg;
if (!core_resetn) begin
rdb_wait_m <= 2'd0;
rdb_busy_m <= 1'b0;
end else if (mlkem_rdb_req) begin
rdb_sel_m <= rdb_req_sel_l;
rdb_addr_m <= rdb_req_addr_l;
rdb_wait_m <= 2'd2;
rdb_busy_m <= 1'b1;
end else if (rdb_wait_m != 2'd0) begin
if (rdb_wait_m == 2'd1) begin
rdb_data_m <= rdb_byte;
rdb_ack_tg <= ~rdb_ack_tg;
rdb_wait_m <= 2'd0;
rdb_busy_m <= 1'b0;
end else begin
rdb_wait_m <= rdb_wait_m - 2'd1;
end
end
// sticky done: set on the core's done_o pulse, cleared by synced W1C.
// (mlkem_start also clears it so a new run starts with done low.)
if (core_done) done_latch <= 1'b1;
if (mlkem_srst_active) done_latch <= 1'b0;
else if (core_done) done_latch <= 1'b1;
else if (mlkem_dclr) done_latch <= 1'b0;
else if (mlkem_start) done_latch <= 1'b0;
end
end
// ==========================================
// sys_clk domain: sync busy/done/preload-ack back from mlkem.
// AXI clock domain: register status and acknowledge toggles.
// ==========================================
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
busy_sync <= 2'd0;
done_sync <= 2'd0;
pre_ack_sync <= 3'd0;
rdb_ack_sync <= 3'd0;
end else begin
busy_sync <= {busy_sync[0], core_busy};
busy_sync <= {busy_sync[0], core_busy | mlkem_srst_active};
done_sync <= {done_sync[0], done_latch};
pre_ack_sync <= {pre_ack_sync[1:0], pre_ack_tg};
rdb_ack_sync <= {rdb_ack_sync[1:0], rdb_ack_tg};
end
end
wire status_busy = busy_sync[1];
@@ -389,6 +436,7 @@ module mlkem_axi_slave (
rdb_sel <= 2'd0;
rdb_addr <= 12'd0;
start_tg <= 1'b0;
srst_tg <= 1'b0;
dclr_tg <= 1'b0;
pre_req_tg <= 1'b0;
pre_busy <= 1'b0;
@@ -453,8 +501,10 @@ module mlkem_axi_slave (
end else begin
// normal single-cycle register write
case (1'b1)
(w_offset == ADDR_CTRL):
(w_offset == ADDR_CTRL): begin
if (s_axi_wdata[0]) start_tg <= ~start_tg;
if (s_axi_wdata[1]) srst_tg <= ~srst_tg;
end
(w_offset == ADDR_STATUS):
if (s_axi_wdata[1]) dclr_tg <= ~dclr_tg; // clear done
(w_offset == ADDR_CONFIG): begin
@@ -541,7 +591,6 @@ module mlkem_axi_slave (
localparam R_IDLE = 3'd0;
localparam R_DATA = 3'd1;
localparam R_BULK_WAIT = 3'd2;
localparam RDB_WAIT_CYCLES = 3'd4;
reg [2:0] r_state;
reg [31:0] r_addr;
@@ -557,13 +606,8 @@ module mlkem_axi_slave (
reg [1:0] bulk_sel_r;
reg [11:0] bulk_addr_r;
reg [1:0] bulk_lane;
reg [2:0] bulk_wait;
reg [31:0] bulk_word;
assign bulk_read_active = r_bulk && (r_state == R_BULK_WAIT);
assign bulk_rdb_sel = bulk_sel_r;
assign bulk_rdb_addr = bulk_addr_r;
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
r_state <= R_IDLE;
@@ -579,8 +623,10 @@ module mlkem_axi_slave (
bulk_sel_r <= 2'd0;
bulk_addr_r <= 12'd0;
bulk_lane <= 2'd0;
bulk_wait <= 3'd0;
bulk_word <= 32'd0;
rdb_req_tg <= 1'b0;
rdb_req_sel_l <= 2'd0;
rdb_req_addr_l <= 12'd0;
end else begin
case (r_state)
R_IDLE: begin
@@ -597,8 +643,10 @@ module mlkem_axi_slave (
bulk_sel_r <= window_readback_sel(s_axi_araddr[15:12]);
bulk_addr_r <= s_axi_araddr[11:0];
bulk_lane <= 2'd0;
bulk_wait <= RDB_WAIT_CYCLES;
bulk_word <= 32'd0;
rdb_req_sel_l <= window_readback_sel(s_axi_araddr[15:12]);
rdb_req_addr_l <= s_axi_araddr[11:0];
rdb_req_tg <= ~rdb_req_tg;
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
r_state <= R_BULK_WAIT;
@@ -610,14 +658,12 @@ module mlkem_axi_slave (
end
end
R_BULK_WAIT: begin
if (bulk_wait != 3'd0) begin
bulk_wait <= bulk_wait - 3'd1;
end else begin
if (rdb_ack_edge) begin
case (bulk_lane)
2'd0: bulk_word[7:0] <= rdb_byte;
2'd1: bulk_word[15:8] <= rdb_byte;
2'd2: bulk_word[23:16] <= rdb_byte;
default: bulk_word[31:24] <= rdb_byte;
2'd0: bulk_word[7:0] <= rdb_data_m;
2'd1: bulk_word[15:8] <= rdb_data_m;
2'd2: bulk_word[23:16] <= rdb_data_m;
default: bulk_word[31:24] <= rdb_data_m;
endcase
if (bulk_lane == 2'd3) begin
@@ -627,7 +673,8 @@ module mlkem_axi_slave (
end else begin
bulk_lane <= bulk_lane + 2'd1;
bulk_addr_r <= bulk_addr_r + 12'd1;
bulk_wait <= RDB_WAIT_CYCLES;
rdb_req_addr_l <= bulk_addr_r + 12'd1;
rdb_req_tg <= ~rdb_req_tg;
end
end
end
@@ -645,8 +692,10 @@ module mlkem_axi_slave (
if (r_bulk) begin
bulk_addr_r <= (r_burst == 2'b01) ? (r_offset + 12'd4) : r_offset;
bulk_lane <= 2'd0;
bulk_wait <= RDB_WAIT_CYCLES;
bulk_word <= 32'd0;
rdb_req_sel_l <= bulk_sel_r;
rdb_req_addr_l <= (r_burst == 2'b01) ? (r_offset + 12'd4) : r_offset;
rdb_req_tg <= ~rdb_req_tg;
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
r_state <= R_BULK_WAIT;

File diff suppressed because it is too large Load Diff