diff --git a/dv/uvm/core_ibex/ibex_dv.f b/dv/uvm/core_ibex/ibex_dv.f index c8ec489eb..4b1cde315 100644 --- a/dv/uvm/core_ibex/ibex_dv.f +++ b/dv/uvm/core_ibex/ibex_dv.f @@ -97,6 +97,7 @@ ${PRJ_DIR}/rtl/ibex_multdiv_fast.sv ${PRJ_DIR}/rtl/ibex_prefetch_buffer.sv ${PRJ_DIR}/rtl/ibex_fetch_fifo.sv +${PRJ_DIR}/rtl/ibex_register_file_common.sv ${PRJ_DIR}/rtl/ibex_register_file_ff.sv ${PRJ_DIR}/rtl/ibex_register_file_fpga.sv ${PRJ_DIR}/rtl/ibex_register_file_latch.sv diff --git a/ibex_top.core b/ibex_top.core index 38a279dfb..341c26477 100644 --- a/ibex_top.core +++ b/ibex_top.core @@ -19,6 +19,7 @@ filesets: - lowrisc:prim:onehot_check - lowrisc:prim:onehot files: + - rtl/ibex_register_file_common.sv - rtl/ibex_register_file_ff.sv # generic FF-based - rtl/ibex_register_file_fpga.sv # FPGA - rtl/ibex_register_file_latch.sv # ASIC diff --git a/rtl/ibex_core.f b/rtl/ibex_core.f index cde47fca2..ee9437f63 100644 --- a/rtl/ibex_core.f +++ b/rtl/ibex_core.f @@ -17,5 +17,6 @@ ibex_multdiv_fast.sv ibex_prefetch_buffer.sv ibex_fetch_fifo.sv +ibex_register_file_common.sv ibex_register_file_ff.sv ibex_core.sv diff --git a/rtl/ibex_register_file_common.sv b/rtl/ibex_register_file_common.sv new file mode 100644 index 000000000..6eca72bb8 --- /dev/null +++ b/rtl/ibex_register_file_common.sv @@ -0,0 +1,175 @@ +// Copyright lowRISC contributors. +// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * RISC-V register file + * + * Register file common security functionality across multiple implementations + * - Contains common security hardening logic across implementations + * - Contains checks for onehot encoding of addresses and write enable(s) + */ + +module ibex_register_file_common #( + parameter bit FPGA = 0, + parameter int unsigned AddrWidth = 5, + parameter int unsigned NumWords = 2 ** AddrWidth, + parameter bit WrenCheck = 0, + parameter bit RdataMuxCheck = 0 +) ( + /* verilator lint_off UNUSED */ + // Clock and Reset + input logic clk_i, + input logic rst_ni, + /* verilator lint_on UNUSED */ + + //Read port R1 + input logic [4:0] raddr_a_i, + output logic [NumWords-1:0] raddr_onehot_a, + output logic oh_raddr_a_err, + + //Read port R2 + input logic [4:0] raddr_b_i, + output logic [NumWords-1:0] raddr_onehot_b, + output logic oh_raddr_b_err, + + // Write port W1 + input logic [4:0] waddr_a_i, + input logic we_a_i, + output logic [NumWords-1:0] we_onehot_a, + output logic oh_we_err, + + // This indicates whether spurious WE or non-one-hot encoded raddr are detected. + output logic err_o +); + + if (FPGA) begin : gen_fpga_oh_we_a_o_decoder + always_comb begin : oh_we_a_o_decoder + for (int unsigned i = 0; i < NumWords; i++) begin + we_onehot_a[i] = (i == 0) ? we_a_i : 1'b0; + end + end + end else begin : gen_other_oh_we_a_o_decoder + always_comb begin : oh_we_a_o_decoder + for (int unsigned i = 0; i < NumWords; i++) begin + we_onehot_a[i] = (waddr_a_i == 5'(i)) ? we_a_i : 1'b0; + end + end + end + + // SEC_CM: DATA_REG_SW.GLITCH_DETECT + // This checks for spurious WE strobes on the regfile. + if (WrenCheck) begin : gen_wren_check + // Buffer the decoded write enable bits so that the checker + // is not optimized into the address decoding logic. + logic [NumWords-1:0] we_onehot_a_buf; + prim_buf #( + .Width(NumWords) + ) u_prim_buf ( + .in_i (we_onehot_a), + .out_o(we_onehot_a_buf) + ); + + prim_onehot_check #( + .AddrWidth (AddrWidth), + .OneHotWidth(NumWords), + .AddrCheck (FPGA ? 0 : 1), // disable in case of FPGA impl, as we use [0] only + .EnableCheck(1), + ) u_prim_onehot_check ( + .clk_i, + .rst_ni, + .oh_i (we_onehot_a_buf), + .addr_i(waddr_a_i), + .en_i (we_a_i), + .err_o (oh_we_err) + ); + end else begin : gen_no_wren_check + if (FPGA) begin : gen_unused_wren_check + logic unused_waddr_a; + assign unused_waddr_a = ^waddr_a_i; + end + assign oh_we_err = 1'b0; + end + + if (RdataMuxCheck) begin : gen_rdata_mux_check + // Encode raddr_a/b into one-hot encoded signals. + logic [NumWords-1:0] raddr_onehot_a_buf, raddr_onehot_b_buf; + prim_onehot_enc #( + .OneHotWidth(NumWords) + ) u_prim_onehot_enc_raddr_a ( + .in_i (raddr_a_i), + .en_i (1'b1), + .out_o(raddr_onehot_a) + ); + + prim_onehot_enc #( + .OneHotWidth(NumWords) + ) u_prim_onehot_enc_raddr_b ( + .in_i (raddr_b_i), + .en_i (1'b1), + .out_o(raddr_onehot_b) + ); + + // Buffer the one-hot encoded signals so that the checkers + // are not optimized. + prim_buf #( + .Width(NumWords) + ) u_prim_buf_raddr_a ( + .in_i (raddr_onehot_a), + .out_o(raddr_onehot_a_buf) + ); + + prim_buf #( + .Width(NumWords) + ) u_prim_buf_raddr_b ( + .in_i (raddr_onehot_b), + .out_o(raddr_onehot_b_buf) + ); + + // SEC_CM: DATA_REG_SW.GLITCH_DETECT + // Check the one-hot encoded signals for glitches. + prim_onehot_check #( + .AddrWidth (AddrWidth), + .OneHotWidth(NumWords), + .AddrCheck (1), + // When AddrCheck=1 also EnableCheck needs to be 1. + .EnableCheck(1) + ) u_prim_onehot_check_raddr_a ( + .clk_i, + .rst_ni, + .oh_i (raddr_onehot_a_buf), + .addr_i(raddr_a_i), + // Set enable=1 as address is always valid. + .en_i (1'b1), + .err_o (oh_raddr_a_err) + ); + + prim_onehot_check #( + .AddrWidth (AddrWidth), + .OneHotWidth(NumWords), + .AddrCheck (1), + // When AddrCheck=1 also EnableCheck needs to be 1. + .EnableCheck(1) + ) u_prim_onehot_check_raddr_b ( + .clk_i, + .rst_ni, + .oh_i (raddr_onehot_b_buf), + .addr_i(raddr_b_i), + // Set enable=1 as address is always valid. + .en_i (1'b1), + .err_o (oh_raddr_b_err) + ); + end else begin : gen_no_rdata_mux_check + assign oh_raddr_a_err = 1'b0; + assign oh_raddr_b_err = 1'b0; + assign raddr_onehot_a = '0; + assign raddr_onehot_b = '0; + + logic unused_raddr; + assign unused_raddr = ^{raddr_a_i, raddr_b_i}; + end + + assign err_o = oh_raddr_a_err || oh_raddr_b_err || oh_we_err; + +endmodule diff --git a/rtl/ibex_register_file_ff.sv b/rtl/ibex_register_file_ff.sv index 53c89e2d3..4354d517b 100644 --- a/rtl/ibex_register_file_ff.sv +++ b/rtl/ibex_register_file_ff.sv @@ -48,46 +48,34 @@ module ibex_register_file_ff #( localparam int unsigned NUM_WORDS = 2**ADDR_WIDTH; logic [DataWidth-1:0] rf_reg [NUM_WORDS]; - logic [NUM_WORDS-1:0] we_a_dec; + // Encode we_a/raddr_a/raddr_b into one-hot encoded signals + logic [NUM_WORDS-1:0] raddr_onehot_a, raddr_onehot_b, we_onehot_a; + + // One-hot encoding error signals logic oh_raddr_a_err, oh_raddr_b_err, oh_we_err; - always_comb begin : we_a_decoder - for (int unsigned i = 0; i < NUM_WORDS; i++) begin - we_a_dec[i] = (waddr_a_i == 5'(i)) ? we_a_i : 1'b0; - end - end - - // SEC_CM: DATA_REG_SW.GLITCH_DETECT - // This checks for spurious WE strobes on the regfile. - if (WrenCheck) begin : gen_wren_check - // Buffer the decoded write enable bits so that the checker - // is not optimized into the address decoding logic. - logic [NUM_WORDS-1:0] we_a_dec_buf; - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf ( - .in_i(we_a_dec), - .out_o(we_a_dec_buf) - ); - - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .AddrCheck(1), - .EnableCheck(1) - ) u_prim_onehot_check ( - .clk_i, - .rst_ni, - .oh_i(we_a_dec_buf), - .addr_i(waddr_a_i), - .en_i(we_a_i), - .err_o(oh_we_err) - ); - end else begin : gen_no_wren_check - logic unused_strobe; - assign unused_strobe = we_a_dec[0]; // this is never read from in this case - assign oh_we_err = 1'b0; - end + // Common security functionality + ibex_register_file_common #( + .AddrWidth(ADDR_WIDTH), + .NumWords(NUM_WORDS), + .WrenCheck(WrenCheck), + .RdataMuxCheck(RdataMuxCheck) + ) security_module ( + .clk_i, + .rst_ni, + .raddr_a_i, + .raddr_onehot_a, + .oh_raddr_a_err, + .raddr_b_i, + .raddr_onehot_b, + .oh_raddr_b_err, + .waddr_a_i, + .we_a_i, + .we_onehot_a, + .oh_we_err, + .err_o + ); // No flops for R0 as it's hard-wired to 0 for (genvar i = 1; i < NUM_WORDS; i++) begin : g_rf_flops @@ -96,7 +84,7 @@ module ibex_register_file_ff #( always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rf_reg_q <= WordZeroVal; - end else if (we_a_dec[i]) begin + end else if (we_onehot_a[i]) begin rf_reg_q <= wdata_a_i; end end @@ -134,75 +122,6 @@ module ibex_register_file_ff #( end if (RdataMuxCheck) begin : gen_rdata_mux_check - // Encode raddr_a/b into one-hot encoded signals. - logic [NUM_WORDS-1:0] raddr_onehot_a, raddr_onehot_b; - logic [NUM_WORDS-1:0] raddr_onehot_a_buf, raddr_onehot_b_buf; - prim_onehot_enc #( - .OneHotWidth(NUM_WORDS) - ) u_prim_onehot_enc_raddr_a ( - .in_i (raddr_a_i), - .en_i (1'b1), - .out_o (raddr_onehot_a) - ); - - prim_onehot_enc #( - .OneHotWidth(NUM_WORDS) - ) u_prim_onehot_enc_raddr_b ( - .in_i (raddr_b_i), - .en_i (1'b1), - .out_o (raddr_onehot_b) - ); - - // Buffer the one-hot encoded signals so that the checkers - // are not optimized. - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf_raddr_a ( - .in_i (raddr_onehot_a), - .out_o(raddr_onehot_a_buf) - ); - - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf_raddr_b ( - .in_i (raddr_onehot_b), - .out_o(raddr_onehot_b_buf) - ); - - // SEC_CM: DATA_REG_SW.GLITCH_DETECT - // Check the one-hot encoded signals for glitches. - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .OneHotWidth(NUM_WORDS), - .AddrCheck(1), - // When AddrCheck=1 also EnableCheck needs to be 1. - .EnableCheck(1) - ) u_prim_onehot_check_raddr_a ( - .clk_i, - .rst_ni, - .oh_i (raddr_onehot_a_buf), - .addr_i (raddr_a_i), - // Set enable=1 as address is always valid. - .en_i (1'b1), - .err_o (oh_raddr_a_err) - ); - - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .OneHotWidth(NUM_WORDS), - .AddrCheck(1), - // When AddrCheck=1 also EnableCheck needs to be 1. - .EnableCheck(1) - ) u_prim_onehot_check_raddr_b ( - .clk_i, - .rst_ni, - .oh_i (raddr_onehot_b_buf), - .addr_i (raddr_b_i), - // Set enable=1 as address is always valid. - .en_i (1'b1), - .err_o (oh_raddr_b_err) - ); - // MUX register to rdata_a/b_o according to raddr_a/b_onehot. prim_onehot_mux #( .Width(DataWidth), @@ -228,14 +147,21 @@ module ibex_register_file_ff #( end else begin : gen_no_rdata_mux_check assign rdata_a_o = rf_reg[raddr_a_i]; assign rdata_b_o = rf_reg[raddr_b_i]; - assign oh_raddr_a_err = 1'b0; - assign oh_raddr_b_err = 1'b0; - end - assign err_o = oh_raddr_a_err || oh_raddr_b_err || oh_we_err; + logic unused_raddr_onehot, unused_oh_raddr_err; + assign unused_raddr_onehot = ^{raddr_onehot_a, raddr_onehot_b}; + assign unused_oh_raddr_err = ^{oh_raddr_a_err, oh_raddr_b_err}; + end // Signal not used in FF register file logic unused_test_en; assign unused_test_en = test_en_i; + if (WrenCheck) begin : gen_wren_check + end else begin : gen_no_wren_check + logic unused_strobe, unused_oh_we_err; + assign unused_strobe = we_onehot_a[0]; // this is never read from in this case + assign unused_oh_we_err = oh_we_err; // this is never read from in this case + end + endmodule diff --git a/rtl/ibex_register_file_fpga.sv b/rtl/ibex_register_file_fpga.sv index 65698d1c5..729c2541f 100644 --- a/rtl/ibex_register_file_fpga.sv +++ b/rtl/ibex_register_file_fpga.sv @@ -48,82 +48,38 @@ module ibex_register_file_fpga #( logic [DataWidth-1:0] mem[NUM_WORDS]; logic we; // write enable if writing to any register other than R0 - logic [DataWidth-1:0] mem_o_a, mem_o_b; + // Encode we_a/raddr_a/raddr_b into one-hot encoded signals + logic [NUM_WORDS-1:0] raddr_onehot_a, raddr_onehot_b, we_onehot_a; // WE strobe and one-hot encoded raddr alert. logic oh_raddr_a_err, oh_raddr_b_err, oh_we_err; - assign err_o = oh_raddr_a_err || oh_raddr_b_err || oh_we_err; - - if (RdataMuxCheck) begin : gen_rdata_mux_check - // Encode raddr_a/b into one-hot encoded signals. - logic [NUM_WORDS-1:0] raddr_onehot_a, raddr_onehot_b; - logic [NUM_WORDS-1:0] raddr_onehot_a_buf, raddr_onehot_b_buf; - prim_onehot_enc #( - .OneHotWidth(NUM_WORDS) - ) u_prim_onehot_enc_raddr_a ( - .in_i (raddr_a_i), - .en_i (1'b1), - .out_o (raddr_onehot_a) - ); - prim_onehot_enc #( - .OneHotWidth(NUM_WORDS) - ) u_prim_onehot_enc_raddr_b ( - .in_i (raddr_b_i), - .en_i (1'b1), - .out_o (raddr_onehot_b) - ); - - // Buffer the one-hot encoded signals so that the checkers - // are not optimized. - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf_raddr_a ( - .in_i (raddr_onehot_a), - .out_o(raddr_onehot_a_buf) - ); - - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf_raddr_b ( - .in_i (raddr_onehot_b), - .out_o(raddr_onehot_b_buf) - ); - - // SEC_CM: DATA_REG_SW.GLITCH_DETECT - // Check the one-hot encoded signals for glitches. - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .OneHotWidth(NUM_WORDS), - .AddrCheck(1), - // When AddrCheck=1 also EnableCheck needs to be 1. - .EnableCheck(1) - ) u_prim_onehot_check_raddr_a ( - .clk_i, - .rst_ni, - .oh_i (raddr_onehot_a_buf), - .addr_i (raddr_a_i), - // Set enable=1 as address is always valid. - .en_i (1'b1), - .err_o (oh_raddr_a_err) - ); + logic [DataWidth-1:0] mem_o_a, mem_o_b; - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .OneHotWidth(NUM_WORDS), - .AddrCheck(1), - // When AddrCheck=1 also EnableCheck needs to be 1. - .EnableCheck(1) - ) u_prim_onehot_check_raddr_b ( - .clk_i, - .rst_ni, - .oh_i (raddr_onehot_b_buf), - .addr_i (raddr_b_i), - // Set enable=1 as address is always valid. - .en_i (1'b1), - .err_o (oh_raddr_b_err) - ); + // Common security functionality + ibex_register_file_common #( + .FPGA(1), + .AddrWidth(ADDR_WIDTH), + .NumWords(NUM_WORDS), + .WrenCheck(WrenCheck), + .RdataMuxCheck(RdataMuxCheck) + ) security_module ( + .clk_i, + .rst_ni, + .raddr_a_i, + .raddr_onehot_a, + .oh_raddr_a_err, + .raddr_b_i, + .raddr_onehot_b, + .oh_raddr_b_err, + .waddr_a_i, + .we_a_i, + .we_onehot_a, + .oh_we_err, + .err_o + ); + if (RdataMuxCheck) begin : gen_rdata_mux_check // MUX register to rdata_a/b_o according to raddr_a/b_onehot. prim_onehot_mux #( .Width(DataWidth), @@ -153,21 +109,13 @@ module ibex_register_file_fpga #( assign rdata_a_o = (raddr_a_i == '0) ? WordZeroVal : mem[raddr_a_i]; assign rdata_b_o = (raddr_b_i == '0) ? WordZeroVal : mem[raddr_b_i]; - assign oh_raddr_a_err = 1'b0; - assign oh_raddr_b_err = 1'b0; + logic unused_raddr_onehot, unused_oh_raddr_err; + assign unused_raddr_onehot = ^{raddr_onehot_a, raddr_onehot_b}; + assign unused_oh_raddr_err = ^{oh_raddr_a_err, oh_raddr_b_err}; end // we select - assign we = (waddr_a_i == '0) ? 1'b0 : we_a_i; - - // SEC_CM: DATA_REG_SW.GLITCH_DETECT - // This checks for spurious WE strobes on the regfile. - if (WrenCheck) begin : gen_wren_check - // Since the FPGA uses a memory macro, there is only one write-enable strobe to check. - assign oh_we_err = we && !we_a_i; - end else begin : gen_no_wren_check - assign oh_we_err = 1'b0; - end + assign we = (waddr_a_i == '0) ? 1'b0 : we_onehot_a[0]; // Note that the SystemVerilog LRM requires variables on the LHS of assignments within // "always_ff" to not be written to by any other process. However, to enable the initialization @@ -198,4 +146,10 @@ module ibex_register_file_fpga #( logic unused_test_en; assign unused_test_en = test_en_i; + if (WrenCheck) begin : gen_wren_check + end else begin : gen_no_wren_check + logic unused_oh_we_err; + assign unused_oh_we_err = oh_we_err; // this is never read from in this case + end + endmodule diff --git a/rtl/ibex_register_file_latch.sv b/rtl/ibex_register_file_latch.sv index 375da414b..0283af9ab 100644 --- a/rtl/ibex_register_file_latch.sv +++ b/rtl/ibex_register_file_latch.sv @@ -51,6 +51,7 @@ module ibex_register_file_latch #( logic [NUM_WORDS-1:0] waddr_onehot_a; + // One-hot encoding error signals logic oh_raddr_a_err, oh_raddr_b_err, oh_we_err; logic [NUM_WORDS-1:1] mem_clocks; @@ -58,6 +59,7 @@ module ibex_register_file_latch #( // internal addresses logic [ADDR_WIDTH-1:0] raddr_a_int, raddr_b_int, waddr_a_int; + logic [NUM_WORDS-1:0] raddr_onehot_a, raddr_onehot_b, we_onehot_a; assign raddr_a_int = raddr_a_i[ADDR_WIDTH-1:0]; assign raddr_b_int = raddr_b_i[ADDR_WIDTH-1:0]; @@ -65,81 +67,32 @@ module ibex_register_file_latch #( logic clk_int; - assign err_o = oh_raddr_a_err || oh_raddr_b_err || oh_we_err; + // Common security functionality + ibex_register_file_common #( + .AddrWidth(ADDR_WIDTH), + .NumWords(NUM_WORDS), + .WrenCheck(WrenCheck), + .RdataMuxCheck(RdataMuxCheck) + ) security_module ( + .clk_i, + .rst_ni, + .raddr_a_i(raddr_a_int), + .raddr_onehot_a, + .oh_raddr_a_err, + .raddr_b_i(raddr_b_int), + .raddr_onehot_b, + .oh_raddr_b_err, + .waddr_a_i(waddr_a_int), + .we_a_i, + .we_onehot_a, + .oh_we_err, + .err_o + ); ////////// // READ // ////////// if (RdataMuxCheck) begin : gen_rdata_mux_check - // Encode raddr_a/b into one-hot encoded signals. - logic [NUM_WORDS-1:0] raddr_onehot_a, raddr_onehot_b; - logic [NUM_WORDS-1:0] raddr_onehot_a_buf, raddr_onehot_b_buf; - prim_onehot_enc #( - .OneHotWidth(NUM_WORDS) - ) u_prim_onehot_enc_raddr_a ( - .in_i (raddr_a_int), - .en_i (1'b1), - .out_o (raddr_onehot_a) - ); - - prim_onehot_enc #( - .OneHotWidth(NUM_WORDS) - ) u_prim_onehot_enc_raddr_b ( - .in_i (raddr_b_int), - .en_i (1'b1), - .out_o (raddr_onehot_b) - ); - - // Buffer the one-hot encoded signals so that the checkers - // are not optimized. - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf_raddr_a ( - .in_i(raddr_onehot_a), - .out_o(raddr_onehot_a_buf) - ); - - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf_raddr_b ( - .in_i(raddr_onehot_b), - .out_o(raddr_onehot_b_buf) - ); - - // SEC_CM: DATA_REG_SW.GLITCH_DETECT - // Check the one-hot encoded signals for glitches. - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .OneHotWidth(NUM_WORDS), - .AddrCheck(1), - // When AddrCheck=1 also EnableCheck needs to be 1. - .EnableCheck(1) - ) u_prim_onehot_check_raddr_a ( - .clk_i, - .rst_ni, - .oh_i (raddr_onehot_a_buf), - .addr_i (raddr_a_int), - // Set enable=1 as address is always valid. - .en_i (1'b1), - .err_o (oh_raddr_a_err) - ); - - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .OneHotWidth(NUM_WORDS), - .AddrCheck(1), - // When AddrCheck=1 also EnableCheck needs to be 1. - .EnableCheck(1) - ) u_prim_onehot_check_raddr_b ( - .clk_i, - .rst_ni, - .oh_i (raddr_onehot_b_buf), - .addr_i (raddr_b_int), - // Set enable=1 as address is always valid. - .en_i (1'b1), - .err_o (oh_raddr_b_err) - ); - // MUX register to rdata_a/b_o according to raddr_a/b_onehot. prim_onehot_mux #( .Width(DataWidth), @@ -165,8 +118,10 @@ module ibex_register_file_latch #( end else begin : gen_no_rdata_mux_check assign rdata_a_o = mem[raddr_a_int]; assign rdata_b_o = mem[raddr_b_int]; - assign oh_raddr_a_err = 1'b0; - assign oh_raddr_b_err = 1'b0; + + logic unused_raddr_onehot, unused_oh_raddr_err; + assign unused_raddr_onehot = ^{raddr_onehot_a, raddr_onehot_b}; + assign unused_oh_raddr_err = ^{oh_raddr_a_err, oh_raddr_b_err}; end /////////// @@ -192,55 +147,13 @@ module ibex_register_file_latch #( end end - // Write address decoding - always_comb begin : wad - for (int i = 0; i < NUM_WORDS; i++) begin : wad_word_iter - if (we_a_i && (waddr_a_int == 5'(i))) begin - waddr_onehot_a[i] = 1'b1; - end else begin - waddr_onehot_a[i] = 1'b0; - end - end - end - - // SEC_CM: DATA_REG_SW.GLITCH_DETECT - // This checks for spurious WE strobes on the regfile. - if (WrenCheck) begin : gen_wren_check - // Buffer the decoded write enable bits so that the checker - // is not optimized into the address decoding logic. - logic [NUM_WORDS-1:0] waddr_onehot_a_buf; - prim_buf #( - .Width(NUM_WORDS) - ) u_prim_buf ( - .in_i(waddr_onehot_a), - .out_o(waddr_onehot_a_buf) - ); - - prim_onehot_check #( - .AddrWidth(ADDR_WIDTH), - .AddrCheck(1), - .EnableCheck(1) - ) u_prim_onehot_check ( - .clk_i, - .rst_ni, - .oh_i(waddr_onehot_a_buf), - .addr_i(waddr_a_i), - .en_i(we_a_i), - .err_o(oh_we_err) - ); - end else begin : gen_no_wren_check - logic unused_strobe; - assign unused_strobe = waddr_onehot_a[0]; // this is never read from in this case - assign oh_we_err = 1'b0; - end - // Individual clock gating (if integrated clock-gating cells are available) for (genvar x = 1; x < NUM_WORDS; x++) begin : gen_cg_word_iter prim_clock_gating cg_i ( - .clk_i ( clk_int ), - .en_i ( waddr_onehot_a[x] ), - .test_en_i ( test_en_i ), - .clk_o ( mem_clocks[x] ) + .clk_i ( clk_int ), + .en_i ( we_onehot_a[x] ), + .test_en_i ( test_en_i ), + .clk_o ( mem_clocks[x] ) ); end @@ -290,6 +203,13 @@ module ibex_register_file_latch #( assign mem[0] = WordZeroVal; end + if (WrenCheck) begin : gen_wren_check + end else begin : gen_no_wren_check + logic unused_strobe, unused_oh_we_err; + assign unused_strobe = we_onehot_a[0]; // this is never read from in this case + assign unused_oh_we_err = oh_we_err; // this is never read from in this case + end + `ifdef VERILATOR initial begin $display("Latch-based register file not supported for Verilator simulation");