| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| /** |
| * 256b General Purpose Register File (GPRs) with integrity code detecting triple bit errors on a |
| * 32-bit granule (312 bits total). |
| * |
| * This wraps two implementations, one for FPGA (otbn_rf_base_fpga) implementation the other for |
| * ASIC (otbn_rf_base_ff). |
| * |
| * Integrity protection uses an inverted (39, 32) Hsaio code providing a Hamming distance of 4. |
| * |
| * `wr_data_no_intg_i` supplies data that requires integrity calulation and `wr_data_intg_i` |
| * supplies data that comes with integrity. `wr_data_intg_sel_i` is asserted to select the data with |
| * integrity for the write, otherwise integrity is calculated separately from `wr_data_i`. |
| * |
| * Features: |
| * - 2 read ports |
| * - 1 write port |
| * - triple error detection |
| */ |
| |
| module otbn_rf_bignum |
| import otbn_pkg::*; |
| #( |
| // Register file implementation selection, see otbn_pkg.sv. |
| parameter regfile_e RegFile = RegFileFF |
| )( |
| 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 wr_commit_i, |
| input logic [WLEN-1:0] wr_data_no_intg_i, |
| input logic [ExtWLEN-1:0] wr_data_intg_i, |
| input logic wr_data_intg_sel_i, |
| |
| input logic rd_en_a_i, |
| input logic [WdrAw-1:0] rd_addr_a_i, |
| output logic [ExtWLEN-1:0] rd_data_a_intg_o, |
| |
| input logic rd_en_b_i, |
| input logic [WdrAw-1:0] rd_addr_b_i, |
| output logic [ExtWLEN-1:0] rd_data_b_intg_o, |
| |
| output logic rf_err_o, |
| |
| input rf_predec_bignum_t rf_predec_bignum_i, |
| output logic predec_error_o |
| ); |
| |
| logic spurious_we_err; |
| logic [ExtWLEN-1:0] wr_data_intg_mux_out, wr_data_intg_calc; |
| logic [1:0] wr_en_internal; |
| logic [BaseWordsPerWLEN*2-1:0] rd_data_a_err, rd_data_b_err; |
| logic [NWdr-1:0] expected_rd_en_a_onehot, expected_rd_en_b_onehot; |
| logic [NWdr-1:0] expected_wr_en_onehot; |
| logic rd_en_a_mismatch, rd_en_b_mismatch, wr_en_mismatch; |
| |
| assign wr_en_internal = wr_en_i & {2{wr_commit_i}}; |
| |
| if (RegFile == RegFileFF) begin : gen_rf_bignum_ff |
| otbn_rf_bignum_ff #( |
| .WordZeroVal(prim_secded_pkg::SecdedInv3932ZeroWord) |
| ) u_otbn_rf_bignum_inner ( |
| .clk_i, |
| .rst_ni, |
| |
| .wr_addr_i, |
| .wr_en_i(wr_en_internal), |
| .wr_data_i(wr_data_intg_mux_out), |
| |
| .rd_addr_a_i, |
| .rd_data_a_o(rd_data_a_intg_o), |
| |
| .rd_addr_b_i, |
| .rd_data_b_o(rd_data_b_intg_o), |
| |
| .rf_predec_bignum_i, |
| |
| .we_err_o(spurious_we_err) |
| ); |
| end else if (RegFile == RegFileFPGA) begin : gen_rf_bignum_fpga |
| otbn_rf_bignum_fpga #( |
| .WordZeroVal(prim_secded_pkg::SecdedInv3932ZeroWord) |
| ) u_otbn_rf_bignum_inner ( |
| .clk_i, |
| .rst_ni, |
| |
| .wr_addr_i, |
| .wr_en_i(wr_en_internal), |
| .wr_data_i(wr_data_intg_mux_out), |
| |
| .rd_addr_a_i, |
| .rd_data_a_o(rd_data_a_intg_o), |
| |
| .rd_addr_b_i, |
| .rd_data_b_o(rd_data_b_intg_o), |
| |
| .we_err_o(spurious_we_err) |
| ); |
| end |
| |
| prim_onehot_enc #( |
| .OneHotWidth(NWdr) |
| ) u_rf_ren_a_onehot_enc ( |
| .in_i (rd_addr_a_i), |
| .en_i (rd_en_a_i), |
| .out_o (expected_rd_en_a_onehot) |
| ); |
| |
| prim_onehot_enc #( |
| .OneHotWidth(NWdr) |
| ) u_rf_ren_b_onehot_enc ( |
| .in_i (rd_addr_b_i), |
| .en_i (rd_en_b_i), |
| .out_o (expected_rd_en_b_onehot) |
| ); |
| |
| prim_onehot_enc #( |
| .OneHotWidth(NWdr) |
| ) u_rf_we_onehot_enc ( |
| .in_i (wr_addr_i), |
| .en_i (|wr_en_i), |
| .out_o (expected_wr_en_onehot) |
| ); |
| |
| // SEC_CM: CTRL.REDUN |
| assign rd_en_a_mismatch = expected_rd_en_a_onehot != rf_predec_bignum_i.rf_ren_a; |
| assign rd_en_b_mismatch = expected_rd_en_b_onehot != rf_predec_bignum_i.rf_ren_b; |
| assign wr_en_mismatch = expected_wr_en_onehot != rf_predec_bignum_i.rf_we; |
| |
| assign predec_error_o = rd_en_a_mismatch | rd_en_b_mismatch | wr_en_mismatch; |
| |
| // New data can have its integrity from an external source or the integrity can be calculated here |
| assign wr_data_intg_mux_out = wr_data_intg_sel_i ? wr_data_intg_i : wr_data_intg_calc; |
| |
| // SEC_CM: RF_BIGNUM.DATA_REG_SW.INTEGRITY |
| // Separate integrity encode and decode per 32-bit integrity granule |
| for (genvar i = 0; i < BaseWordsPerWLEN; ++i) begin : g_rf_intg_calc |
| prim_secded_inv_39_32_enc u_wr_data_intg_enc ( |
| .data_i(wr_data_no_intg_i[i * 32 +: 32]), |
| .data_o(wr_data_intg_calc[i * 39 +: 39]) |
| ); |
| |
| // Integrity decoders used to detect errors only, corrections (`syndrome_o`/`d_o`) are ignored |
| prim_secded_inv_39_32_dec u_rd_data_a_intg_dec ( |
| .data_i (rd_data_a_intg_o[i * 39 +: 39]), |
| .data_o (), |
| .syndrome_o(), |
| .err_o (rd_data_a_err[i*2 +: 2]) |
| ); |
| |
| prim_secded_inv_39_32_dec u_rd_data_b_intg_dec ( |
| .data_i (rd_data_b_intg_o[i * 39 +: 39]), |
| .data_o (), |
| .syndrome_o(), |
| .err_o (rd_data_b_err[i*2 +: 2]) |
| ); |
| end |
| |
| assign rf_err_o = ((|rd_data_a_err) & rd_en_a_i) | |
| ((|rd_data_b_err) & rd_en_b_i) | |
| spurious_we_err; |
| endmodule |