This repository has been archived on 2026-08-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ciciec2026/rtl/ip/mlkem/sha3/keccak_core.v
FallenSigh 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

100 lines
3.5 KiB
Verilog

// keccak_core.v - Synchronous Keccak-f[1600] core with valid/ready
//
// Runs 24 rounds of keccak_round on the input state.
// valid_i high with ready_o high → load state_i, start 24-round sequence.
// Each round takes 1 cycle. After round 23, valid_o asserted with state_o.
//
// Parameter:
// ROUNDS = 24 (default)
//
// Interface:
// clk, rst_n - clock, active-low reset
// state_i - 1600-bit input state
// valid_i - start permutation
// ready_o - core can accept new input
// state_o - 1600-bit output state (after permutation)
// valid_o - output is valid
// ready_i - consumer accepts output
module keccak_core #(parameter ROUNDS = 24) (
input clk,
input rst_n,
input [1599:0] state_i,
input valid_i,
output ready_o,
output [1599:0] state_o,
output valid_o,
input ready_i
);
// ================================================================
// Internal registers
// ================================================================
reg busy_r; // 1 while running permutation
reg [4:0] cnt_r; // round counter (0 to ROUNDS-1)
reg [1599:0] state_r; // current state
// ================================================================
// Next-state logic
// ================================================================
wire cnt_is_last; // cnt_r == ROUNDS-1 ?
wire [1599:0] state_next; // combinational round output
assign cnt_is_last = (cnt_r == (ROUNDS - 1));
// keccak_round: apply one round to current state
keccak_round u_round (
.state_i(state_r),
.round_i(cnt_r),
.state_o(state_next)
);
// ================================================================
// Valid/ready handshake
// ================================================================
// ready_o: accept new input when not busy (or just finishing)
assign ready_o = !busy_r;
// valid_o: output valid when we just finished the last round
// (the final state is already in state_r at the output cycle)
assign valid_o = busy_r && cnt_is_last;
// state_o: output the final state
assign state_o = state_next; // final state from the last round
// ================================================================
// Sequential logic
// ================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
busy_r <= 1'b0;
cnt_r <= 5'd0;
state_r <= 1600'd0;
end else begin
if (!busy_r) begin
// IDLE: wait for valid_i
if (valid_i) begin
state_r <= state_i;
cnt_r <= 5'd0;
busy_r <= 1'b1;
end
end else begin
// BUSY: running permutations
if (cnt_is_last) begin
// Final round: check if output can be accepted
if (ready_i) begin
busy_r <= 1'b0;
cnt_r <= 5'd0;
end
// else: hold until ready_i
end else begin
// Intermediate round: advance state
state_r <= state_next;
cnt_r <= cnt_r + 5'd1;
end
end
end
end
endmodule