module multicrack ( input logic clk, input logic rst_n, input logic en, output logic rdy, output logic [23:0] key, output logic key_valid, output logic [7:0] ct_addr, input logic [7:0] ct_rddata ); localparam int NUM_CORES = 108; localparam int WINNER_W = $clog2(NUM_CORES); localparam logic [23:0] KEY_INCREMENT = 24'd108; logic c_en; logic [NUM_CORES-1:0] core_rdy, core_key_valid; logic [NUM_CORES-1:0][7:0] core_ct_addr; logic [NUM_CORES-1:0][7:0] core_pt_addr; logic [NUM_CORES-1:0][7:0] core_pt_rddata; logic [NUM_CORES-1:0][23:0] core_key; logic [NUM_CORES-1:0] ct_core_wren; logic [NUM_CORES-1:0][7:0] ct_core_addr; logic [NUM_CORES-1:0][7:0] ct_core_wrdata, ct_core_rddata; logic pt_wren; logic [7:0] pt_addr; logic [7:0] pt_wrdata, pt_rddata; logic [7:0] ct_copy_idx_d, ct_copy_idx_q; logic [7:0] pt_copy_idx_d, pt_copy_idx_q; logic [WINNER_W-1:0] winner_d, winner_q; logic all_cores_rdy; logic winning_core_valid; logic [WINNER_W-1:0] winning_core_idx; logic [23:0] winner_key; logic [7:0] winner_pt_rddata; typedef enum logic [2:0] { IDLE, CT_FETCH, CT_WRITE, CRACK_START, CRACK, PT_FETCH, PT_WRITE, DONE } state_t; state_t state_d, state_q; pt_mem pt ( .address(pt_addr), .clock(clk), .data(pt_wrdata), .wren(pt_wren), .q(pt_rddata) ); genvar i; generate for (i = 0; i < NUM_CORES; i++) begin : gen_cores ct_core_mem ct ( .address(ct_core_addr[i]), .clock(clk), .data(ct_core_wrdata[i]), .wren(ct_core_wren[i]), .q(ct_core_rddata[i]) ); crack #( .KeyStart(i), .KeyIncrement(KEY_INCREMENT) ) core ( .clk, .rst_n, .en(c_en), .rdy(core_rdy[i]), .key(core_key[i]), .key_valid(core_key_valid[i]), .ct_addr(core_ct_addr[i]), .ct_rddata(ct_core_rddata[i]), .pt_addr_ext(core_pt_addr[i]), .pt_rddata_ext(core_pt_rddata[i]) ); end endgenerate always_comb begin all_cores_rdy = 1'b1; winning_core_valid = 1'b0; winning_core_idx = '0; for (int j = 0; j < NUM_CORES; j++) begin all_cores_rdy &= core_rdy[j]; if (!winning_core_valid && core_rdy[j] && core_key_valid[j]) begin winning_core_valid = 1'b1; winning_core_idx = WINNER_W'(j); end end end assign winner_key = core_key[winner_q]; assign winner_pt_rddata = core_pt_rddata[winner_q]; always_ff @(posedge clk) begin if (~rst_n) begin state_q <= IDLE; ct_copy_idx_q <= '0; pt_copy_idx_q <= '0; winner_q <= '0; end else begin state_q <= state_d; ct_copy_idx_q <= ct_copy_idx_d; pt_copy_idx_q <= pt_copy_idx_d; winner_q <= winner_d; end end always_comb begin state_d = state_q; ct_copy_idx_d = ct_copy_idx_q; pt_copy_idx_d = pt_copy_idx_q; winner_d = winner_q; unique case (state_q) IDLE: begin if (en) begin state_d = CT_FETCH; ct_copy_idx_d = '0; pt_copy_idx_d = '0; winner_d = '0; end end CT_FETCH: state_d = CT_WRITE; CT_WRITE: begin if (ct_copy_idx_q == 8'hFF) begin state_d = CRACK_START; end else begin state_d = CT_FETCH; ct_copy_idx_d = ct_copy_idx_q + 8'd1; end end CRACK_START: begin if (all_cores_rdy) state_d = CRACK; end CRACK: begin if (winning_core_valid) begin state_d = PT_FETCH; pt_copy_idx_d = '0; winner_d = winning_core_idx; end else if (all_cores_rdy) begin state_d = DONE; end end PT_FETCH: state_d = PT_WRITE; PT_WRITE: begin if (pt_copy_idx_q == 8'hFF) begin state_d = DONE; end else begin state_d = PT_FETCH; pt_copy_idx_d = pt_copy_idx_q + 8'd1; end end DONE: state_d = DONE; default: state_d = IDLE; endcase end always_comb begin rdy = '0; key_valid = '0; key = '0; c_en = '0; ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; for (int j = 0; j < NUM_CORES; j++) begin ct_core_addr[j] = core_ct_addr[j]; ct_core_wrdata[j] = '0; ct_core_wren[j] = '0; core_pt_addr[j] = pt_copy_idx_q; end unique case (state_q) IDLE: rdy = '1; CT_FETCH: begin ct_addr = ct_copy_idx_q; end CT_WRITE: begin for (int j = 0; j < NUM_CORES; j++) begin ct_core_addr[j] = ct_copy_idx_q; ct_core_wrdata[j] = ct_rddata; ct_core_wren[j] = '1; end end CRACK_START: begin c_en = all_cores_rdy; end CRACK: begin end PT_FETCH: begin end PT_WRITE: begin pt_addr = pt_copy_idx_q; pt_wren = '1; pt_wrdata = winner_pt_rddata; end DONE: begin rdy = '1; if (core_key_valid[winner_q]) begin key_valid = '1; key = winner_key; end end default: begin end endcase end endmodule: multicrack