| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | /** | 
 |  * 32b General Purpose Register File (GPRs) | 
 |  * | 
 |  * This wraps two implementations, one for FPGA (otbn_rf_base_fpga) | 
 |  * implementation the other for ASIC (otbn_rf_base_ff). | 
 |  * | 
 |  * Features: | 
 |  * - 2 read ports | 
 |  * - 1 write port | 
 |  * - special purpose stack on a single register (localparam `CallStackRegIndex`) | 
 |  *   for use as a call stack | 
 |  */ | 
 | module otbn_rf_base | 
 |   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 [4:0]    wr_addr_i, | 
 |   input logic          wr_en_i, | 
 |   input logic [31:0]   wr_data_i, | 
 |  | 
 |   input  logic [4:0]   rd_addr_a_i, | 
 |   input  logic         rd_en_a_i, | 
 |   output logic [31:0]  rd_data_a_o, | 
 |  | 
 |   input  logic [4:0]   rd_addr_b_i, | 
 |   input  logic         rd_en_b_i, | 
 |   output logic [31:0]  rd_data_b_o, | 
 |  | 
 |   output logic         call_stack_overflow_err_o | 
 | ); | 
 |   localparam int unsigned CallStackRegIndex = 1; | 
 |   localparam int unsigned CallStackDepth = 8; | 
 |  | 
 |   // The stack implementation is shared between FF and FPGA implementations, | 
 |   // actual register register file differs between FF and FPGA implementations. | 
 |   // Pass through signals to chosen register file, diverting any reads/writes to | 
 |   // register CallStatckRegIndex to the stack. | 
 |  | 
 |   logic        wr_en_masked; | 
 |   logic [31:0] rd_data_a_raw; | 
 |   logic [31:0] rd_data_b_raw; | 
 |  | 
 |   logic pop_stack_a; | 
 |   logic pop_stack_b; | 
 |   logic pop_stack; | 
 |   logic push_stack; | 
 |  | 
 |   logic        stack_full; | 
 |   logic [31:0] stack_data; | 
 |   logic        stack_data_valid; | 
 |  | 
 |   assign pop_stack_a = rd_en_a_i & (rd_addr_a_i == CallStackRegIndex[4:0]); | 
 |   assign pop_stack_b = rd_en_b_i & (rd_addr_b_i == CallStackRegIndex[4:0]); | 
 |   assign pop_stack   = pop_stack_a | pop_stack_b; | 
 |  | 
 |   assign push_stack = wr_en_i & (wr_addr_i == CallStackRegIndex[4:0]); | 
 |  | 
 |   assign call_stack_overflow_err_o = (push_stack & stack_full & ~pop_stack) | (pop_stack & ~stack_data_valid); | 
 |  | 
 |   // Prevent any write to the stack register from going to the register file, | 
 |   // all other writes are passed straight through | 
 |   assign wr_en_masked = wr_en_i & ~push_stack; | 
 |  | 
 |   // Ignore read data from the register file if reading from the stack register, | 
 |   // otherwise pass data through from register file. | 
 |   assign rd_data_a_o = pop_stack_a ? stack_data : rd_data_a_raw; | 
 |   assign rd_data_b_o = pop_stack_b ? stack_data : rd_data_b_raw; | 
 |  | 
 |   otbn_stack #( | 
 |     .StackWidth (32), | 
 |     .StackDepth (CallStackDepth) | 
 |   ) u_call_stack ( | 
 |     .clk_i, | 
 |     .rst_ni, | 
 |  | 
 |     .full_o       (stack_full), | 
 |  | 
 |     .push_i       (push_stack), | 
 |     .push_data_i  (wr_data_i), | 
 |  | 
 |     .pop_i        (pop_stack), | 
 |     .top_data_o   (stack_data), | 
 |     .top_valid_o  (stack_data_valid) | 
 |   ); | 
 |  | 
 |   if (RegFile == RegFileFF) begin : gen_rf_base_ff | 
 |     otbn_rf_base_ff u_otbn_rf_base_inner ( | 
 |       .clk_i, | 
 |       .rst_ni, | 
 |  | 
 |       .wr_addr_i, | 
 |       .wr_en_i   (wr_en_masked), | 
 |       .wr_data_i, | 
 |  | 
 |       .rd_addr_a_i, | 
 |       .rd_data_a_o (rd_data_a_raw), | 
 |       .rd_addr_b_i, | 
 |       .rd_data_b_o (rd_data_b_raw) | 
 |     ); | 
 |   end else if (RegFile == RegFileFPGA) begin : gen_rf_base_fpga | 
 |     otbn_rf_base_fpga u_otbn_rf_base_inner ( | 
 |       .clk_i, | 
 |       .rst_ni, | 
 |  | 
 |       .wr_addr_i, | 
 |       .wr_en_i   (wr_en_masked), | 
 |       .wr_data_i, | 
 |  | 
 |       .rd_addr_a_i, | 
 |       .rd_data_a_o (rd_data_a_raw), | 
 |       .rd_addr_b_i, | 
 |       .rd_data_b_o (rd_data_b_raw) | 
 |     ); | 
 |   end | 
 | endmodule |