// keccak_arbiter.v - Fixed-priority arbiter for sharing a single keccak_core // // Allows N consumers (sha3_chain, sample_cbd, sample_ntt, sha3_top) to // share one keccak_core instance. Consumer 0 has highest priority — used // for sha3_chain which needs fast turnaround during KeyGen. // // State machine: // IDLE: Wait for any cons_valid_i. Grant to highest-priority consumer // (lowest index). Assert kc_valid_i to start permutation. // BUSY: Hold grant until kc_valid_o fires (permutation done), then // return to IDLE. cons_valid_o pulses for the granted consumer. // // Parameters: // NUM_CONSUMERS = 4 // // Interface: // Keccak side: kc_state_i/o, kc_valid_i/o, kc_ready_i/o (single instance) // Consumer side: packed per-consumer valid/ready/state vectors module keccak_arbiter #( parameter NUM_CONSUMERS = 4 ) ( input clk, input rst_n, // ── Keccak core side (single keccak_core instance) ────────────── output [1599:0] kc_state_i, output kc_valid_i, input kc_ready_o, input [1599:0] kc_state_o, input kc_valid_o, output kc_ready_i, // ── Consumer side (N copies, packed) ──────────────────────────── input [NUM_CONSUMERS*1600-1:0] cons_state_i, input [NUM_CONSUMERS-1:0] cons_valid_i, output [NUM_CONSUMERS-1:0] cons_ready_o, output [NUM_CONSUMERS*1600-1:0] cons_state_o, output [NUM_CONSUMERS-1:0] cons_valid_o, /* verilator lint_off UNUSEDSIGNAL */ input [NUM_CONSUMERS-1:0] cons_ready_i /* verilator lint_on UNUSEDSIGNAL */ ); // ================================================================ // State machine // ================================================================ localparam ST_IDLE = 1'b0; localparam ST_BUSY = 1'b1; reg state_r, state_next; // ================================================================ // Grant logic // ================================================================ localparam GRANT_W = $clog2(NUM_CONSUMERS); reg [GRANT_W-1:0] grant_r; // registered grant (held during BUSY) reg [GRANT_W-1:0] grant_comb; // priority-encoded index (combinational) // Any consumer requesting wire any_valid; assign any_valid = |cons_valid_i; // Priority encoder: consumer 0 has highest priority (lowest index). // Reverse iteration so last assignment wins → lowest-index priority. integer i; always @(*) begin grant_comb = {GRANT_W{1'b0}}; for (i = NUM_CONSUMERS - 1; i >= 0; i = i - 1) begin if (cons_valid_i[i]) begin /* verilator lint_off WIDTHTRUNC */ grant_comb = i; // intentional truncation: i ∈ [0,NUM_CONSUMERS-1] fits GRANT_W /* verilator lint_on WIDTHTRUNC */ end end end // Active grant: combinational in IDLE, registered (held) in BUSY wire [GRANT_W-1:0] active_grant; assign active_grant = (state_r == ST_IDLE) ? grant_comb : grant_r; // ================================================================ // FSM next-state logic // ================================================================ always @(*) begin state_next = state_r; case (state_r) ST_IDLE: if (kc_ready_o && any_valid) state_next = ST_BUSY; ST_BUSY: if (kc_valid_o) state_next = ST_IDLE; default: state_next = ST_IDLE; endcase end // ================================================================ // Sequential logic // ================================================================ always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state_r <= ST_IDLE; grant_r <= {GRANT_W{1'b0}}; end else begin state_r <= state_next; // Capture grant on IDLE→BUSY transition if (state_r == ST_IDLE && state_next == ST_BUSY) grant_r <= grant_comb; end end // ================================================================ // Keccak core side // ================================================================ // Route selected consumer's state to keccak assign kc_state_i = cons_state_i[active_grant * 1600 +: 1600]; // Start permutation when IDLE, keccak ready, and any consumer wants access assign kc_valid_i = (state_r == ST_IDLE) && kc_ready_o && any_valid; // Always accept keccak output (keccak_core's ready_i) assign kc_ready_i = 1'b1; // ================================================================ // Consumer side (generated per consumer) // ================================================================ genvar g; generate for (g = 0; g < NUM_CONSUMERS; g = g + 1) begin : gen_consumer // cons_ready_o: this consumer is granted AND keccak is ready assign cons_ready_o[g] = (active_grant == g) && any_valid && (state_r == ST_IDLE) && kc_ready_o; // cons_valid_o: this consumer was granted AND keccak finished assign cons_valid_o[g] = (grant_r == g) && kc_valid_o; // cons_state_o: broadcast keccak output to all consumers. // Each consumer latches only when its own valid_o is high. assign cons_state_o[g*1600 +: 1600] = kc_state_o; end endgenerate endmodule