// Copyright 2020 ETH Zurich and University of Bologna. // Solderpad Hardware License, Version 0.51, see LICENSE for details. // SPDX-License-Identifier: SHL-0.51 // Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch> // Description: Variable Register File module snitch_regfile #( parameter DATA_WIDTH = 32, parameter NR_READ_PORTS = 2, parameter NR_WRITE_PORTS = 1, parameter ZERO_REG_ZERO = 1, parameter ADDR_WIDTH = 4 ) ( // clock and reset input logic clk_i, // read port input logic [NR_READ_PORTS-1:0][ADDR_WIDTH-1:0] raddr_i, output logic [NR_READ_PORTS-1:0][DATA_WIDTH-1:0] rdata_o, // write port input logic [NR_WRITE_PORTS-1:0][ADDR_WIDTH-1:0] waddr_i, input logic [NR_WRITE_PORTS-1:0][DATA_WIDTH-1:0] wdata_i, input logic [NR_WRITE_PORTS-1:0] we_i ); localparam NUM_WORDS = 2**ADDR_WIDTH; logic clk; logic [NUM_WORDS-1:0] mem_clocks; logic [NUM_WORDS-1:0][DATA_WIDTH-1:0] mem; logic [NR_WRITE_PORTS-1:0][DATA_WIDTH-1:0] wdata_q; logic [NR_WRITE_PORTS-1:0][NUM_WORDS-1:0] waddr_onehot; logic [NUM_WORDS-1:0][NR_WRITE_PORTS-1:0] waddr_onehot_trans; // transposed index version for (genvar i = 0; i < NR_WRITE_PORTS; i++) begin for (genvar j = 0; j < NUM_WORDS; j++) begin assign waddr_onehot_trans[j][i] = waddr_onehot[i][j]; end end tc_clk_gating i_regfile_cg ( .clk_i, .en_i ( |we_i ), .test_en_i ( 1'b0 ), .clk_o ( clk ) ); // Sample Input Data for (genvar i = 0; i < NR_WRITE_PORTS; i++) begin always_ff @(posedge clk) wdata_q[i] <= wdata_i[i]; for (genvar j = ZERO_REG_ZERO; j < NUM_WORDS; j++) begin always_comb begin if (we_i[i] && waddr_i[i] == j) waddr_onehot[i][j] = 1'b1; else waddr_onehot[i][j] = 1'b0; end end end for (genvar i = 0; i < NUM_WORDS; i++) begin tc_clk_gating i_regfile_cg ( .clk_i ( clk ), .en_i ( |waddr_onehot_trans[i] ), .test_en_i ( 1'b0 ), .clk_o ( mem_clocks[i] ) ); end always_latch begin if (ZERO_REG_ZERO) mem[0] = '0; for (int unsigned i = ZERO_REG_ZERO; i < NUM_WORDS; i++) begin for (int unsigned j = 0; j < NR_WRITE_PORTS; j++) begin if (mem_clocks[i]) begin // TODO(zarubaf) generalize to more than 1 read port mem[i] = wdata_q[j]; end end end end for (genvar i = 0; i < NR_READ_PORTS; i++) assign rdata_o[i] = mem[raddr_i[i][ADDR_WIDTH-1:0]]; endmodule