| // 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 |
| * |
| * This register file is designed to make FPGA synthesis tools infer RAM primitives. For Xilinx |
| * FPGA architectures, it will produce RAM32M primitives. Other vendors have not yet been tested. |
| */ |
| module otbn_rf_bignum_fpga |
| import otbn_pkg::*; |
| #( |
| parameter logic [BaseIntgWidth-1:0] WordZeroVal = '0 |
| ) ( |
| 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 |
| ); |
| |
| |
| // The reset is not used in this register file version. |
| logic unused_rst_ni; |
| assign unused_rst_ni = rst_ni; |
| |
| // This is only used for backdoor access in simulations. |
| logic [ExtWLEN-1:0] rf [NWdr]; |
| logic [ExtWLEN-1:0] unused_rf [NWdr]; |
| assign unused_rf = rf; |
| |
| // Split registers into individual 39bit wide memories - otherwise the tool fails to properly |
| // implement the non-zero memory intialization assignment in the initial block. Further, the |
| // regfile is split into two sets of memories for clear separation of the enable terms. |
| for (genvar i = 0; i < BaseWordsPerWLEN; i++) begin : gen_rf |
| logic [BaseIntgWidth-1:0] rf_local [NWdr]; |
| // Sync write |
| // 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 |
| // of the inferred RAM32M primitives with non-zero values, below "initial" procedure is needed. |
| // Therefore, we use "always" instead of the generally preferred "always_ff" for the synchronous |
| // write procedure. |
| always @(posedge clk_i) begin |
| if (wr_en_i[i/(BaseWordsPerWLEN/2)] == 1'b1) begin |
| rf_local[wr_addr_i] <= wr_data_i[i*BaseIntgWidth+:BaseIntgWidth]; |
| end |
| end |
| |
| // Make sure we initialize the BRAM with the correct register reset value. |
| initial begin |
| for (int k = 0; k < NWdr; k++) begin |
| rf_local[k] = WordZeroVal; |
| end |
| end |
| |
| // Async read |
| assign rd_data_a_o[i*BaseIntgWidth+:BaseIntgWidth] = rf_local[rd_addr_a_i]; |
| assign rd_data_b_o[i*BaseIntgWidth+:BaseIntgWidth] = rf_local[rd_addr_b_i]; |
| |
| // SEC_CM: RF_BASE.DATA_REG_SW.GLITCH_DETECT |
| // There is nothing to check here since the decoding happens inside the inferred |
| // memory block. |
| assign we_err_o = 1'b0; |
| |
| // This is only used for backdoor access in simulations. |
| `ifdef VERILATOR |
| `define INC_BACKDOOR_LOAD |
| `elsif SIMULATION |
| `define INC_BACKDOOR_LOAD |
| `endif |
| `ifdef INC_BACKDOOR_LOAD |
| for (genvar k = 0; k < NWdr; k++) begin : gen_sim |
| assign rf[k][i*BaseIntgWidth+:BaseIntgWidth] = rf_local[k]; |
| end |
| `undef INC_BACKDOOR_LOAD |
| `endif |
| end |
| |
| endmodule |