mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-25 06:27:22 -04:00
[rtl] Instantiate instruction cache
- Add parameters and actual instantiation of icache - Add a custom CSR in the M-mode custom RW range to enable the cache - Wire up the cache invalidation signal to trigger on fence.i Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
parent
e9171001c3
commit
c054a63c3d
16 changed files with 235 additions and 35 deletions
|
@ -66,6 +66,8 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0x7B3 | ``dscratch1`` | RW | Debug Scratch Register 1 |
|
| 0x7B3 | ``dscratch1`` | RW | Debug Scratch Register 1 |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
|
| 0x7C0 | ``cpuctrl`` | RW | CPU Control Register (Custom CSR) |
|
||||||
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0xB00 | ``mcycle`` | RW | Machine Cycle Counter |
|
| 0xB00 | ``mcycle`` | RW | Machine Cycle Counter |
|
||||||
+---------+--------------------+--------+-----------------------------------------------+
|
+---------+--------------------+--------+-----------------------------------------------+
|
||||||
| 0xB02 | ``minstret`` | RW | Machine Instructions-Retired Counter |
|
| 0xB02 | ``minstret`` | RW | Machine Instructions-Retired Counter |
|
||||||
|
@ -483,6 +485,26 @@ Reset Value: ``0x0000_0000``
|
||||||
Scratch register to be used by the debug module.
|
Scratch register to be used by the debug module.
|
||||||
Accessible in Debug Mode only.
|
Accessible in Debug Mode only.
|
||||||
|
|
||||||
|
CPU Control Register (cpuctrl)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
CSR Address: ``0x7C0``
|
||||||
|
|
||||||
|
Reset Value: ``0x0000_0000``
|
||||||
|
|
||||||
|
Custom CSR to control runtime configuration of CPU components.
|
||||||
|
Accessible in Machine Mode only.
|
||||||
|
Ibex implements the following bit fields.
|
||||||
|
Other bit fields read as zero.
|
||||||
|
|
||||||
|
+-------+------+------------------------------------------------------------------+
|
||||||
|
| Bit# | R/W | Description |
|
||||||
|
+-------+------+------------------------------------------------------------------+
|
||||||
|
| 0 | WARL | **icache_enable:** Enable (1) or disable (0) the instruction |
|
||||||
|
| | | cache. If the instruction cache has not been configured (ICache |
|
||||||
|
| | | parameter == 0), this field will always read as zero. |
|
||||||
|
+-------+------+------------------------------------------------------------------+
|
||||||
|
|
||||||
Time Registers (time(h))
|
Time Registers (time(h))
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,11 @@ A localparam ``DEPTH`` gives a configurable depth which is set to 3 by default.
|
||||||
The top-level of the instruction fetch controls the prefetch buffer (in particular flushing it on branches/jumps/exception and beginning prefetching from the appropriate new PC) and supplies new instructions to the ID/EX stage along with their PC.
|
The top-level of the instruction fetch controls the prefetch buffer (in particular flushing it on branches/jumps/exception and beginning prefetching from the appropriate new PC) and supplies new instructions to the ID/EX stage along with their PC.
|
||||||
Compressed instructions are expanded by the IF stage so the decoder can always deal with uncompressed instructions (the ID stage still receives the compressed instruction for placing into ``mtval`` on an illegal instruction exception).
|
Compressed instructions are expanded by the IF stage so the decoder can always deal with uncompressed instructions (the ID stage still receives the compressed instruction for placing into ``mtval`` on an illegal instruction exception).
|
||||||
|
|
||||||
|
If Ibex has been configured with an instruction cache (parameter ICache == 1), then the prefetch buffer is replaced by the icache module (:ref:`icache`).
|
||||||
|
The interfaces of the icache module are the same as the prefetch buffer with two additions.
|
||||||
|
Firstly, a signal to enable the cache which is driven from a custom CSR.
|
||||||
|
Secondly a signal to the flush the cache which is set every time a ``fence.i`` instruction is executed.
|
||||||
|
|
||||||
Instruction-Side Memory Interface
|
Instruction-Side Memory Interface
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ Instantiation Template
|
||||||
.RV32E ( 0 ),
|
.RV32E ( 0 ),
|
||||||
.RV32M ( 1 ),
|
.RV32M ( 1 ),
|
||||||
.MultiplierImplementation ( "fast" ),
|
.MultiplierImplementation ( "fast" ),
|
||||||
|
.ICache ( 0 ),
|
||||||
|
.ICacheECC ( 0 ),
|
||||||
.DbgTriggerEn ( 0 ),
|
.DbgTriggerEn ( 0 ),
|
||||||
.DmHaltAddr ( 32'h1A110800 ),
|
.DmHaltAddr ( 32'h1A110800 ),
|
||||||
.DmExceptionAddr ( 32'h1A110808 )
|
.DmExceptionAddr ( 32'h1A110808 )
|
||||||
|
@ -98,6 +100,12 @@ Parameters
|
||||||
| | | | "fast": multi-cycle fast, |
|
| | | | "fast": multi-cycle fast, |
|
||||||
| | | | "single-cycle": single-cycle |
|
| | | | "single-cycle": single-cycle |
|
||||||
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
||||||
|
| ``ICache`` | bit | 0 | *EXPERIMENTAL* Enable instruction cache instead of prefetch |
|
||||||
|
| | | | buffer |
|
||||||
|
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
||||||
|
| ``ICacheECC`` | bit | 0 | *EXPERIMENTAL* Enable SECDED ECC protection in ICache (if |
|
||||||
|
| | | | ICache == 1) |
|
||||||
|
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
||||||
| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) |
|
| ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) |
|
||||||
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
||||||
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
|
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
module tb_cs_registers #(
|
module tb_cs_registers #(
|
||||||
parameter bit DbgTriggerEn = 0,
|
parameter bit DbgTriggerEn = 0,
|
||||||
|
parameter bit ICache = 0,
|
||||||
parameter int unsigned MHPMCounterNum = 8,
|
parameter int unsigned MHPMCounterNum = 8,
|
||||||
parameter int unsigned MHPMCounterWidth = 40,
|
parameter int unsigned MHPMCounterWidth = 40,
|
||||||
parameter bit PMPEnable = 0,
|
parameter bit PMPEnable = 0,
|
||||||
|
@ -70,6 +71,8 @@ module tb_cs_registers #(
|
||||||
logic [31:0] pc_id_i;
|
logic [31:0] pc_id_i;
|
||||||
logic [31:0] pc_wb_i;
|
logic [31:0] pc_wb_i;
|
||||||
|
|
||||||
|
logic icache_enable_o;
|
||||||
|
|
||||||
logic csr_save_if_i;
|
logic csr_save_if_i;
|
||||||
logic csr_save_id_i;
|
logic csr_save_id_i;
|
||||||
logic csr_save_wb_i;
|
logic csr_save_wb_i;
|
||||||
|
|
|
@ -14,6 +14,11 @@ ${PRJ_DIR}/ibex/shared/rtl/prim_clock_gating.sv
|
||||||
// ibex CORE RTL files
|
// ibex CORE RTL files
|
||||||
+incdir+${PRJ_DIR}/ibex/rtl
|
+incdir+${PRJ_DIR}/ibex/rtl
|
||||||
${PRJ_DIR}/ibex/shared/rtl/prim_assert.sv
|
${PRJ_DIR}/ibex/shared/rtl/prim_assert.sv
|
||||||
|
${PRJ_DIR}/ibex/shared/rtl/prim_generic_ram_1p.sv
|
||||||
|
${PRJ_DIR}/ibex/shared/rtl/prim_secded_28_22_enc.sv
|
||||||
|
${PRJ_DIR}/ibex/shared/rtl/prim_secded_28_22_dec.sv
|
||||||
|
${PRJ_DIR}/ibex/shared/rtl/prim_secded_72_64_enc.sv
|
||||||
|
${PRJ_DIR}/ibex/shared/rtl/prim_secded_72_64_dec.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_pkg.sv
|
${PRJ_DIR}/ibex/rtl/ibex_pkg.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_tracer_pkg.sv
|
${PRJ_DIR}/ibex/rtl/ibex_tracer_pkg.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
|
${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
|
||||||
|
@ -26,6 +31,7 @@ ${PRJ_DIR}/ibex/rtl/ibex_decoder.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_ex_block.sv
|
${PRJ_DIR}/ibex/rtl/ibex_ex_block.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_wb_stage.sv
|
${PRJ_DIR}/ibex/rtl/ibex_wb_stage.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_id_stage.sv
|
${PRJ_DIR}/ibex/rtl/ibex_id_stage.sv
|
||||||
|
${PRJ_DIR}/ibex/rtl/ibex_icache.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_if_stage.sv
|
${PRJ_DIR}/ibex/rtl/ibex_if_stage.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_load_store_unit.sv
|
${PRJ_DIR}/ibex/rtl/ibex_load_store_unit.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_multdiv_slow.sv
|
${PRJ_DIR}/ibex/rtl/ibex_multdiv_slow.sv
|
||||||
|
|
|
@ -87,4 +87,7 @@ targets:
|
||||||
# XXX: Cleanup all warnings and remove this option
|
# XXX: Cleanup all warnings and remove this option
|
||||||
# (or make it more fine-grained at least)
|
# (or make it more fine-grained at least)
|
||||||
- "-Wno-fatal"
|
- "-Wno-fatal"
|
||||||
|
# RAM primitives wider than 64bit (required for ECC) fail to build in
|
||||||
|
# Verilator without increasing the unroll count (see Verilator#1266)
|
||||||
|
- "--unroll-count 72"
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ filesets:
|
||||||
- rtl/ibex_decoder.sv
|
- rtl/ibex_decoder.sv
|
||||||
- rtl/ibex_ex_block.sv
|
- rtl/ibex_ex_block.sv
|
||||||
- rtl/ibex_fetch_fifo.sv
|
- rtl/ibex_fetch_fifo.sv
|
||||||
|
- rtl/ibex_icache.sv
|
||||||
- rtl/ibex_id_stage.sv
|
- rtl/ibex_id_stage.sv
|
||||||
- rtl/ibex_if_stage.sv
|
- rtl/ibex_if_stage.sv
|
||||||
- rtl/ibex_load_store_unit.sv
|
- rtl/ibex_load_store_unit.sv
|
||||||
|
@ -70,6 +71,18 @@ parameters:
|
||||||
description: "Multiplier implementation. Valid values: fast, slow"
|
description: "Multiplier implementation. Valid values: fast, slow"
|
||||||
default: fast
|
default: fast
|
||||||
|
|
||||||
|
ICache:
|
||||||
|
datatype: bool
|
||||||
|
paramtype: vlogparam
|
||||||
|
description: "Enable instruction cache"
|
||||||
|
default: false
|
||||||
|
|
||||||
|
ICacheECC:
|
||||||
|
datatype: bool
|
||||||
|
paramtype: vlogparam
|
||||||
|
description: "Enable ECC protection in instruction cache"
|
||||||
|
default: false
|
||||||
|
|
||||||
BranchTargetALU:
|
BranchTargetALU:
|
||||||
datatype: int
|
datatype: int
|
||||||
paramtype: vlogparam
|
paramtype: vlogparam
|
||||||
|
@ -104,6 +117,9 @@ targets:
|
||||||
mode: lint-only
|
mode: lint-only
|
||||||
verilator_options:
|
verilator_options:
|
||||||
- "-Wall"
|
- "-Wall"
|
||||||
|
# RAM primitives wider than 64bit (required for ECC) fail to build in
|
||||||
|
# Verilator without increasing the unroll count (see Verilator#1266)
|
||||||
|
- "--unroll-count 72"
|
||||||
veriblelint:
|
veriblelint:
|
||||||
ruleset: default
|
ruleset: default
|
||||||
rules:
|
rules:
|
||||||
|
|
|
@ -46,6 +46,18 @@ parameters:
|
||||||
description: "Multiplier implementation. Valid values: fast, slow"
|
description: "Multiplier implementation. Valid values: fast, slow"
|
||||||
default: fast
|
default: fast
|
||||||
|
|
||||||
|
ICache:
|
||||||
|
datatype: bool
|
||||||
|
paramtype: vlogparam
|
||||||
|
description: "Enable instruction cache"
|
||||||
|
default: false
|
||||||
|
|
||||||
|
ICacheECC:
|
||||||
|
datatype: bool
|
||||||
|
paramtype: vlogparam
|
||||||
|
description: "Enable ECC protection in instruction cache"
|
||||||
|
default: false
|
||||||
|
|
||||||
BranchTargetALU:
|
BranchTargetALU:
|
||||||
datatype: int
|
datatype: int
|
||||||
paramtype: vlogparam
|
paramtype: vlogparam
|
||||||
|
@ -79,6 +91,9 @@ targets:
|
||||||
mode: lint-only
|
mode: lint-only
|
||||||
verilator_options:
|
verilator_options:
|
||||||
- "-Wall"
|
- "-Wall"
|
||||||
|
# RAM primitives wider than 64bit (required for ECC) fail to build in
|
||||||
|
# Verilator without increasing the unroll count (see Verilator#1266)
|
||||||
|
- "--unroll-count 72"
|
||||||
veriblelint:
|
veriblelint:
|
||||||
ruleset: default
|
ruleset: default
|
||||||
rules:
|
rules:
|
||||||
|
|
|
@ -21,6 +21,8 @@ module ibex_core #(
|
||||||
parameter bit BranchTargetALU = 1'b0,
|
parameter bit BranchTargetALU = 1'b0,
|
||||||
parameter bit WritebackStage = 1'b0,
|
parameter bit WritebackStage = 1'b0,
|
||||||
parameter MultiplierImplementation = "fast",
|
parameter MultiplierImplementation = "fast",
|
||||||
|
parameter bit ICache = 1'b0,
|
||||||
|
parameter bit ICacheECC = 1'b0,
|
||||||
parameter bit DbgTriggerEn = 1'b0,
|
parameter bit DbgTriggerEn = 1'b0,
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||||
|
@ -113,6 +115,9 @@ module ibex_core #(
|
||||||
logic [31:0] pc_id; // Program counter in ID stage
|
logic [31:0] pc_id; // Program counter in ID stage
|
||||||
logic [31:0] pc_wb; // Program counter in WB stage
|
logic [31:0] pc_wb; // Program counter in WB stage
|
||||||
|
|
||||||
|
logic icache_enable;
|
||||||
|
logic icache_inval;
|
||||||
|
|
||||||
logic instr_first_cycle_id;
|
logic instr_first_cycle_id;
|
||||||
logic instr_valid_clear;
|
logic instr_valid_clear;
|
||||||
logic pc_set;
|
logic pc_set;
|
||||||
|
@ -339,8 +344,10 @@ module ibex_core #(
|
||||||
//////////////
|
//////////////
|
||||||
|
|
||||||
ibex_if_stage #(
|
ibex_if_stage #(
|
||||||
.DmHaltAddr ( DmHaltAddr ),
|
.DmHaltAddr ( DmHaltAddr ),
|
||||||
.DmExceptionAddr ( DmExceptionAddr )
|
.DmExceptionAddr ( DmExceptionAddr ),
|
||||||
|
.ICache ( ICache ),
|
||||||
|
.ICacheECC ( ICacheECC )
|
||||||
) if_stage_i (
|
) if_stage_i (
|
||||||
.clk_i ( clk ),
|
.clk_i ( clk ),
|
||||||
.rst_ni ( rst_ni ),
|
.rst_ni ( rst_ni ),
|
||||||
|
@ -376,6 +383,8 @@ module ibex_core #(
|
||||||
.pc_mux_i ( pc_mux_id ),
|
.pc_mux_i ( pc_mux_id ),
|
||||||
.exc_pc_mux_i ( exc_pc_mux_id ),
|
.exc_pc_mux_i ( exc_pc_mux_id ),
|
||||||
.exc_cause ( exc_cause ),
|
.exc_cause ( exc_cause ),
|
||||||
|
.icache_enable_i ( icache_enable ),
|
||||||
|
.icache_inval_i ( icache_inval ),
|
||||||
|
|
||||||
// jump targets
|
// jump targets
|
||||||
.jump_target_ex_i ( jump_target_ex ),
|
.jump_target_ex_i ( jump_target_ex ),
|
||||||
|
@ -436,6 +445,7 @@ module ibex_core #(
|
||||||
.pc_mux_o ( pc_mux_id ),
|
.pc_mux_o ( pc_mux_id ),
|
||||||
.exc_pc_mux_o ( exc_pc_mux_id ),
|
.exc_pc_mux_o ( exc_pc_mux_id ),
|
||||||
.exc_cause_o ( exc_cause ),
|
.exc_cause_o ( exc_cause ),
|
||||||
|
.icache_inval_o ( icache_inval ),
|
||||||
|
|
||||||
.instr_fetch_err_i ( instr_fetch_err ),
|
.instr_fetch_err_i ( instr_fetch_err ),
|
||||||
.instr_fetch_err_plus2_i ( instr_fetch_err_plus2 ),
|
.instr_fetch_err_plus2_i ( instr_fetch_err_plus2 ),
|
||||||
|
@ -756,6 +766,7 @@ module ibex_core #(
|
||||||
|
|
||||||
ibex_cs_registers #(
|
ibex_cs_registers #(
|
||||||
.DbgTriggerEn ( DbgTriggerEn ),
|
.DbgTriggerEn ( DbgTriggerEn ),
|
||||||
|
.ICache ( ICache ),
|
||||||
.MHPMCounterNum ( MHPMCounterNum ),
|
.MHPMCounterNum ( MHPMCounterNum ),
|
||||||
.MHPMCounterWidth ( MHPMCounterWidth ),
|
.MHPMCounterWidth ( MHPMCounterWidth ),
|
||||||
.PMPEnable ( PMPEnable ),
|
.PMPEnable ( PMPEnable ),
|
||||||
|
@ -816,6 +827,8 @@ module ibex_core #(
|
||||||
.pc_id_i ( pc_id ),
|
.pc_id_i ( pc_id ),
|
||||||
.pc_wb_i ( pc_wb ),
|
.pc_wb_i ( pc_wb ),
|
||||||
|
|
||||||
|
.icache_enable_o ( icache_enable ),
|
||||||
|
|
||||||
.csr_save_if_i ( csr_save_if ),
|
.csr_save_if_i ( csr_save_if ),
|
||||||
.csr_save_id_i ( csr_save_id ),
|
.csr_save_id_i ( csr_save_id ),
|
||||||
.csr_save_wb_i ( csr_save_wb ),
|
.csr_save_wb_i ( csr_save_wb ),
|
||||||
|
|
|
@ -16,6 +16,8 @@ module ibex_core_tracing #(
|
||||||
parameter bit RV32M = 1'b1,
|
parameter bit RV32M = 1'b1,
|
||||||
parameter bit BranchTargetALU = 1'b0,
|
parameter bit BranchTargetALU = 1'b0,
|
||||||
parameter MultiplierImplementation = "fast",
|
parameter MultiplierImplementation = "fast",
|
||||||
|
parameter bit ICache = 1'b0,
|
||||||
|
parameter bit ICacheECC = 1'b0,
|
||||||
parameter bit DbgTriggerEn = 1'b0,
|
parameter bit DbgTriggerEn = 1'b0,
|
||||||
parameter bit WritebackStage = 1'b0,
|
parameter bit WritebackStage = 1'b0,
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
|
@ -103,6 +105,8 @@ module ibex_core_tracing #(
|
||||||
.RV32M ( RV32M ),
|
.RV32M ( RV32M ),
|
||||||
.BranchTargetALU ( BranchTargetALU ),
|
.BranchTargetALU ( BranchTargetALU ),
|
||||||
.MultiplierImplementation ( MultiplierImplementation ),
|
.MultiplierImplementation ( MultiplierImplementation ),
|
||||||
|
.ICache ( ICache ),
|
||||||
|
.ICacheECC ( ICacheECC ),
|
||||||
.DbgTriggerEn ( DbgTriggerEn ),
|
.DbgTriggerEn ( DbgTriggerEn ),
|
||||||
.WritebackStage ( WritebackStage ),
|
.WritebackStage ( WritebackStage ),
|
||||||
.DmHaltAddr ( DmHaltAddr ),
|
.DmHaltAddr ( DmHaltAddr ),
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
module ibex_cs_registers #(
|
module ibex_cs_registers #(
|
||||||
parameter bit DbgTriggerEn = 0,
|
parameter bit DbgTriggerEn = 0,
|
||||||
|
parameter bit ICache = 1'b0,
|
||||||
parameter int unsigned MHPMCounterNum = 10,
|
parameter int unsigned MHPMCounterNum = 10,
|
||||||
parameter int unsigned MHPMCounterWidth = 40,
|
parameter int unsigned MHPMCounterWidth = 40,
|
||||||
parameter bit PMPEnable = 0,
|
parameter bit PMPEnable = 0,
|
||||||
|
@ -77,6 +78,10 @@ module ibex_cs_registers #(
|
||||||
input logic [31:0] pc_id_i,
|
input logic [31:0] pc_id_i,
|
||||||
input logic [31:0] pc_wb_i,
|
input logic [31:0] pc_wb_i,
|
||||||
|
|
||||||
|
// CPU control bits
|
||||||
|
output logic icache_enable_o,
|
||||||
|
|
||||||
|
// Exception save/restore
|
||||||
input logic csr_save_if_i,
|
input logic csr_save_if_i,
|
||||||
input logic csr_save_id_i,
|
input logic csr_save_id_i,
|
||||||
input logic csr_save_wb_i,
|
input logic csr_save_wb_i,
|
||||||
|
@ -151,6 +156,12 @@ module ibex_cs_registers #(
|
||||||
priv_lvl_e prv;
|
priv_lvl_e prv;
|
||||||
} Dcsr_t;
|
} Dcsr_t;
|
||||||
|
|
||||||
|
// CPU control register fields
|
||||||
|
typedef struct packed {
|
||||||
|
logic [30:0] unused_ctrl;
|
||||||
|
logic icache_enable;
|
||||||
|
} CpuCtrl_t;
|
||||||
|
|
||||||
// Interrupt and exception control signals
|
// Interrupt and exception control signals
|
||||||
logic [31:0] exception_pc;
|
logic [31:0] exception_pc;
|
||||||
|
|
||||||
|
@ -200,6 +211,9 @@ module ibex_cs_registers #(
|
||||||
logic [31:0] tmatch_control_rdata;
|
logic [31:0] tmatch_control_rdata;
|
||||||
logic [31:0] tmatch_value_rdata;
|
logic [31:0] tmatch_value_rdata;
|
||||||
|
|
||||||
|
// CPU control bits
|
||||||
|
CpuCtrl_t cpuctrl_rdata, cpuctrl_wdata;
|
||||||
|
|
||||||
// CSR update logic
|
// CSR update logic
|
||||||
logic [31:0] csr_wdata_int;
|
logic [31:0] csr_wdata_int;
|
||||||
logic [31:0] csr_rdata_int;
|
logic [31:0] csr_rdata_int;
|
||||||
|
@ -398,6 +412,11 @@ module ibex_cs_registers #(
|
||||||
illegal_csr = ~DbgTriggerEn;
|
illegal_csr = ~DbgTriggerEn;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// Custom CSR for controlling CPU features
|
||||||
|
CSR_CPUCTRL: begin
|
||||||
|
csr_rdata_int = {cpuctrl_rdata};
|
||||||
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
illegal_csr = 1'b1;
|
illegal_csr = 1'b1;
|
||||||
end
|
end
|
||||||
|
@ -1016,6 +1035,44 @@ module ibex_cs_registers #(
|
||||||
assign trigger_match_o = 'b0;
|
assign trigger_match_o = 'b0;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// CPU control fields
|
||||||
|
assign cpuctrl_rdata.unused_ctrl = '0;
|
||||||
|
// Cast register write data
|
||||||
|
assign cpuctrl_wdata = CpuCtrl_t'(csr_wdata_int);
|
||||||
|
|
||||||
|
// Generate icache enable bit
|
||||||
|
if (ICache) begin : gen_icache_enable
|
||||||
|
logic icache_enable_d, icache_enable_q;
|
||||||
|
|
||||||
|
// Update the value when cpuctrl register is written
|
||||||
|
assign icache_enable_d = (csr_we_int & (csr_addr == CSR_CPUCTRL)) ?
|
||||||
|
cpuctrl_wdata.icache_enable : icache_enable_q;
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
icache_enable_q <= 1'b0; // disabled on reset
|
||||||
|
end else begin
|
||||||
|
icache_enable_q <= icache_enable_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign cpuctrl_rdata.icache_enable = icache_enable_q;
|
||||||
|
|
||||||
|
end else begin : gen_no_icache
|
||||||
|
// tieoff for the unused icen bit
|
||||||
|
logic unused_icen;
|
||||||
|
assign unused_icen = cpuctrl_wdata.icache_enable;
|
||||||
|
|
||||||
|
// icen field will always read as zero if ICache not configured
|
||||||
|
assign cpuctrl_rdata.icache_enable = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// tieoff for the currently unused bits of cpuctrl
|
||||||
|
logic [31:1] unused_cpuctrl;
|
||||||
|
assign unused_cpuctrl = {cpuctrl_wdata[31:1]};
|
||||||
|
|
||||||
|
assign icache_enable_o = cpuctrl_rdata.icache_enable;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// Assertions //
|
// Assertions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
|
@ -34,6 +34,7 @@ module ibex_decoder #(
|
||||||
output logic ecall_insn_o, // syscall instr encountered
|
output logic ecall_insn_o, // syscall instr encountered
|
||||||
output logic wfi_insn_o, // wait for interrupt instr encountered
|
output logic wfi_insn_o, // wait for interrupt instr encountered
|
||||||
output logic jump_set_o, // jump taken set signal
|
output logic jump_set_o, // jump taken set signal
|
||||||
|
output logic icache_inval_o,
|
||||||
|
|
||||||
// from IF-ID pipeline register
|
// from IF-ID pipeline register
|
||||||
input logic instr_first_cycle_i, // instruction read is in its first cycle
|
input logic instr_first_cycle_i, // instruction read is in its first cycle
|
||||||
|
@ -171,6 +172,7 @@ module ibex_decoder #(
|
||||||
jump_in_dec_o = 1'b0;
|
jump_in_dec_o = 1'b0;
|
||||||
jump_set_o = 1'b0;
|
jump_set_o = 1'b0;
|
||||||
branch_in_dec_o = 1'b0;
|
branch_in_dec_o = 1'b0;
|
||||||
|
icache_inval_o = 1'b0;
|
||||||
|
|
||||||
mult_en_o = 1'b0;
|
mult_en_o = 1'b0;
|
||||||
div_en_o = 1'b0;
|
div_en_o = 1'b0;
|
||||||
|
@ -431,7 +433,7 @@ module ibex_decoder #(
|
||||||
OPCODE_MISC_MEM: begin
|
OPCODE_MISC_MEM: begin
|
||||||
// For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
|
// For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
|
||||||
// in a system with caches and should be revisited.
|
// in a system with caches and should be revisited.
|
||||||
// FENCE.I will flush the IF stage and prefetch buffer but nothing else.
|
// FENCE.I will flush the IF stage and prefetch buffer (or ICache) but nothing else.
|
||||||
unique case (instr[14:12])
|
unique case (instr[14:12])
|
||||||
3'b000: begin
|
3'b000: begin
|
||||||
rf_we = 1'b0;
|
rf_we = 1'b0;
|
||||||
|
@ -440,12 +442,14 @@ module ibex_decoder #(
|
||||||
// FENCE.I is implemented as a jump to the next PC, this gives the required flushing
|
// FENCE.I is implemented as a jump to the next PC, this gives the required flushing
|
||||||
// behaviour (iside prefetch buffer flushed and response to any outstanding iside
|
// behaviour (iside prefetch buffer flushed and response to any outstanding iside
|
||||||
// requests will be ignored).
|
// requests will be ignored).
|
||||||
|
// If present, the ICache will also be flushed.
|
||||||
jump_in_dec_o = 1'b1;
|
jump_in_dec_o = 1'b1;
|
||||||
|
|
||||||
rf_we = 1'b0;
|
rf_we = 1'b0;
|
||||||
|
|
||||||
if (instr_first_cycle_i) begin
|
if (instr_first_cycle_i) begin
|
||||||
jump_set_o = 1'b1;
|
jump_set_o = 1'b1;
|
||||||
|
icache_inval_o = 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
|
|
|
@ -14,7 +14,7 @@ module ibex_icache #(
|
||||||
// Cache arrangement parameters
|
// Cache arrangement parameters
|
||||||
parameter int unsigned BusWidth = 32,
|
parameter int unsigned BusWidth = 32,
|
||||||
parameter int unsigned CacheSizeBytes = 4*1024,
|
parameter int unsigned CacheSizeBytes = 4*1024,
|
||||||
parameter bit CacheECC = 1'b0,
|
parameter bit ICacheECC = 1'b0,
|
||||||
parameter int unsigned LineSize = 64,
|
parameter int unsigned LineSize = 64,
|
||||||
parameter int unsigned NumWays = 2,
|
parameter int unsigned NumWays = 2,
|
||||||
// Always make speculative bus requests in parallel with lookups
|
// Always make speculative bus requests in parallel with lookups
|
||||||
|
@ -65,7 +65,7 @@ module ibex_icache #(
|
||||||
// Request throttling threshold
|
// Request throttling threshold
|
||||||
localparam int unsigned FB_THRESHOLD = NUM_FB - 2;
|
localparam int unsigned FB_THRESHOLD = NUM_FB - 2;
|
||||||
// Derived parameters
|
// Derived parameters
|
||||||
localparam int unsigned LINE_SIZE_ECC = CacheECC ? (LineSize + 8) : LineSize;
|
localparam int unsigned LINE_SIZE_ECC = ICacheECC ? (LineSize + 8) : LineSize;
|
||||||
localparam int unsigned LINE_SIZE_BYTES = LineSize/8;
|
localparam int unsigned LINE_SIZE_BYTES = LineSize/8;
|
||||||
localparam int unsigned LINE_W = $clog2(LINE_SIZE_BYTES);
|
localparam int unsigned LINE_W = $clog2(LINE_SIZE_BYTES);
|
||||||
localparam int unsigned BUS_BYTES = BusWidth/8;
|
localparam int unsigned BUS_BYTES = BusWidth/8;
|
||||||
|
@ -76,7 +76,7 @@ module ibex_icache #(
|
||||||
localparam int unsigned INDEX_W = $clog2(NUM_LINES);
|
localparam int unsigned INDEX_W = $clog2(NUM_LINES);
|
||||||
localparam int unsigned INDEX_HI = INDEX_W + LINE_W - 1;
|
localparam int unsigned INDEX_HI = INDEX_W + LINE_W - 1;
|
||||||
localparam int unsigned TAG_SIZE = ADDR_W - INDEX_W - LINE_W + 1; // 1 valid bit
|
localparam int unsigned TAG_SIZE = ADDR_W - INDEX_W - LINE_W + 1; // 1 valid bit
|
||||||
localparam int unsigned TAG_SIZE_ECC = CacheECC ? (TAG_SIZE + 6) : TAG_SIZE;
|
localparam int unsigned TAG_SIZE_ECC = ICacheECC ? (TAG_SIZE + 6) : TAG_SIZE;
|
||||||
localparam int unsigned OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords
|
localparam int unsigned OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords
|
||||||
|
|
||||||
// Prefetch signals
|
// Prefetch signals
|
||||||
|
@ -257,7 +257,7 @@ module ibex_icache #(
|
||||||
assign data_write_ic0 = tag_write_ic0;
|
assign data_write_ic0 = tag_write_ic0;
|
||||||
|
|
||||||
// Append ECC checkbits to write data if required
|
// Append ECC checkbits to write data if required
|
||||||
if (CacheECC) begin : gen_ecc_wdata
|
if (ICacheECC) begin : gen_ecc_wdata
|
||||||
|
|
||||||
// Tagram ECC
|
// Tagram ECC
|
||||||
// Reuse the same ecc encoding module for larger cache sizes by padding with zeros
|
// Reuse the same ecc encoding module for larger cache sizes by padding with zeros
|
||||||
|
@ -383,7 +383,7 @@ module ibex_icache #(
|
||||||
round_robin_way_q;
|
round_robin_way_q;
|
||||||
|
|
||||||
// ECC checking logic
|
// ECC checking logic
|
||||||
if (CacheECC) begin : gen_data_ecc_checking
|
if (ICacheECC) begin : gen_data_ecc_checking
|
||||||
logic [NumWays-1:0] tag_err_ic1;
|
logic [NumWays-1:0] tag_err_ic1;
|
||||||
logic [1:0] data_err_ic1;
|
logic [1:0] data_err_ic1;
|
||||||
logic ecc_correction_write_d, ecc_correction_write_q;
|
logic ecc_correction_write_d, ecc_correction_write_q;
|
||||||
|
|
|
@ -39,6 +39,7 @@ module ibex_id_stage #(
|
||||||
output logic instr_first_cycle_id_o,
|
output logic instr_first_cycle_id_o,
|
||||||
output logic instr_valid_clear_o, // kill instr in IF-ID reg
|
output logic instr_valid_clear_o, // kill instr in IF-ID reg
|
||||||
output logic id_in_ready_o, // ID stage is ready for next instr
|
output logic id_in_ready_o, // ID stage is ready for next instr
|
||||||
|
output logic icache_inval_o,
|
||||||
|
|
||||||
// Jumps and branches
|
// Jumps and branches
|
||||||
input logic branch_decision_i,
|
input logic branch_decision_i,
|
||||||
|
@ -331,6 +332,7 @@ module ibex_id_stage #(
|
||||||
.ecall_insn_o ( ecall_insn_dec ),
|
.ecall_insn_o ( ecall_insn_dec ),
|
||||||
.wfi_insn_o ( wfi_insn_dec ),
|
.wfi_insn_o ( wfi_insn_dec ),
|
||||||
.jump_set_o ( jump_set ),
|
.jump_set_o ( jump_set ),
|
||||||
|
.icache_inval_o ( icache_inval_o ),
|
||||||
|
|
||||||
// from IF-ID pipeline register
|
// from IF-ID pipeline register
|
||||||
.instr_first_cycle_i ( instr_first_cycle ),
|
.instr_first_cycle_i ( instr_first_cycle ),
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
`include "prim_assert.sv"
|
`include "prim_assert.sv"
|
||||||
|
|
||||||
module ibex_if_stage #(
|
module ibex_if_stage #(
|
||||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
||||||
|
parameter bit ICache = 1'b0,
|
||||||
|
parameter bit ICacheECC = 1'b0
|
||||||
) (
|
) (
|
||||||
input logic clk_i,
|
input logic clk_i,
|
||||||
input logic rst_ni,
|
input logic rst_ni,
|
||||||
|
@ -56,6 +58,9 @@ module ibex_if_stage #(
|
||||||
input ibex_pkg::exc_pc_sel_e exc_pc_mux_i, // selects ISR address
|
input ibex_pkg::exc_pc_sel_e exc_pc_mux_i, // selects ISR address
|
||||||
input ibex_pkg::exc_cause_e exc_cause, // selects ISR address for
|
input ibex_pkg::exc_cause_e exc_cause, // selects ISR address for
|
||||||
// vectorized interrupt lines
|
// vectorized interrupt lines
|
||||||
|
input logic icache_enable_i,
|
||||||
|
input logic icache_inval_i,
|
||||||
|
|
||||||
// jump and branch target
|
// jump and branch target
|
||||||
input logic [31:0] jump_target_ex_i, // jump target address
|
input logic [31:0] jump_target_ex_i, // jump target address
|
||||||
|
|
||||||
|
@ -134,35 +139,71 @@ module ibex_if_stage #(
|
||||||
// tell CS register file to initialize mtvec on boot
|
// tell CS register file to initialize mtvec on boot
|
||||||
assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
|
assign csr_mtvec_init_o = (pc_mux_i == PC_BOOT) & pc_set_i;
|
||||||
|
|
||||||
// prefetch buffer, caches a fixed number of instructions
|
if (ICache) begin : gen_icache
|
||||||
ibex_prefetch_buffer prefetch_buffer_i (
|
// Full I-Cache option
|
||||||
.clk_i ( clk_i ),
|
ibex_icache #(
|
||||||
.rst_ni ( rst_ni ),
|
.ICacheECC (ICacheECC)
|
||||||
|
) icache_i (
|
||||||
|
.clk_i ( clk_i ),
|
||||||
|
.rst_ni ( rst_ni ),
|
||||||
|
|
||||||
.req_i ( req_i ),
|
.req_i ( req_i ),
|
||||||
|
|
||||||
.branch_i ( branch_req ),
|
.branch_i ( branch_req ),
|
||||||
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
|
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
|
||||||
|
|
||||||
.ready_i ( fetch_ready ),
|
.ready_i ( fetch_ready ),
|
||||||
.valid_o ( fetch_valid ),
|
.valid_o ( fetch_valid ),
|
||||||
.rdata_o ( fetch_rdata ),
|
.rdata_o ( fetch_rdata ),
|
||||||
.addr_o ( fetch_addr ),
|
.addr_o ( fetch_addr ),
|
||||||
.err_o ( fetch_err ),
|
.err_o ( fetch_err ),
|
||||||
.err_plus2_o ( fetch_err_plus2 ),
|
.err_plus2_o ( fetch_err_plus2 ),
|
||||||
|
|
||||||
// goes to instruction memory / instruction cache
|
.instr_req_o ( instr_req_o ),
|
||||||
.instr_req_o ( instr_req_o ),
|
.instr_addr_o ( instr_addr_o ),
|
||||||
.instr_addr_o ( instr_addr_o ),
|
.instr_gnt_i ( instr_gnt_i ),
|
||||||
.instr_gnt_i ( instr_gnt_i ),
|
.instr_rvalid_i ( instr_rvalid_i ),
|
||||||
.instr_rvalid_i ( instr_rvalid_i ),
|
.instr_rdata_i ( instr_rdata_i ),
|
||||||
.instr_rdata_i ( instr_rdata_i ),
|
.instr_err_i ( instr_err_i ),
|
||||||
.instr_err_i ( instr_err_i ),
|
.instr_pmp_err_i ( instr_pmp_err_i ),
|
||||||
.instr_pmp_err_i ( instr_pmp_err_i ),
|
|
||||||
|
|
||||||
// Prefetch Buffer Status
|
.icache_enable_i ( icache_enable_i ),
|
||||||
.busy_o ( prefetch_busy )
|
.icache_inval_i ( icache_inval_i ),
|
||||||
);
|
.busy_o ( prefetch_busy )
|
||||||
|
);
|
||||||
|
end else begin : gen_prefetch_buffer
|
||||||
|
// prefetch buffer, caches a fixed number of instructions
|
||||||
|
ibex_prefetch_buffer prefetch_buffer_i (
|
||||||
|
.clk_i ( clk_i ),
|
||||||
|
.rst_ni ( rst_ni ),
|
||||||
|
|
||||||
|
.req_i ( req_i ),
|
||||||
|
|
||||||
|
.branch_i ( branch_req ),
|
||||||
|
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
|
||||||
|
|
||||||
|
.ready_i ( fetch_ready ),
|
||||||
|
.valid_o ( fetch_valid ),
|
||||||
|
.rdata_o ( fetch_rdata ),
|
||||||
|
.addr_o ( fetch_addr ),
|
||||||
|
.err_o ( fetch_err ),
|
||||||
|
.err_plus2_o ( fetch_err_plus2 ),
|
||||||
|
|
||||||
|
.instr_req_o ( instr_req_o ),
|
||||||
|
.instr_addr_o ( instr_addr_o ),
|
||||||
|
.instr_gnt_i ( instr_gnt_i ),
|
||||||
|
.instr_rvalid_i ( instr_rvalid_i ),
|
||||||
|
.instr_rdata_i ( instr_rdata_i ),
|
||||||
|
.instr_err_i ( instr_err_i ),
|
||||||
|
.instr_pmp_err_i ( instr_pmp_err_i ),
|
||||||
|
|
||||||
|
.busy_o ( prefetch_busy )
|
||||||
|
);
|
||||||
|
// ICache tieoffs
|
||||||
|
logic unused_icen, unused_icinv;
|
||||||
|
assign unused_icen = icache_enable_i;
|
||||||
|
assign unused_icinv = icache_inval_i;
|
||||||
|
end
|
||||||
|
|
||||||
assign branch_req = pc_set_i;
|
assign branch_req = pc_set_i;
|
||||||
assign fetch_ready = id_in_ready_i;
|
assign fetch_ready = id_in_ready_i;
|
||||||
|
|
|
@ -389,7 +389,8 @@ typedef enum logic[11:0] {
|
||||||
CSR_MHPMCOUNTER28H = 12'hB9C,
|
CSR_MHPMCOUNTER28H = 12'hB9C,
|
||||||
CSR_MHPMCOUNTER29H = 12'hB9D,
|
CSR_MHPMCOUNTER29H = 12'hB9D,
|
||||||
CSR_MHPMCOUNTER30H = 12'hB9E,
|
CSR_MHPMCOUNTER30H = 12'hB9E,
|
||||||
CSR_MHPMCOUNTER31H = 12'hB9F
|
CSR_MHPMCOUNTER31H = 12'hB9F,
|
||||||
|
CSR_CPUCTRL = 12'h7C0
|
||||||
} csr_num_e;
|
} csr_num_e;
|
||||||
|
|
||||||
// CSR pmp-related offsets
|
// CSR pmp-related offsets
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue