| // 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 | 
 |   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; | 
 |   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) | 
 |   ); | 
 |  | 
 |   // 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 |