blob: 2f250052914f866882e80595701fb2702bb515d3 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* ExtWLEN (312b) Wide Register File (WDRs)
*
* ExtWLEN allows bits to provide integrity checking to WLEN words on a 32-bit granule. Integrity
* generation/checking implemented in wrapping otbn_rf_bignum module
*
* Features:
* - 2 read ports
* - 1 write port
* - Half (WLEN) word write enables
*/
module otbn_rf_bignum_ff
import otbn_pkg::*;
(
input logic clk_i,
input logic rst_ni,
input logic [WdrAw-1:0] wr_addr_i,
input logic [1:0] wr_en_i,
input logic [ExtWLEN-1:0] wr_data_i,
input logic [WdrAw-1:0] rd_addr_a_i,
output logic [ExtWLEN-1:0] rd_data_a_o,
input logic [WdrAw-1:0] rd_addr_b_i,
output logic [ExtWLEN-1:0] rd_data_b_o,
// Indicates whether a spurious WE has been seen in the last cycle.
output logic we_err_o,
input rf_predec_bignum_t rf_predec_bignum_i
);
logic [ExtWLEN-1:0] rf [NWdr];
logic [1:0] we_onehot [NWdr];
logic unused_addr;
for (genvar i = 0; i < NWdr; i++) begin : g_rf
logic [ExtWLEN-1:0] wr_data_blanked;
assign we_onehot[i] = wr_en_i & {2{wr_addr_i == i}};
// SEC_CM: DATA_REG_SW.SCA
prim_blanker #(.Width(ExtWLEN)) u_wdata_blanker(
.in_i (wr_data_i),
.en_i (rf_predec_bignum_i.rf_we[i]),
.out_o(wr_data_blanked)
);
// Split registers into halves for clear seperation for the enable terms
always_ff @(posedge clk_i) begin
if (rf_predec_bignum_i.rf_we[i] & we_onehot[i][0]) begin
rf[i][0+:ExtWLEN/2] <= wr_data_blanked[0+:ExtWLEN/2];
end
end
always_ff @(posedge clk_i) begin
if (rf_predec_bignum_i.rf_we[i] & we_onehot[i][1]) begin
rf[i][ExtWLEN/2+:ExtWLEN/2] <= wr_data_blanked[ExtWLEN/2+:ExtWLEN/2];
end
end
`ASSERT(BlankingBignumRegWData_A, !(|we_onehot[i]) |-> wr_data_blanked inside {'0, 'x})
end
// SEC_CM: DATA_REG_SW.SCA
prim_onehot_mux #(
.Width(ExtWLEN),
.Inputs(NWdr)
) u_rd_mux_a (
.clk_i,
.rst_ni,
.in_i (rf),
.sel_i (rf_predec_bignum_i.rf_ren_a),
.out_o (rd_data_a_o)
);
prim_onehot_mux #(
.Width(ExtWLEN),
.Inputs(NWdr)
) u_rd_mux_b (
.clk_i,
.rst_ni,
.in_i (rf),
.sel_i (rf_predec_bignum_i.rf_ren_b),
.out_o (rd_data_b_o)
);
assign unused_addr = ^rd_addr_a_i ^ ^rd_addr_b_i ^ ^wr_addr_i;
logic we_err, we_err_d;
logic [1:0][NWdr-1:0] we_onehot_unbuf, we_onehot_buf;
for (genvar k = 0; k < 2; k++) begin : g_check
for (genvar i = 0; i < NWdr; i++) begin : g_reshape
assign we_onehot_unbuf[k][i] = we_onehot[i][k];
end
end
// Buffer the decoded write enable bits so that the checker
// is not optimized into the address decoding logic.
prim_buf #(
.Width(2*NWdr)
) u_prim_buf (
.in_i(we_onehot_unbuf),
.out_o(we_onehot_buf)
);
// SEC_CM: RF_BIGNUM.DATA_REG_SW.GLITCH_DETECT
// This checks for spurious WE strobes on the regfile.
prim_onehot_check #(
.AddrWidth(WdrAw),
.OneHotWidth(NWdr),
.AddrCheck(1),
.EnableCheck(1)
) u_prim_onehot_check (
.clk_i,
.rst_ni,
// OR the two register halves.
.oh_i(we_onehot_buf[0] | we_onehot_buf[1]),
.addr_i(wr_addr_i),
.en_i(|wr_en_i),
.err_o(we_err)
);
assign we_err_d = we_err | we_err_o;
prim_flop #(
.Width(1),
.ResetValue('0)
) u_we_err_flop (
.clk_i,
.rst_ni,
.d_i(we_err_d),
.q_o(we_err_o)
);
endmodule