module prga ( input logic clk, input logic rst_n, input logic en, output logic rdy, input logic [23:0] key, output logic [7:0] s_addr, input logic [7:0] s_rddata, output logic [7:0] s_wrdata, output logic s_wren, output logic [7:0] ct_addr, input logic [7:0] ct_rddata, output logic [7:0] pt_addr, input logic [7:0] pt_rddata, output logic [7:0] pt_wrdata, output logic pt_wren ); logic [7:0] i_d, i_q, j_d, j_q, k_d, k_q, si_d, si_q, sj_d, sj_q; logic [7:0] length_d, length_q; enum logic [3:0] { INIT, SET_LENGTH, FETCH_I, FETCH_J, WRITE_I, WRITE_J, FETCH_PAD, WRITE_PT, DONE } state_d, state_q; always_comb begin: fsm_output_logic rdy = '0; i_d = i_q; j_d = j_q; k_d = k_q; si_d = si_q; sj_d = sj_q; length_d = length_q; unique case (state_q) INIT: begin rdy = '1; s_addr = '0; s_wrdata = '0; s_wren = '0; /* Fetch message length. */ ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end SET_LENGTH: begin length_d = ct_rddata; rdy = '0; s_addr = '0; s_wrdata = '0; s_wren = '0; ct_addr = '0; pt_addr = '0; pt_wrdata = ct_rddata; pt_wren = '1; end FETCH_I: begin i_d = i_q + 1'b1; rdy = '0; s_addr = i_d; s_wrdata = '0; s_wren = '0; ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end /* s_rddata now contains s[i]. */ FETCH_J: begin /* Calculate j. */ j_d = j_q + s_rddata; /* Save s[i]. */ si_d = s_rddata; rdy = '0; s_addr = j_d; s_wrdata = '0; s_wren = '0; ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end /* s_rddata now contains s[j]. */ WRITE_I: begin /* Save s[j]. */ sj_d = s_rddata; rdy = '0; s_addr = j_d; s_wrdata = si_q; s_wren = '1; ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end WRITE_J: begin rdy = '0; s_addr = i_d; s_wrdata = sj_q; s_wren = '1; ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end FETCH_PAD: begin rdy = '0; s_addr = si_q + sj_q; s_wrdata = '0; s_wren = '0; ct_addr = k_q; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end WRITE_PT: begin k_d = k_q + 1'b1; rdy = '0; s_addr = '0; s_wrdata = '0; s_wren = '0; ct_addr = '0; pt_addr = k_q; pt_wrdata = s_rddata ^ ct_rddata; pt_wren = '1; end DONE: begin rdy = '1; s_addr = '0; s_wrdata = '0; s_wren = '0; ct_addr = '0; pt_addr = '0; pt_wrdata = '0; pt_wren = '0; end default: begin end endcase end: fsm_output_logic always_comb begin: fsm_next_state_logic unique case (state_q) INIT: begin if (rdy && en) state_d = SET_LENGTH; else state_d = INIT; end SET_LENGTH: state_d = FETCH_I; FETCH_I: state_d = FETCH_J; FETCH_J: state_d = WRITE_I; WRITE_I: state_d = WRITE_J; WRITE_J: state_d = FETCH_PAD; FETCH_PAD: state_d = WRITE_PT; WRITE_PT: begin if (k_q == length_q) state_d = DONE; else state_d = FETCH_I; end DONE: state_d = DONE; default: state_d = INIT; endcase end: fsm_next_state_logic always_ff @(posedge clk) begin: fsm_reg if (~rst_n) begin state_q <= INIT; i_q <= '0; j_q <= '0; k_q <= 1'b1; si_q <= '0; sj_q <= '0; length_q <= '0; end else begin state_q <= state_d; i_q <= i_d; j_q <= j_d; k_q <= k_d; si_q <= si_d; sj_q <= sj_d; length_q <= length_d; end end: fsm_reg endmodule: prga