Relocate RegFile from TOP level to CORE level (#95)

Remove dead and related code

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>
Co-authored-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>
This commit is contained in:
christian-herber-nxp 2023-03-03 17:09:12 +01:00 committed by GitHub
parent ec096aafd3
commit 823f596047
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 22 additions and 425 deletions

View file

@ -5,13 +5,6 @@ Getting Started with Ibex
This page discusses initial steps and requirements to start using Ibex in your design.
Register File
-------------
Ibex comes with three different register file implementations that can be selected using the enumerated parameter ``RegFile`` defined in :file:`rtl/cve2_pkg.sv`.
Depending on the target technology, either the flip-flop-based ("cve2_pkg::RegFileFF", default), the latch-based ("cve2_pkg::RegFileLatch") or an FPGA-targeted ("cve2_pkg::RegFileFPGA") implementation should be selected.
For more information about the three register file implementations and their trade-offs, check out :ref:`register-file`.
Identification CSRs
-------------------

View file

@ -18,7 +18,6 @@ Instantiation Template
.MHPMCounterWidth ( 40 ),
.RV32E ( 0 ),
.RV32M ( cve2_pkg::RV32MFast ),
.RegFile ( cve2_pkg::RegFileFF ),
.BranchPrediction ( 0 ),
.RndCnstLfsrSeed ( cve2_pkg::RndCnstLfsrSeedDefault ),
.RndCnstLfsrPerm ( cve2_pkg::RndCnstLfsrPermDefault ),
@ -95,11 +94,6 @@ Parameters
| | | | "cve2_pkg::RV32MFast": 3-4 cycle multiplier, iterative divider |
| | | | "cve2_pkg::RV32MSingleCycle": 1-2 cycle multiplier, iterative divider |
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
| ``RegFile`` | cve2_pkg::regfile_e | RegFileFF | Register file implementation select: |
| | | | "cve2_pkg::RegFileFF": Generic flip-flop-based register file |
| | | | "cve2_pkg::RegFileFPGA": Register file for FPGA targets |
| | | | "cve2_pkg::RegFileLatch": Latch-based register file for ASIC targets |
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
| | | | improving performance of loads and stores |
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+

View file

@ -2,79 +2,17 @@
Register File
=============
Source Files: :file:`rtl/cve2_register_file_ff.sv` :file:`rtl/cve2_register_file_fpga.sv` :file:`rtl/cve2_register_file_latch.sv`
Source File: :file:`rtl/cve2_register_file_ff.sv`
Ibex has either 31 or 15 32-bit registers if the RV32E extension is disabled or enabled, respectively.
CVE2 has either 31 or 15 32-bit registers if the RV32E extension is disabled or enabled, respectively.
Register ``x0`` is statically bound to 0 and can only be read, it does not contain any sequential logic.
The register file has two read ports and one write port, register file data is available the same cycle a read is requested.
There is no write to read forwarding path so if one register is being both read and written the read will return the current value rather than the value being written.
There are three flavors of register file available, each having their own benefits and trade-offs.
The register file flavor is selected via the enumerated parameter ``RegFile`` defined in :file:`rtl/cve2_pkg.sv`.
Flip-Flop-Based Register File
-----------------------------
The flip-flop-based register file uses regular, positive-edge-triggered flip-flops to implement the registers.
This makes it the **first choice when simulating the design using Verilator**.
This implementation can be selected by setting the ``RegFile`` parameter to "cve2_pkg::RegFileFF".
It is the default selection.
FPGA Register File
------------------
The FPGA register file leverages synchronous-write / asynchronous-read RAM design elements, where available on FPGA targets.
For Xilinx FPGAs, synthesis results in an implementation using RAM32M primitives. Using this design with a Xilinx Artya7-100 FPGA conserves around 600 Logic LUTs and 1000 flip-flops at the expense of 48 LUTRAMs for the 31-entry register file as compared to the flip-flop-based register file.
This makes it the **first choice for FPGA synthesis**.
To select the FPGA register file, set the ``RegFile`` parameter to "cve2_pkg::RegFileFPGA".
Latch-Based Register File
-------------------------
The latch-based register file uses level-sensitive latches to implement the registers.
This allows for significant area savings compared to an implementation using regular flip-flops and thus makes the latch-based register file the **first choice for ASIC implementations**.
Simulation of the latch-based register file is possible using commercial tools.
.. note:: The latch-based register file cannot be simulated using Verilator.
The latch-based register file can also be used for FPGA synthesis, but this is not recommended as FPGAs usually do not well support latches.
To select the latch-based register file, set the ``RegFile`` parameter to "cve2_pkg::RegFileLatch".
In addition, a technology-specific clock gating cell must be provided to keep the clock inactive when the latches are not written.
This cell must be wrapped in a module called ``prim_clock_gating``.
For more information regarding the clock gating cell, checkout :ref:`getting-started`.
.. note:: The latch-based register file requires the gated clock to be enabled in the cycle after the write enable ``we_a_i`` signal was set high.
This can be achieved by latching ``we_a_i`` in the clock gating cell during the low phase of ``clk_i``.
The resulting behavior of the latch-based register file is visualized in :numref:`timing`.
The input data ``wdata_a_i`` is sampled into a flip-flop-based register ``wdata_a_q`` using ``clk_int``.
The actual latch-based registers ``mem[1]`` and ``mem[2]`` are transparent during high phases of ``mem_clk[1]`` and ``mem_clk[2]``, respectively.
Their content is sampled from ``wdata_a_q`` on falling edges of these clocks.
.. wavedrom::
:name: timing
:caption: Latch-based register file operation
{"signal":
[
{"name": "clk_i", "wave": "hlhlhlhl"},
{"name": "we_a_i", "wave": "0.1...0."},
{"name": "waddr_a_i", "wave": "xx=.=.xx", "data": ["1","2"]},
{"name": "wdata_a_i", "wave": "xx=.=.xx", "data": ["Data1","Data2"]},
{"name": "clk_int", "wave": "0...HlHl"},
{"name": "wdata_a_q", "wave": "xxxx=.=.", "data": ["Data1", "Data2"]},
{"name": "mem_clk[1]", "wave": "0...hL.."},
{"name": "mem[1]", "wave": "xxxx=...", "data": ["Data1"]},
{"name": "mem_clk[2]", "wave": "0.....hL"},
{"name": "mem[2]", "wave": "xxxxxx=.", "data": ["Data2"]}
],
"config": { "hscale": 2 }
}

View file

@ -54,15 +54,6 @@ module cve2_core import cve2_pkg::*; #(
input logic [31:0] data_rdata_i,
input logic data_err_i,
// Register file interface
output logic [4:0] rf_raddr_a_o,
output logic [4:0] rf_raddr_b_o,
output logic [4:0] rf_waddr_wb_o,
output logic rf_we_wb_o,
output logic [31:0] rf_wdata_wb_ecc_o,
input logic [31:0] rf_rdata_a_ecc_i,
input logic [31:0] rf_rdata_b_ecc_i,
// Interrupt inputs
input logic irq_software_i,
input logic irq_timer_i,
@ -180,7 +171,6 @@ module cve2_core import cve2_pkg::*; #(
logic [31:0] rf_wdata_lsu;
logic rf_we_wb;
logic rf_we_lsu;
logic rf_ecc_err_comb;
logic [4:0] rf_waddr_id;
logic [31:0] rf_wdata_id;
@ -678,20 +668,6 @@ module cve2_core import cve2_pkg::*; #(
assign rf_we_wb_o = rf_we_wb;
assign rf_raddr_b_o = rf_raddr_b;
begin : gen_no_regfile_ecc
logic unused_rf_ren_a, unused_rf_ren_b;
logic unused_rf_rd_a_wb_match, unused_rf_rd_b_wb_match;
assign unused_rf_ren_a = rf_ren_a;
assign unused_rf_ren_b = rf_ren_b;
assign unused_rf_rd_a_wb_match = rf_rd_a_wb_match;
assign unused_rf_rd_b_wb_match = rf_rd_b_wb_match;
assign rf_wdata_wb_ecc_o = rf_wdata_wb;
assign rf_rdata_a = rf_rdata_a_ecc_i;
assign rf_rdata_b = rf_rdata_b_ecc_i;
assign rf_ecc_err_comb = 1'b0;
end
///////////////////////
// Crash dump output //
///////////////////////
@ -708,9 +684,6 @@ module cve2_core import cve2_pkg::*; #(
// Minor alert - core is in a recoverable state
assign alert_minor_o = 1'b0;
// Major alert - core is unrecoverable
assign alert_major_o = rf_ecc_err_comb;
// Explict INC_ASSERT block to avoid unused signal lint warnings were asserts are not included
`ifdef INC_ASSERT
// Signals used for assertions only
@ -753,8 +726,26 @@ module cve2_core import cve2_pkg::*; #(
////////////////////////
// RF (Register File) //
////////////////////////
`ifdef RVFI
`endif
begin : gen_regfile_ff
cve2_register_file_ff #(
.RV32E (RV32E),
.DataWidth (32),
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
) register_file_i (
.clk_i (clk_i),
.rst_ni(rst_ni),
.test_en_i (test_en_i),
.raddr_a_i(rf_raddr_a),
.rdata_a_o(rf_rdata_a),
.raddr_b_i(rf_raddr_b),
.rdata_b_o(rf_rdata_b),
.waddr_a_i(rf_waddr_wb),
.wdata_a_i(rf_wdata_wb),
.we_a_i (rf_we_wb)
);
end
/////////////////////////////////////////

View file

@ -31,12 +31,6 @@ package cve2_pkg;
// Parameter Enums //
/////////////////////
typedef enum integer {
RegFileFF = 0,
RegFileFPGA = 1,
RegFileLatch = 2
} regfile_e;
typedef enum integer {
RV32MNone = 0,
RV32MSlow = 1,

View file

@ -1,82 +0,0 @@
// Copyright lowRISC contributors.
// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* RISC-V register file
*
* Register file with 31 or 15x 32 bit wide registers. Register 0 is fixed to 0.
*
* 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 cve2_register_file_fpga #(
parameter bit RV32E = 0,
parameter int unsigned DataWidth = 32,
parameter logic [DataWidth-1:0] WordZeroVal = '0
) (
// Clock and Reset
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic dummy_instr_id_i,
//Read port R1
input logic [ 4:0] raddr_a_i,
output logic [DataWidth-1:0] rdata_a_o,
//Read port R2
input logic [ 4:0] raddr_b_i,
output logic [DataWidth-1:0] rdata_b_o,
// Write port W1
input logic [ 4:0] waddr_a_i,
input logic [DataWidth-1:0] wdata_a_i,
input logic we_a_i
);
localparam int ADDR_WIDTH = RV32E ? 4 : 5;
localparam int NUM_WORDS = 2 ** ADDR_WIDTH;
logic [DataWidth-1:0] mem[NUM_WORDS];
logic we; // write enable if writing to any register other than R0
// async_read a
assign rdata_a_o = (raddr_a_i == '0) ? '0 : mem[raddr_a_i];
// async_read b
assign rdata_b_o = (raddr_b_i == '0) ? '0 : mem[raddr_b_i];
// we select
assign we = (waddr_a_i == '0) ? 1'b0 : we_a_i;
// 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 : sync_write
if (we == 1'b1) begin
mem[waddr_a_i] <= wdata_a_i;
end
end : sync_write
// Make sure we initialize the BRAM with the correct register reset value.
initial begin
for (int k = 0; k < NUM_WORDS; k++) begin
mem[k] = WordZeroVal;
end
end
// Reset not used in this register file version
logic unused_rst_ni;
assign unused_rst_ni = rst_ni;
// Dummy instruction changes not relevant for FPGA implementation
logic unused_dummy_instr;
assign unused_dummy_instr = dummy_instr_id_i;
// Test enable signal not used in FPGA implementation
logic unused_test_en;
assign unused_test_en = test_en_i;
endmodule

View file

@ -1,135 +0,0 @@
// Copyright lowRISC contributors.
// Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* RISC-V register file
*
* Register file with 31 or 15x 32 bit wide registers. Register 0 is fixed to 0.
* This register file is based on latches and is thus smaller than the flip-flop
* based RF. It requires a target technology-specific clock gating cell. Use this
* register file when targeting ASIC synthesis or event-based simulators.
*/
module cve2_register_file_latch #(
parameter bit RV32E = 0,
parameter int unsigned DataWidth = 32,
parameter logic [DataWidth-1:0] WordZeroVal = '0
) (
// Clock and Reset
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic dummy_instr_id_i,
//Read port R1
input logic [4:0] raddr_a_i,
output logic [DataWidth-1:0] rdata_a_o,
//Read port R2
input logic [4:0] raddr_b_i,
output logic [DataWidth-1:0] rdata_b_o,
// Write port W1
input logic [4:0] waddr_a_i,
input logic [DataWidth-1:0] wdata_a_i,
input logic we_a_i
);
localparam int unsigned ADDR_WIDTH = RV32E ? 4 : 5;
localparam int unsigned NUM_WORDS = 2**ADDR_WIDTH;
logic [DataWidth-1:0] mem[NUM_WORDS];
logic [NUM_WORDS-1:1] waddr_onehot_a;
logic [NUM_WORDS-1:1] mem_clocks;
logic [DataWidth-1:0] wdata_a_q;
// internal addresses
logic [ADDR_WIDTH-1:0] raddr_a_int, raddr_b_int, waddr_a_int;
assign raddr_a_int = raddr_a_i[ADDR_WIDTH-1:0];
assign raddr_b_int = raddr_b_i[ADDR_WIDTH-1:0];
assign waddr_a_int = waddr_a_i[ADDR_WIDTH-1:0];
logic clk_int;
//////////
// READ //
//////////
assign rdata_a_o = mem[raddr_a_int];
assign rdata_b_o = mem[raddr_b_int];
///////////
// WRITE //
///////////
// Global clock gating
prim_clock_gating cg_we_global (
.clk_i ( clk_i ),
.en_i ( we_a_i ),
.test_en_i ( test_en_i ),
.clk_o ( clk_int )
);
// Sample input data
// Use clk_int here, since otherwise we don't want to write anything anyway.
always_ff @(posedge clk_int or negedge rst_ni) begin : sample_wdata
if (!rst_ni) begin
wdata_a_q <= WordZeroVal;
end else begin
if (we_a_i) begin
wdata_a_q <= wdata_a_i;
end
end
end
// Write address decoding
always_comb begin : wad
for (int i = 1; i < NUM_WORDS; i++) begin : wad_word_iter
if (we_a_i && (waddr_a_int == 5'(i))) begin
waddr_onehot_a[i] = 1'b1;
end else begin
waddr_onehot_a[i] = 1'b0;
end
end
end
// Individual clock gating (if integrated clock-gating cells are available)
for (genvar x = 1; x < NUM_WORDS; x++) begin : gen_cg_word_iter
prim_clock_gating cg_i (
.clk_i ( clk_int ),
.en_i ( waddr_onehot_a[x] ),
.test_en_i ( test_en_i ),
.clk_o ( mem_clocks[x] )
);
end
// Actual write operation:
// Generate the sequential process for the NUM_WORDS words of the memory.
// The process is synchronized with the clocks mem_clocks[i], i = 1, ..., NUM_WORDS-1.
for (genvar i = 1; i < NUM_WORDS; i++) begin : g_rf_latches
always_latch begin
if (mem_clocks[i]) begin
mem[i] = wdata_a_q;
end
end
end
begin : g_normal_r0
logic unused_dummy_instr_id;
assign unused_dummy_instr_id = dummy_instr_id_i;
assign mem[0] = WordZeroVal;
end
`ifdef VERILATOR
initial begin
$display("Latch-based register file not supported for Verilator simulation");
$fatal;
end
`endif
endmodule

View file

@ -17,7 +17,6 @@ module cve2_top import cve2_pkg::*; #(
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 1'b0,
parameter rv32m_e RV32M = RV32MFast,
parameter regfile_e RegFile = RegFileFF,
parameter bit WritebackStage = 1'b0,
parameter bit BranchPredictor = 1'b0,
parameter int unsigned DmHaltAddr = 32'h1A110800,
@ -130,14 +129,6 @@ module cve2_top import cve2_pkg::*; #(
logic core_busy_d, core_busy_q;
logic clock_en;
logic irq_pending;
// Core <-> Register file signals
logic [4:0] rf_raddr_a;
logic [4:0] rf_raddr_b;
logic [4:0] rf_waddr_wb;
logic rf_we_wb;
logic [31:0] rf_wdata_wb_ecc;
logic [31:0] rf_rdata_a_ecc, rf_rdata_a_ecc_buf;
logic [31:0] rf_rdata_b_ecc, rf_rdata_b_ecc_buf;
// Alert signals
logic core_alert_major, core_alert_minor;
@ -167,16 +158,6 @@ module cve2_top import cve2_pkg::*; #(
// Core instantiation //
////////////////////////
prim_buf #(.Width(32)) u_rf_rdata_a_ecc_buf (
.in_i (rf_rdata_a_ecc),
.out_o(rf_rdata_a_ecc_buf)
);
prim_buf #(.Width(32)) u_rf_rdata_b_ecc_buf (
.in_i (rf_rdata_b_ecc),
.out_o(rf_rdata_b_ecc_buf)
);
cve2_core #(
.PMPEnable (PMPEnable),
.PMPGranularity (PMPGranularity),
@ -216,14 +197,6 @@ module cve2_top import cve2_pkg::*; #(
.data_rdata_i,
.data_err_i,
.rf_raddr_a_o (rf_raddr_a),
.rf_raddr_b_o (rf_raddr_b),
.rf_waddr_wb_o (rf_waddr_wb),
.rf_we_wb_o (rf_we_wb),
.rf_wdata_wb_ecc_o(rf_wdata_wb_ecc),
.rf_rdata_a_ecc_i (rf_rdata_a_ecc), //_buf),
.rf_rdata_b_ecc_i (rf_rdata_b_ecc), //_buf),
.irq_software_i,
.irq_timer_i,
.irq_external_i,
@ -269,69 +242,6 @@ module cve2_top import cve2_pkg::*; #(
.core_busy_o (core_busy_d)
);
/////////////////////////////////
// Register file Instantiation //
/////////////////////////////////
if (RegFile == RegFileFF) begin : gen_regfile_ff
cve2_register_file_ff #(
.RV32E (RV32E),
.DataWidth (32),
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
) register_file_i (
.clk_i (clk),
.rst_ni(rst_ni),
.test_en_i (test_en_i),
.raddr_a_i(rf_raddr_a),
.rdata_a_o(rf_rdata_a_ecc),
.raddr_b_i(rf_raddr_b),
.rdata_b_o(rf_rdata_b_ecc),
.waddr_a_i(rf_waddr_wb),
.wdata_a_i(rf_wdata_wb_ecc),
.we_a_i (rf_we_wb)
);
end else if (RegFile == RegFileFPGA) begin : gen_regfile_fpga
cve2_register_file_fpga #(
.RV32E (RV32E),
.DataWidth (32),
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
) register_file_i (
.clk_i (clk),
.rst_ni(rst_ni),
.test_en_i (test_en_i),
.raddr_a_i(rf_raddr_a),
.rdata_a_o(rf_rdata_a_ecc),
.raddr_b_i(rf_raddr_b),
.rdata_b_o(rf_rdata_b_ecc),
.waddr_a_i(rf_waddr_wb),
.wdata_a_i(rf_wdata_wb_ecc),
.we_a_i (rf_we_wb)
);
end else if (RegFile == RegFileLatch) begin : gen_regfile_latch
cve2_register_file_latch #(
.RV32E (RV32E),
.DataWidth (32),
.WordZeroVal (32'(prim_secded_pkg::SecdedInv3932ZeroWord))
) register_file_i (
.clk_i (clk),
.rst_ni(rst_ni),
.test_en_i (test_en_i),
.raddr_a_i(rf_raddr_a),
.rdata_a_o(rf_rdata_a_ecc),
.raddr_b_i(rf_raddr_b),
.rdata_b_o(rf_rdata_b_ecc),
.waddr_a_i(rf_waddr_wb),
.wdata_a_i(rf_wdata_wb_ecc),
.we_a_i (rf_we_wb)
);
end
////////////////////////
// Rams Instantiation //
////////////////////////
@ -346,10 +256,6 @@ module cve2_top import cve2_pkg::*; #(
end
assign alert_major_internal_o = core_alert_major;
assign alert_major_bus_o = 1'b0;
assign alert_minor_o = core_alert_minor;
// X checks for top-level outputs
`ASSERT_KNOWN(IbexInstrReqX, instr_req_o)
`ASSERT_KNOWN_IF(IbexInstrReqPayloadX, instr_addr_o, instr_req_o)

View file

@ -12,7 +12,6 @@ module cve2_top_tracing import cve2_pkg::*; #(
parameter bit RV32E = 1'b0,
parameter rv32m_e RV32M = RV32MFast,
parameter rv32b_e RV32B = RV32BNone,
parameter regfile_e RegFile = RegFileFF,
parameter bit WritebackStage = 1'b0,
parameter bit BranchPredictor = 1'b0,
parameter bit DbgTriggerEn = 1'b0,
@ -124,7 +123,6 @@ module cve2_top_tracing import cve2_pkg::*; #(
.RV32E ( RV32E ),
.RV32M ( RV32M ),
.RV32B ( RV32B ),
.RegFile ( RegFile ),
.BranchPredictor ( BranchPredictor ),
.DbgTriggerEn ( DbgTriggerEn ),
.DbgHwBreakNum ( DbgHwBreakNum ),