blob: 3aac3f1838ee60f21cd4122a7025b2ef2df37fac [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* 39b General Purpose Register File (GPRs)
*
* 39b to support 32b register with 7b integrity. Integrity generation/checking implemented in
* wrapping otbn_rf_base module
*
* Features:
* - 2 read ports
* - 1 write port
*/
module otbn_rf_base_ff
import otbn_pkg::*;
#(
parameter logic [BaseIntgWidth-1:0] WordZeroVal = '0
) (
input logic clk_i,
input logic rst_ni,
input logic [4:0] wr_addr_i,
input logic wr_en_i,
input logic [BaseIntgWidth-1:0] wr_data_i,
input logic [4:0] rd_addr_a_i,
output logic [BaseIntgWidth-1:0] rd_data_a_o,
input logic [4:0] rd_addr_b_i,
output logic [BaseIntgWidth-1:0] rd_data_b_o,
// Indicates whether a spurious WE has been seen in the last cycle.
output logic we_err_o
);
logic [BaseIntgWidth-1:0] rf_reg [NGpr];
logic [31:0] we_onehot;
for (genvar i = 0; i < NGpr; i++) begin : g_we_onehot
assign we_onehot[i] = (wr_addr_i == i) && wr_en_i;
end
// No flops for register 0 as it's hard-wired to 0
assign rf_reg[0] = WordZeroVal;
// No flops for register 1 as it's call stack and handled in a different module.
assign rf_reg[1] = WordZeroVal;
// Generate flops for register 1 - NGpr
for (genvar i = 2; i < NGpr; i++) begin : g_rf_flops
logic [BaseIntgWidth-1:0] rf_reg_q;
always_ff @(posedge clk_i) begin
if(we_onehot[i]) begin
rf_reg_q <= wr_data_i;
end
end
assign rf_reg[i] = rf_reg_q;
end
assign rd_data_a_o = rf_reg[rd_addr_a_i];
assign rd_data_b_o = rf_reg[rd_addr_b_i];
// Buffer the decoded write enable bits so that the checker
// is not optimized into the address decoding logic.
logic [31:0] we_onehot_buf;
prim_buf #(
.Width(32)
) u_prim_buf (
.in_i(we_onehot),
.out_o(we_onehot_buf)
);
// SEC_CM: RF_BASE.DATA_REG_SW.GLITCH_DETECT
// This checks for spurious WE strobes on the regfile.
logic we_err;
prim_onehot_check #(
.AddrWidth(5),
.AddrCheck(1),
.EnableCheck(1)
) u_prim_onehot_check (
.clk_i,
.rst_ni,
.oh_i(we_onehot_buf),
.addr_i(wr_addr_i),
.en_i(wr_en_i),
.err_o(we_err)
);
// We need to register this to avoid timing loops.
always_ff @(posedge clk_i or negedge rst_ni) begin : p_err
if (!rst_ni) begin
we_err_o <= '0;
end else begin
we_err_o <= we_err;
end
end
endmodule