mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-19 11:44:58 -04:00
remove branch predictor (#49)
* remove parameter BranchPredictor Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove references to the removed parameter(s) from examples Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * remove references to the removed parameters from compliance verification Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * remove references to the removed parameters from core lists Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * remove references to the removed parameters from the example configurations Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove references to the removed parameter from documentation Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> * Remove related and dead code Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com> --------- 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:
parent
7836daeb14
commit
066ff47261
18 changed files with 24 additions and 364 deletions
|
@ -38,7 +38,6 @@ ${DESIGN_RTL_DIR}/cve2_tracer_pkg.sv
|
|||
${DESIGN_RTL_DIR}/../vendor/lowrisc_ip/ip/prim/rtl/prim_secded_pkg.sv
|
||||
${DESIGN_RTL_DIR}/../vendor/lowrisc_ip/ip/prim/rtl/prim_ram_1p_pkg.sv
|
||||
${DESIGN_RTL_DIR}/cve2_alu.sv
|
||||
${DESIGN_RTL_DIR}/cve2_branch_predict.sv
|
||||
${DESIGN_RTL_DIR}/cve2_compressed_decoder.sv
|
||||
${DESIGN_RTL_DIR}/cve2_controller.sv
|
||||
${DESIGN_RTL_DIR}/cve2_cs_registers.sv
|
||||
|
|
|
@ -13,7 +13,6 @@ small:
|
|||
RV32B : "cve2_pkg::RV32BNone"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 0
|
||||
BranchPredictor : 0
|
||||
PMPEnable : 0
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 4
|
||||
|
@ -25,7 +24,6 @@ opentitan:
|
|||
RV32B : "cve2_pkg::RV32BOTEarlGrey"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 1
|
||||
BranchPredictor : 0
|
||||
PMPEnable : 1
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 16
|
||||
|
@ -43,7 +41,6 @@ experimental-maxperf:
|
|||
RV32B : "cve2_pkg::RV32BNone"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 1
|
||||
BranchPredictor : 0
|
||||
PMPEnable : 0
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 4
|
||||
|
@ -55,7 +52,6 @@ experimental-maxperf-pmp:
|
|||
RV32B : "cve2_pkg::RV32BNone"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 1
|
||||
BranchPredictor : 0
|
||||
PMPEnable : 1
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 16
|
||||
|
@ -67,7 +63,6 @@ experimental-maxperf-pmp-bmbalanced:
|
|||
RV32B : "cve2_pkg::RV32BBalanced"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 1
|
||||
BranchPredictor : 0
|
||||
PMPEnable : 1
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 16
|
||||
|
@ -79,7 +74,6 @@ experimental-maxperf-pmp-bmfull:
|
|||
RV32B : "cve2_pkg::RV32BFull"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 1
|
||||
BranchPredictor : 0
|
||||
PMPEnable : 1
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 16
|
||||
|
@ -94,7 +88,6 @@ experimental-branch-predictor:
|
|||
RV32B : "cve2_pkg::RV32BNone"
|
||||
RegFile : "cve2_pkg::RegFileFF"
|
||||
WritebackStage : 1
|
||||
BranchPredictor : 1
|
||||
PMPEnable : 0
|
||||
PMPGranularity : 0
|
||||
PMPNumRegions : 4
|
||||
|
|
|
@ -68,7 +68,6 @@ parameters:
|
|||
paramtype: vlogdefine
|
||||
description: "Bitmanip implementation parameter enum. See the cve2_pkg::rv32b_e enum in cve2_pkg.sv for permitted values."
|
||||
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
filesets:
|
||||
|
|
|
@ -65,12 +65,6 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Enables third pipeline stage (EXPERIMENTAL) [0/1]"
|
||||
|
||||
BranchPredictor:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 0
|
||||
description: "Enables static branch prediction (EXPERIMENTAL)"
|
||||
|
||||
SecureCVE2:
|
||||
datatype: int
|
||||
default: 0
|
||||
|
@ -121,7 +115,6 @@ targets:
|
|||
- ICache
|
||||
- ICacheECC
|
||||
- WritebackStage
|
||||
- BranchPredictor
|
||||
- SecureCVE2
|
||||
- ICacheScramble
|
||||
- PMPEnable
|
||||
|
|
|
@ -18,7 +18,6 @@ Instantiation Template
|
|||
.MHPMCounterWidth ( 40 ),
|
||||
.RV32E ( 0 ),
|
||||
.RV32M ( cve2_pkg::RV32MFast ),
|
||||
.BranchPrediction ( 0 ),
|
||||
.RndCnstLfsrSeed ( cve2_pkg::RndCnstLfsrSeedDefault ),
|
||||
.RndCnstLfsrPerm ( cve2_pkg::RndCnstLfsrPermDefault ),
|
||||
.DmHaltAddr ( 32'h1A110800 ),
|
||||
|
@ -94,8 +93,6 @@ Parameters
|
|||
| | | | "cve2_pkg::RV32MFast": 3-4 cycle multiplier, iterative divider |
|
||||
| | | | "cve2_pkg::RV32MSingleCycle": 1-2 cycle multiplier, iterative divider |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``BranchPrediction`` | bit | 0 | *EXPERIMENTAL* Enable Static branch prediction |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |
|
||||
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
|
||||
| ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode |
|
||||
|
|
|
@ -6,9 +6,6 @@ Coverage Plan
|
|||
.. note::
|
||||
Work to implement the functional coverage described in this plan is on-going and the plan itself is not yet complete.
|
||||
|
||||
.. todo::
|
||||
Branch prediction hasn't yet been considered, this will add more coverage points and alter some others
|
||||
|
||||
Introduction
|
||||
------------
|
||||
Ibex functional coverage is split into two major categories:
|
||||
|
|
|
@ -21,16 +21,6 @@ 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.
|
||||
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).
|
||||
|
||||
Branch Prediction
|
||||
-----------------
|
||||
|
||||
Ibex can be configured to use static branch prediction by setting the ``BranchPrediction`` parameter to 1.
|
||||
This improves performance by predicting that any branch with a negative offset is taken and that any branch with a positive offset is not.
|
||||
When successful, the prediction removes a stall cycle from a taken branch.
|
||||
However, there is a mis-predict penalty if a branch is wrongly predicted to be taken.
|
||||
This penalty is at least one cycle, or at least two cycles if the instruction following the branch is uncompressed and not aligned.
|
||||
This feature is *EXPERIMENTAL* and its effects are not yet fully documented.
|
||||
|
||||
Instruction-Side Memory Interface
|
||||
---------------------------------
|
||||
|
||||
|
|
|
@ -59,12 +59,6 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Enable ECC protection in instruction cache"
|
||||
|
||||
BranchPredictor:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 0
|
||||
description: "Enables static branch prediction (EXPERIMENTAL)"
|
||||
|
||||
PMPEnable:
|
||||
datatype: int
|
||||
default: 0
|
||||
|
@ -108,7 +102,6 @@ targets:
|
|||
- RegFile
|
||||
- ICache
|
||||
- ICacheECC
|
||||
- BranchPredictor
|
||||
- PMPEnable
|
||||
- PMPGranularity
|
||||
- PMPNumRegions
|
||||
|
|
|
@ -24,7 +24,6 @@ module cve2_riscv_compliance (
|
|||
parameter cve2_pkg::regfile_e RegFile = cve2_pkg::RegFileFF;
|
||||
parameter bit ICache = 1'b0;
|
||||
parameter bit ICacheECC = 1'b0;
|
||||
parameter bit BranchPredictor = 1'b0;
|
||||
parameter bit SecureIbex = 1'b0;
|
||||
parameter bit ICacheScramble = 1'b0;
|
||||
|
||||
|
@ -121,7 +120,6 @@ module cve2_riscv_compliance (
|
|||
.RegFile (RegFile ),
|
||||
.ICache (ICache ),
|
||||
.ICacheECC (ICacheECC ),
|
||||
.BranchPredictor (BranchPredictor ),
|
||||
.SecureIbex (SecureIbex ),
|
||||
.ICacheScramble (ICacheScramble ),
|
||||
.DmHaltAddr (32'h00000000 ),
|
||||
|
|
|
@ -66,12 +66,6 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Enables ICache scrambling feature (EXPERIMENTAL) [0/1]"
|
||||
|
||||
BranchPredictor:
|
||||
datatype: int
|
||||
paramtype: vlogparam
|
||||
default: 0
|
||||
description: "Enables static branch prediction (EXPERIMENTAL)"
|
||||
|
||||
PMPEnable:
|
||||
datatype: int
|
||||
default: 0
|
||||
|
@ -104,7 +98,6 @@ targets:
|
|||
- ICacheScramble
|
||||
- ICacheECC
|
||||
- SecureIbex
|
||||
- BranchPredictor
|
||||
- PMPEnable
|
||||
- PMPGranularity
|
||||
- PMPNumRegions
|
||||
|
|
|
@ -46,7 +46,6 @@ module cve2_simple_system (
|
|||
parameter cve2_pkg::regfile_e RegFile = `RegFile;
|
||||
parameter bit ICache = 1'b0;
|
||||
parameter bit ICacheECC = 1'b0;
|
||||
parameter bit BranchPredictor = 1'b0;
|
||||
parameter SRAMInitFile = "";
|
||||
|
||||
logic clk_sys = 1'b0, rst_sys_n;
|
||||
|
@ -173,7 +172,6 @@ module cve2_simple_system (
|
|||
.RegFile ( RegFile ),
|
||||
.ICache ( ICache ),
|
||||
.ICacheECC ( ICacheECC ),
|
||||
.BranchPredictor ( BranchPredictor ),
|
||||
.DmHaltAddr ( 32'h00100000 ),
|
||||
.DmExceptionAddr ( 32'h00100000 )
|
||||
) u_top (
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
`include "dv_fcov_macros.svh"
|
||||
|
||||
module cve2_controller #(
|
||||
parameter bit BranchPredictor = 0
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -33,7 +32,6 @@ module cve2_controller #(
|
|||
input logic [31:0] instr_i, // uncompressed instr data for mtval
|
||||
input logic [15:0] instr_compressed_i, // instr compressed data for mtval
|
||||
input logic instr_is_compressed_i, // instr is compressed
|
||||
input logic instr_bp_taken_i, // instr was predicted taken branch
|
||||
input logic instr_fetch_err_i, // instr has error
|
||||
input logic instr_fetch_err_plus2_i, // instr error is x32
|
||||
input logic [31:0] pc_id_i, // instr address
|
||||
|
@ -49,8 +47,6 @@ module cve2_controller #(
|
|||
output logic pc_set_o, // jump to address set by pc_mux
|
||||
output cve2_pkg::pc_sel_e pc_mux_o, // IF stage fetch address selector
|
||||
// (boot, normal, exception...)
|
||||
output logic nt_branch_mispredict_o, // Not-taken branch in ID/EX was
|
||||
// mispredicted (predicted taken)
|
||||
output cve2_pkg::exc_pc_sel_e exc_pc_mux_o, // IF stage selector for exception PC
|
||||
output cve2_pkg::exc_cause_e exc_cause_o, // for IF stage, CSRs
|
||||
|
||||
|
@ -62,7 +58,6 @@ module cve2_controller #(
|
|||
// jump/branch signals
|
||||
input logic branch_set_i, // branch set signal (branch definitely
|
||||
// taken)
|
||||
input logic branch_not_set_i, // branch is definitely not taken
|
||||
input logic jump_set_i, // jump taken set signal
|
||||
|
||||
// interrupt signals
|
||||
|
@ -338,7 +333,6 @@ module cve2_controller #(
|
|||
// helping timing.
|
||||
pc_mux_o = PC_BOOT;
|
||||
pc_set_o = 1'b0;
|
||||
nt_branch_mispredict_o = 1'b0;
|
||||
|
||||
exc_pc_mux_o = EXC_PC_IRQ;
|
||||
exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00
|
||||
|
@ -458,21 +452,12 @@ module cve2_controller #(
|
|||
end
|
||||
|
||||
if (branch_set_i || jump_set_i) begin
|
||||
// Only set the PC if the branch predictor hasn't already done the branch for us
|
||||
pc_set_o = BranchPredictor ? ~instr_bp_taken_i : 1'b1;
|
||||
pc_set_o = 1'b1;
|
||||
|
||||
perf_tbranch_o = branch_set_i;
|
||||
perf_jump_o = jump_set_i;
|
||||
end
|
||||
|
||||
if (BranchPredictor) begin
|
||||
if (instr_bp_taken_i & branch_not_set_i) begin
|
||||
// If the instruction is a branch that was predicted to be taken but was not taken
|
||||
// signal a mispredict.
|
||||
nt_branch_mispredict_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// If entering debug mode or handling an IRQ the core needs to wait until any instruction in
|
||||
// ID has finished executing. Stall IF during that time.
|
||||
if ((enter_debug_mode || handle_irq) && (stall || instr_valid_i)) begin
|
||||
|
@ -776,8 +761,6 @@ module cve2_controller #(
|
|||
// Assertions //
|
||||
////////////////
|
||||
|
||||
`ASSERT(AlwaysInstrClearOnMispredict, nt_branch_mispredict_o |-> instr_valid_clear_o)
|
||||
|
||||
// Selectors must be known/valid.
|
||||
`ASSERT(IbexCtrlStateValid, ctrl_fsm_cs inside {
|
||||
RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
|
||||
|
|
|
@ -21,7 +21,6 @@ module cve2_core import cve2_pkg::*; #(
|
|||
parameter bit RV32E = 1'b0,
|
||||
parameter rv32m_e RV32M = RV32MFast,
|
||||
parameter rv32b_e RV32B = RV32BNone,
|
||||
parameter bit BranchPredictor = 1'b0,
|
||||
parameter bit DbgTriggerEn = 1'b0,
|
||||
parameter int unsigned DbgHwBreakNum = 1,
|
||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||
|
@ -119,7 +118,6 @@ module cve2_core import cve2_pkg::*; #(
|
|||
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
|
||||
logic instr_is_compressed_id;
|
||||
logic instr_perf_count_id;
|
||||
logic instr_bp_taken_id;
|
||||
logic instr_fetch_err; // Bus error on instr fetch
|
||||
logic instr_fetch_err_plus2; // Instruction error is misaligned
|
||||
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
|
||||
|
@ -132,8 +130,6 @@ module cve2_core import cve2_pkg::*; #(
|
|||
logic instr_first_cycle_id;
|
||||
logic instr_valid_clear;
|
||||
logic pc_set;
|
||||
logic nt_branch_mispredict;
|
||||
logic [31:0] nt_branch_addr;
|
||||
pc_sel_e pc_mux_id; // Mux selector for next PC
|
||||
exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC
|
||||
exc_cause_e exc_cause; // Exception cause
|
||||
|
@ -290,8 +286,7 @@ module cve2_core import cve2_pkg::*; #(
|
|||
|
||||
cve2_if_stage #(
|
||||
.DmHaltAddr (DmHaltAddr),
|
||||
.DmExceptionAddr (DmExceptionAddr),
|
||||
.BranchPredictor (BranchPredictor)
|
||||
.DmExceptionAddr (DmExceptionAddr)
|
||||
) if_stage_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni(rst_ni),
|
||||
|
@ -314,7 +309,6 @@ module cve2_core import cve2_pkg::*; #(
|
|||
.instr_rdata_alu_id_o (instr_rdata_alu_id),
|
||||
.instr_rdata_c_id_o (instr_rdata_c_id),
|
||||
.instr_is_compressed_id_o(instr_is_compressed_id),
|
||||
.instr_bp_taken_o (instr_bp_taken_id),
|
||||
.instr_fetch_err_o (instr_fetch_err),
|
||||
.instr_fetch_err_plus2_o (instr_fetch_err_plus2),
|
||||
.illegal_c_insn_id_o (illegal_c_insn_id),
|
||||
|
@ -327,13 +321,11 @@ module cve2_core import cve2_pkg::*; #(
|
|||
.instr_valid_clear_i (instr_valid_clear),
|
||||
.pc_set_i (pc_set),
|
||||
.pc_mux_i (pc_mux_id),
|
||||
.nt_branch_mispredict_i(nt_branch_mispredict),
|
||||
.exc_pc_mux_i (exc_pc_mux_id),
|
||||
.exc_cause (exc_cause),
|
||||
|
||||
// branch targets
|
||||
.branch_target_ex_i(branch_target_ex),
|
||||
.nt_branch_addr_i (nt_branch_addr),
|
||||
|
||||
// CSRs
|
||||
.csr_mepc_i (csr_mepc), // exception return address
|
||||
|
@ -361,8 +353,7 @@ module cve2_core import cve2_pkg::*; #(
|
|||
cve2_id_stage #(
|
||||
.RV32E (RV32E),
|
||||
.RV32M (RV32M),
|
||||
.RV32B (RV32B),
|
||||
.BranchPredictor(BranchPredictor)
|
||||
.RV32B (RV32B)
|
||||
) id_stage_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni(rst_ni),
|
||||
|
@ -378,7 +369,6 @@ module cve2_core import cve2_pkg::*; #(
|
|||
.instr_rdata_alu_i (instr_rdata_alu_id),
|
||||
.instr_rdata_c_i (instr_rdata_c_id),
|
||||
.instr_is_compressed_i(instr_is_compressed_id),
|
||||
.instr_bp_taken_i (instr_bp_taken_id),
|
||||
|
||||
// Jumps and branches
|
||||
.branch_decision_i(branch_decision),
|
||||
|
@ -390,8 +380,6 @@ module cve2_core import cve2_pkg::*; #(
|
|||
.instr_req_o (instr_req_int),
|
||||
.pc_set_o (pc_set),
|
||||
.pc_mux_o (pc_mux_id),
|
||||
.nt_branch_mispredict_o(nt_branch_mispredict),
|
||||
.nt_branch_addr_o (nt_branch_addr),
|
||||
.exc_pc_mux_o (exc_pc_mux_id),
|
||||
.exc_cause_o (exc_cause),
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
module cve2_id_stage #(
|
||||
parameter bit RV32E = 0,
|
||||
parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast,
|
||||
parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone,
|
||||
parameter bit BranchPredictor = 0
|
||||
parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -36,7 +35,6 @@ module cve2_id_stage #(
|
|||
input logic [31:0] instr_rdata_alu_i, // from IF-ID pipeline registers
|
||||
input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers
|
||||
input logic instr_is_compressed_i,
|
||||
input logic instr_bp_taken_i,
|
||||
output logic instr_req_o,
|
||||
output logic instr_first_cycle_id_o,
|
||||
output logic instr_valid_clear_o, // kill instr in IF-ID reg
|
||||
|
@ -48,8 +46,6 @@ module cve2_id_stage #(
|
|||
// IF and ID stage signals
|
||||
output logic pc_set_o,
|
||||
output cve2_pkg::pc_sel_e pc_mux_o,
|
||||
output logic nt_branch_mispredict_o,
|
||||
output logic [31:0] nt_branch_addr_o,
|
||||
output cve2_pkg::exc_pc_sel_e exc_pc_mux_o,
|
||||
output cve2_pkg::exc_cause_e exc_cause_o,
|
||||
|
||||
|
@ -170,7 +166,6 @@ module cve2_id_stage #(
|
|||
logic branch_in_dec;
|
||||
logic branch_set, branch_set_raw, branch_set_raw_d;
|
||||
logic branch_jump_set_done_q, branch_jump_set_done_d;
|
||||
logic branch_not_set;
|
||||
logic jump_in_dec;
|
||||
logic jump_set_dec;
|
||||
logic jump_set, jump_set_raw;
|
||||
|
@ -450,7 +445,6 @@ module cve2_id_stage #(
|
|||
assign illegal_insn_o = instr_valid_i & (illegal_insn_dec | illegal_csr_insn_i);
|
||||
|
||||
cve2_controller #(
|
||||
.BranchPredictor(BranchPredictor)
|
||||
) controller_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni(rst_ni),
|
||||
|
@ -472,7 +466,6 @@ module cve2_id_stage #(
|
|||
.instr_i (instr_rdata_i),
|
||||
.instr_compressed_i (instr_rdata_c_i),
|
||||
.instr_is_compressed_i (instr_is_compressed_i),
|
||||
.instr_bp_taken_i (instr_bp_taken_i),
|
||||
.instr_fetch_err_i (instr_fetch_err_i),
|
||||
.instr_fetch_err_plus2_i(instr_fetch_err_plus2_i),
|
||||
.pc_id_i (pc_id_i),
|
||||
|
@ -486,7 +479,6 @@ module cve2_id_stage #(
|
|||
.instr_req_o (instr_req_o),
|
||||
.pc_set_o (pc_set_o),
|
||||
.pc_mux_o (pc_mux_o),
|
||||
.nt_branch_mispredict_o(nt_branch_mispredict_o),
|
||||
.exc_pc_mux_o (exc_pc_mux_o),
|
||||
.exc_cause_o (exc_cause_o),
|
||||
|
||||
|
@ -496,7 +488,6 @@ module cve2_id_stage #(
|
|||
.store_err_i (lsu_store_err_i),
|
||||
// jump/branch control
|
||||
.branch_set_i (branch_set),
|
||||
.branch_not_set_i (branch_not_set),
|
||||
.jump_set_i (jump_set),
|
||||
|
||||
// interrupt signals
|
||||
|
@ -608,22 +599,6 @@ module cve2_id_stage #(
|
|||
assign jump_set = jump_set_raw & ~branch_jump_set_done_q;
|
||||
assign branch_set = branch_set_raw & ~branch_jump_set_done_q;
|
||||
|
||||
// Holding branch_set/jump_set high for more than one cycle should not cause a functional issue.
|
||||
// However it could generate needless prefetch buffer flushes and instruction fetches. The ID/EX
|
||||
// designs ensures that this never happens for non-predicted branches.
|
||||
`ASSERT(NeverDoubleBranch, branch_set & ~instr_bp_taken_i |=> ~branch_set)
|
||||
`ASSERT(NeverDoubleJump, jump_set & ~instr_bp_taken_i |=> ~jump_set)
|
||||
|
||||
//////////////////////////////
|
||||
// Branch not-taken address //
|
||||
//////////////////////////////
|
||||
|
||||
if (BranchPredictor) begin : g_calc_nt_addr
|
||||
assign nt_branch_addr_o = pc_id_i + (instr_is_compressed_i ? 32'd2 : 32'd4);
|
||||
end else begin : g_n_calc_nt_addr
|
||||
assign nt_branch_addr_o = 32'd0;
|
||||
end
|
||||
|
||||
///////////////
|
||||
// ID-EX FSM //
|
||||
///////////////
|
||||
|
@ -652,7 +627,6 @@ module cve2_id_stage #(
|
|||
stall_branch = 1'b0;
|
||||
stall_alu = 1'b0;
|
||||
branch_set_raw_d = 1'b0;
|
||||
branch_not_set = 1'b0;
|
||||
jump_set_raw = 1'b0;
|
||||
perf_branch_o = 1'b0;
|
||||
|
||||
|
@ -686,10 +660,6 @@ module cve2_id_stage #(
|
|||
stall_branch = branch_decision_i;
|
||||
branch_set_raw_d = branch_decision_i;
|
||||
|
||||
if (BranchPredictor) begin
|
||||
branch_not_set = 1'b1;
|
||||
end
|
||||
|
||||
perf_branch_o = 1'b1;
|
||||
end
|
||||
jump_in_dec: begin
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
|
||||
module cve2_if_stage import cve2_pkg::*; #(
|
||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
||||
parameter bit BranchPredictor = 1'b0
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -42,8 +41,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
// instr_is_compressed_id_o = 1'b1
|
||||
output logic instr_is_compressed_id_o, // compressed decoder thinks this
|
||||
// is a compressed instr
|
||||
output logic instr_bp_taken_o, // instruction was predicted to be
|
||||
// a taken branch
|
||||
output logic instr_fetch_err_o, // bus error on fetch
|
||||
output logic instr_fetch_err_plus2_o, // bus error misaligned
|
||||
output logic illegal_c_insn_id_o, // compressed decoder thinks this
|
||||
|
@ -57,9 +54,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
input logic instr_valid_clear_i, // clear instr valid bit in IF-ID
|
||||
input logic pc_set_i, // set the PC to a new value
|
||||
input pc_sel_e pc_mux_i, // selector for PC multiplexer
|
||||
input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was
|
||||
// mispredicted (predicted taken)
|
||||
input logic [31:0] nt_branch_addr_i, // Not-taken branch address in ID/EX
|
||||
input exc_pc_sel_e exc_pc_mux_i, // selects ISR address
|
||||
input exc_cause_e exc_cause, // selects ISR address for
|
||||
// vectorized interrupt lines
|
||||
|
@ -101,10 +95,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
logic illegal_c_insn;
|
||||
logic instr_is_compressed;
|
||||
|
||||
logic if_instr_valid;
|
||||
logic [31:0] if_instr_rdata;
|
||||
logic [31:0] if_instr_addr;
|
||||
logic if_instr_bus_err;
|
||||
logic if_instr_pmp_err;
|
||||
logic if_instr_err;
|
||||
logic if_instr_err_plus2;
|
||||
|
@ -116,9 +106,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
|
||||
logic if_id_pipe_reg_we; // IF-ID pipeline reg write enable
|
||||
|
||||
logic predict_branch_taken;
|
||||
logic [31:0] predict_branch_pc;
|
||||
|
||||
cve2_pkg::pc_sel_e pc_mux_internal;
|
||||
|
||||
logic [7:0] unused_boot_addr;
|
||||
|
@ -142,10 +129,8 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
endcase
|
||||
end
|
||||
|
||||
// The Branch predictor can provide a new PC which is internal to if_stage. Only override the mux
|
||||
// select to choose this if the core isn't already trying to set a PC.
|
||||
assign pc_mux_internal =
|
||||
(BranchPredictor && predict_branch_taken && !pc_set_i) ? PC_BP : pc_mux_i;
|
||||
pc_mux_i;
|
||||
|
||||
// fetch address selection mux
|
||||
always_comb begin : fetch_addr_mux
|
||||
|
@ -155,9 +140,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
|
||||
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
|
||||
PC_DRET: fetch_addr_n = csr_depc_i;
|
||||
// Without branch predictor will never get pc_mux_internal == PC_BP. We still handle no branch
|
||||
// predictor case here to ensure redundant mux logic isn't synthesised.
|
||||
PC_BP: fetch_addr_n = BranchPredictor ? predict_branch_pc : { boot_addr_i[31:8], 8'h00 };
|
||||
default: fetch_addr_n = { boot_addr_i[31:8], 8'h00 };
|
||||
endcase
|
||||
end
|
||||
|
@ -174,8 +156,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
.req_i ( req_i ),
|
||||
|
||||
.branch_i ( branch_req ),
|
||||
.branch_mispredict_i ( nt_branch_mispredict_i ),
|
||||
.mispredict_addr_i ( nt_branch_addr_i ),
|
||||
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
|
||||
|
||||
.ready_i ( fetch_ready ),
|
||||
|
@ -197,22 +177,22 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
|
||||
assign unused_fetch_addr_n0 = fetch_addr_n[0];
|
||||
|
||||
assign branch_req = pc_set_i | predict_branch_taken;
|
||||
assign branch_req = pc_set_i;
|
||||
|
||||
assign pc_if_o = if_instr_addr;
|
||||
assign pc_if_o = fetch_addr;
|
||||
assign if_busy_o = prefetch_busy;
|
||||
|
||||
// PMP errors
|
||||
// An error can come from the instruction address, or the next instruction address for unaligned,
|
||||
// uncompressed instructions.
|
||||
assign if_instr_pmp_err = pmp_err_if_i |
|
||||
(if_instr_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i);
|
||||
(fetch_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i);
|
||||
|
||||
// Combine bus errors and pmp errors
|
||||
assign if_instr_err = if_instr_bus_err | if_instr_pmp_err;
|
||||
assign if_instr_err = fetch_err | if_instr_pmp_err;
|
||||
|
||||
// Capture the second half of the address for errors on the second part of an instruction
|
||||
assign if_instr_err_plus2 = ((if_instr_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i) |
|
||||
assign if_instr_err_plus2 = ((fetch_addr[2] & ~instr_is_compressed & pmp_err_if_plus2_i) |
|
||||
fetch_err_plus2) & ~pmp_err_if_i;
|
||||
|
||||
// compressed instruction decoding, or more precisely compressed instruction
|
||||
|
@ -224,7 +204,7 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.valid_i (fetch_valid & ~fetch_err),
|
||||
.instr_i (if_instr_rdata),
|
||||
.instr_i (fetch_rdata),
|
||||
.instr_o (instr_decompressed),
|
||||
.is_compressed_o(instr_is_compressed),
|
||||
.illegal_instr_o(illegal_c_insn)
|
||||
|
@ -233,9 +213,9 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
// The ID stage becomes valid as soon as any instruction is registered in the ID stage flops.
|
||||
// Note that the current instruction is squashed by the incoming pc_set_i signal.
|
||||
// Valid is held until it is explicitly cleared (due to an instruction completing or an exception)
|
||||
assign instr_valid_id_d = (if_instr_valid & id_in_ready_i & ~pc_set_i) |
|
||||
assign instr_valid_id_d = (fetch_valid & id_in_ready_i & ~pc_set_i) |
|
||||
(instr_valid_id_q & ~instr_valid_clear_i);
|
||||
assign instr_new_id_d = if_instr_valid & id_in_ready_i;
|
||||
assign instr_new_id_d = fetch_valid & id_in_ready_i;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
|
@ -270,110 +250,14 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
instr_rdata_alu_id_o <= instr_decompressed;
|
||||
instr_fetch_err_o <= if_instr_err;
|
||||
instr_fetch_err_plus2_o <= if_instr_err_plus2;
|
||||
instr_rdata_c_id_o <= if_instr_rdata[15:0];
|
||||
instr_rdata_c_id_o <= fetch_rdata; //if_instr_rdata[15:0];
|
||||
instr_is_compressed_id_o <= instr_is_compressed;
|
||||
illegal_c_insn_id_o <= illegal_c_insn;
|
||||
pc_id_o <= pc_if_o;
|
||||
end
|
||||
end
|
||||
|
||||
if (BranchPredictor) begin : g_branch_predictor
|
||||
logic [31:0] instr_skid_data_q;
|
||||
logic [31:0] instr_skid_addr_q;
|
||||
logic instr_skid_bp_taken_q;
|
||||
logic instr_skid_valid_q, instr_skid_valid_d;
|
||||
logic instr_skid_en;
|
||||
logic instr_bp_taken_q, instr_bp_taken_d;
|
||||
|
||||
logic predict_branch_taken_raw;
|
||||
|
||||
// ID stages needs to know if branch was predicted taken so it can signal mispredicts
|
||||
begin : g_bp_taken
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
instr_bp_taken_q <= '0;
|
||||
end else if (if_id_pipe_reg_we) begin
|
||||
instr_bp_taken_q <= instr_bp_taken_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// When branch prediction is enabled a skid buffer between the IF and ID/EX stage is introduced.
|
||||
// If an instruction in IF is predicted to be a taken branch and ID/EX is not ready the
|
||||
// instruction in IF is moved to the skid buffer which becomes the output of the IF stage until
|
||||
// the ID/EX stage accepts the instruction. The skid buffer is required as otherwise the ID/EX
|
||||
// ready signal is coupled to the instr_req_o output which produces a feedthrough path from
|
||||
// data_gnt_i -> instr_req_o (which needs to be avoided as for some interconnects this will
|
||||
// result in a combinational loop).
|
||||
|
||||
assign instr_skid_en = predict_branch_taken & ~pc_set_i & ~id_in_ready_i & ~instr_skid_valid_q;
|
||||
|
||||
assign instr_skid_valid_d = (instr_skid_valid_q & ~id_in_ready_i) |
|
||||
instr_skid_en;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
instr_skid_valid_q <= 1'b0;
|
||||
end else begin
|
||||
instr_skid_valid_q <= instr_skid_valid_d;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
instr_skid_bp_taken_q <= '0;
|
||||
instr_skid_data_q <= '0;
|
||||
instr_skid_addr_q <= '0;
|
||||
end else if (instr_skid_en) begin
|
||||
instr_skid_bp_taken_q <= predict_branch_taken;
|
||||
instr_skid_data_q <= fetch_rdata;
|
||||
instr_skid_addr_q <= fetch_addr;
|
||||
end
|
||||
end
|
||||
|
||||
cve2_branch_predict branch_predict_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.fetch_rdata_i(fetch_rdata),
|
||||
.fetch_pc_i (fetch_addr),
|
||||
.fetch_valid_i(fetch_valid),
|
||||
|
||||
.predict_branch_taken_o(predict_branch_taken_raw),
|
||||
.predict_branch_pc_o (predict_branch_pc)
|
||||
);
|
||||
|
||||
// If there is an instruction in the skid buffer there must be no branch prediction.
|
||||
// Instructions are only placed in the skid after they have been predicted to be a taken branch
|
||||
// so with the skid valid any prediction has already occurred.
|
||||
// Do not branch predict on instruction errors.
|
||||
assign predict_branch_taken = predict_branch_taken_raw & ~instr_skid_valid_q & ~fetch_err;
|
||||
|
||||
assign if_instr_valid = fetch_valid | (instr_skid_valid_q & ~nt_branch_mispredict_i);
|
||||
assign if_instr_rdata = instr_skid_valid_q ? instr_skid_data_q : fetch_rdata;
|
||||
assign if_instr_addr = instr_skid_valid_q ? instr_skid_addr_q : fetch_addr;
|
||||
|
||||
// Don't branch predict on instruction error so only instructions without errors end up in the
|
||||
// skid buffer.
|
||||
assign if_instr_bus_err = ~instr_skid_valid_q & fetch_err;
|
||||
assign instr_bp_taken_d = instr_skid_valid_q ? instr_skid_bp_taken_q : predict_branch_taken;
|
||||
|
||||
assign fetch_ready = id_in_ready_i & ~instr_skid_valid_q;
|
||||
|
||||
assign instr_bp_taken_o = instr_bp_taken_q;
|
||||
|
||||
`ASSERT(NoPredictSkid, instr_skid_valid_q |-> ~predict_branch_taken)
|
||||
`ASSERT(NoPredictIllegal, predict_branch_taken |-> ~illegal_c_insn)
|
||||
end else begin : g_no_branch_predictor
|
||||
assign instr_bp_taken_o = 1'b0;
|
||||
assign predict_branch_taken = 1'b0;
|
||||
assign predict_branch_pc = 32'b0;
|
||||
|
||||
assign if_instr_valid = fetch_valid;
|
||||
assign if_instr_rdata = fetch_rdata;
|
||||
assign if_instr_addr = fetch_addr;
|
||||
assign if_instr_bus_err = fetch_err;
|
||||
assign fetch_ready = id_in_ready_i;
|
||||
end
|
||||
assign fetch_ready = id_in_ready_i;
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
|
@ -382,109 +266,6 @@ module cve2_if_stage import cve2_pkg::*; #(
|
|||
// Selectors must be known/valid.
|
||||
`ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i)
|
||||
|
||||
if (BranchPredictor) begin : g_branch_predictor_asserts
|
||||
`ASSERT_IF(IbexPcMuxValid, pc_mux_internal inside {
|
||||
PC_BOOT,
|
||||
PC_JUMP,
|
||||
PC_EXC,
|
||||
PC_ERET,
|
||||
PC_DRET,
|
||||
PC_BP},
|
||||
pc_set_i)
|
||||
|
||||
`ifdef INC_ASSERT
|
||||
/**
|
||||
* Checks for branch prediction interface to fetch_fifo/icache
|
||||
*
|
||||
* The interface has two signals:
|
||||
* - predicted_branch_i: When set with a branch (branch_i) indicates the branch is a predicted
|
||||
* one, it should be ignored when a branch_i isn't set.
|
||||
* - branch_mispredict_i: Indicates the previously predicted branch was mis-predicted and
|
||||
* execution should resume with the not-taken side of the branch (i.e. continue with the PC
|
||||
* that followed the predicted branch). This must be raised before the instruction that is
|
||||
* made available following a predicted branch is accepted (Following a cycle with branch_i
|
||||
* & predicted_branch_i, branch_mispredict_i can only be asserted before or on the same cycle
|
||||
* as seeing fetch_valid & fetch_ready). When branch_mispredict_i is asserted, fetch_valid may
|
||||
* be asserted in response. If fetch_valid is asserted on the same cycle as
|
||||
* branch_mispredict_i this indicates the fetch_fifo/icache has the not-taken side of the
|
||||
* branch immediately ready for use
|
||||
*/
|
||||
logic predicted_branch_live_q, predicted_branch_live_d;
|
||||
logic [31:0] predicted_branch_nt_pc_q, predicted_branch_nt_pc_d;
|
||||
logic [31:0] awaiting_instr_after_mispredict_q, awaiting_instr_after_mispredict_d;
|
||||
logic [31:0] next_pc;
|
||||
|
||||
logic mispredicted, mispredicted_d, mispredicted_q;
|
||||
|
||||
assign next_pc = fetch_addr + (instr_is_compressed ? 32'd2 : 32'd4);
|
||||
|
||||
logic predicted_branch;
|
||||
|
||||
// pc_set_i takes precendence over branch prediction
|
||||
assign predicted_branch = predict_branch_taken & ~pc_set_i;
|
||||
|
||||
always_comb begin
|
||||
predicted_branch_live_d = predicted_branch_live_q;
|
||||
mispredicted_d = mispredicted_q;
|
||||
|
||||
if (branch_req & predicted_branch) begin
|
||||
predicted_branch_live_d = 1'b1;
|
||||
mispredicted_d = 1'b0;
|
||||
end else if (predicted_branch_live_q) begin
|
||||
if (fetch_valid & fetch_ready) begin
|
||||
predicted_branch_live_d = 1'b0;
|
||||
end else if (nt_branch_mispredict_i) begin
|
||||
mispredicted_d = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
predicted_branch_live_q <= 1'b0;
|
||||
mispredicted_q <= 1'b0;
|
||||
end else begin
|
||||
predicted_branch_live_q <= predicted_branch_live_d;
|
||||
mispredicted_q <= mispredicted_d;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (branch_req & predicted_branch) begin
|
||||
predicted_branch_nt_pc_q <= next_pc;
|
||||
end
|
||||
end
|
||||
|
||||
// Must only see mispredict after we've performed a predicted branch but before we've accepted
|
||||
// any instruction (with fetch_ready & fetch_valid) that follows that predicted branch.
|
||||
`ASSERT(MispredictOnlyImmediatelyAfterPredictedBranch,
|
||||
nt_branch_mispredict_i |-> predicted_branch_live_q)
|
||||
// Check that on mispredict we get the correct PC for the non-taken side of the branch when
|
||||
// prefetch buffer/icache makes that PC available.
|
||||
`ASSERT(CorrectPCOnMispredict,
|
||||
predicted_branch_live_q & mispredicted_d & fetch_valid |->
|
||||
fetch_addr == predicted_branch_nt_pc_q)
|
||||
// Must not signal mispredict over multiple cycles but it's possible to have back to back
|
||||
// mispredicts for different branches (core signals mispredict, prefetch buffer/icache immediate
|
||||
// has not-taken side of the mispredicted branch ready, which itself is a predicted branch,
|
||||
// following cycle core signal that that branch has mispredicted).
|
||||
`ASSERT(MispredictSingleCycle,
|
||||
nt_branch_mispredict_i & ~(fetch_valid & fetch_ready) |=> ~nt_branch_mispredict_i)
|
||||
// Note that we should never see a mispredict and an incoming branch on the same cycle.
|
||||
// The mispredict also cancels any predicted branch so overall branch_req must be low.
|
||||
`ASSERT(NoMispredBranch, nt_branch_mispredict_i |-> ~branch_req)
|
||||
`endif
|
||||
|
||||
end else begin : g_no_branch_predictor_asserts
|
||||
`ASSERT_IF(IbexPcMuxValid, pc_mux_internal inside {
|
||||
PC_BOOT,
|
||||
PC_JUMP,
|
||||
PC_EXC,
|
||||
PC_ERET,
|
||||
PC_DRET},
|
||||
pc_set_i)
|
||||
end
|
||||
|
||||
// Boot address must be aligned to 256 bytes.
|
||||
`ASSERT(IbexBootAddrUnaligned, boot_addr_i[7:0] == 8'h00)
|
||||
|
||||
|
|
|
@ -17,8 +17,6 @@ module cve2_prefetch_buffer #(
|
|||
input logic req_i,
|
||||
|
||||
input logic branch_i,
|
||||
input logic branch_mispredict_i,
|
||||
input logic [31:0] mispredict_addr_i,
|
||||
input logic [31:0] addr_i,
|
||||
|
||||
|
||||
|
@ -64,16 +62,12 @@ module cve2_prefetch_buffer #(
|
|||
|
||||
logic valid_raw;
|
||||
|
||||
logic branch_or_mispredict;
|
||||
|
||||
////////////////////////////
|
||||
// Prefetch buffer status //
|
||||
////////////////////////////
|
||||
|
||||
assign busy_o = (|rdata_outstanding_q) | instr_req_o;
|
||||
|
||||
assign branch_or_mispredict = branch_i | branch_mispredict_i;
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Fetch fifo - consumes addresses and data //
|
||||
//////////////////////////////////////////////
|
||||
|
@ -81,7 +75,7 @@ module cve2_prefetch_buffer #(
|
|||
// A branch will invalidate any previously fetched instructions.
|
||||
// Note that the FENCE.I instruction relies on this flushing behaviour on branch. If it is
|
||||
// altered the FENCE.I implementation may require changes.
|
||||
assign fifo_clear = branch_or_mispredict;
|
||||
assign fifo_clear = branch_i;
|
||||
|
||||
// Reversed version of rdata_outstanding_q which can be overlaid with fifo fill state
|
||||
for (genvar i = 0; i < NUM_REQS; i++) begin : gen_rd_rev
|
||||
|
@ -120,7 +114,7 @@ module cve2_prefetch_buffer #(
|
|||
//////////////
|
||||
|
||||
// Make a new request any time there is space in the FIFO, and space in the request queue
|
||||
assign valid_new_req = req_i & (fifo_ready | branch_or_mispredict) &
|
||||
assign valid_new_req = req_i & (fifo_ready | branch_i) &
|
||||
~rdata_outstanding_q[NUM_REQS-1];
|
||||
|
||||
assign valid_req = valid_req_q | valid_new_req;
|
||||
|
@ -129,7 +123,7 @@ module cve2_prefetch_buffer #(
|
|||
assign valid_req_d = valid_req & ~instr_gnt_i;
|
||||
|
||||
// Record whether an outstanding bus request is cancelled by a branch
|
||||
assign discard_req_d = valid_req_q & (branch_or_mispredict | discard_req_q);
|
||||
assign discard_req_d = valid_req_q & (branch_i | discard_req_q);
|
||||
|
||||
////////////////
|
||||
// Fetch addr //
|
||||
|
@ -164,10 +158,9 @@ module cve2_prefetch_buffer #(
|
|||
// 2. fetch_addr_q
|
||||
|
||||
// Update on a branch or as soon as a request is issued
|
||||
assign fetch_addr_en = branch_or_mispredict | (valid_new_req & ~valid_req_q);
|
||||
assign fetch_addr_en = branch_i | (valid_new_req & ~valid_req_q);
|
||||
|
||||
assign fetch_addr_d = (branch_i ? addr_i :
|
||||
branch_mispredict_i ? {mispredict_addr_i[31:2], 2'b00} :
|
||||
{fetch_addr_q[31:2], 2'b00}) +
|
||||
// Current address + 4
|
||||
{{29{1'b0}},(valid_new_req & ~valid_req_q),2'b00};
|
||||
|
@ -183,7 +176,6 @@ module cve2_prefetch_buffer #(
|
|||
// Address mux
|
||||
assign instr_addr = valid_req_q ? stored_addr_q :
|
||||
branch_i ? addr_i :
|
||||
branch_mispredict_i ? mispredict_addr_i :
|
||||
fetch_addr_q;
|
||||
|
||||
assign instr_addr_w_aligned = {instr_addr[31:2], 2'b00};
|
||||
|
@ -202,7 +194,7 @@ module cve2_prefetch_buffer #(
|
|||
// If a branch is received at any point while a request is outstanding, it must be tracked
|
||||
// to ensure we discard the data once received
|
||||
assign branch_discard_n[i] = (valid_req & instr_gnt_i & discard_req_d) |
|
||||
(branch_or_mispredict & rdata_outstanding_q[i]) |
|
||||
(branch_i & rdata_outstanding_q[i]) |
|
||||
branch_discard_q[i];
|
||||
|
||||
end else begin : g_reqtop
|
||||
|
@ -214,7 +206,7 @@ module cve2_prefetch_buffer #(
|
|||
rdata_outstanding_q[i];
|
||||
assign branch_discard_n[i] = (valid_req & instr_gnt_i & discard_req_d &
|
||||
rdata_outstanding_q[i-1]) |
|
||||
(branch_or_mispredict & rdata_outstanding_q[i]) |
|
||||
(branch_i & rdata_outstanding_q[i]) |
|
||||
branch_discard_q[i];
|
||||
end
|
||||
end
|
||||
|
@ -228,7 +220,7 @@ module cve2_prefetch_buffer #(
|
|||
// Push a new entry to the FIFO once complete (and not cancelled by a branch)
|
||||
assign fifo_valid = instr_rvalid_i & ~branch_discard_q[0];
|
||||
|
||||
assign fifo_addr = branch_i ? addr_i : mispredict_addr_i;
|
||||
assign fifo_addr = addr_i;
|
||||
|
||||
///////////////
|
||||
// Registers //
|
||||
|
@ -255,6 +247,6 @@ module cve2_prefetch_buffer #(
|
|||
assign instr_req_o = valid_req;
|
||||
assign instr_addr_o = instr_addr_w_aligned;
|
||||
|
||||
assign valid_o = valid_raw & ~branch_mispredict_i;
|
||||
assign valid_o = valid_raw;
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -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 bit BranchPredictor = 1'b0,
|
||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||
) (
|
||||
|
@ -159,7 +158,6 @@ module cve2_top import cve2_pkg::*; #(
|
|||
.RV32E (RV32E),
|
||||
.RV32M (RV32M),
|
||||
.RV32B (RV32B),
|
||||
.BranchPredictor (BranchPredictor),
|
||||
.DbgTriggerEn (DbgTriggerEn),
|
||||
.DbgHwBreakNum (DbgHwBreakNum),
|
||||
.DmHaltAddr (DmHaltAddr),
|
||||
|
|
|
@ -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 bit BranchPredictor = 1'b0,
|
||||
parameter bit DbgTriggerEn = 1'b0,
|
||||
parameter int unsigned DbgHwBreakNum = 1,
|
||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||
|
@ -122,7 +121,6 @@ module cve2_top_tracing import cve2_pkg::*; #(
|
|||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M ),
|
||||
.RV32B ( RV32B ),
|
||||
.BranchPredictor ( BranchPredictor ),
|
||||
.DbgTriggerEn ( DbgTriggerEn ),
|
||||
.DbgHwBreakNum ( DbgHwBreakNum ),
|
||||
.DmHaltAddr ( DmHaltAddr ),
|
||||
|
|
Loading…
Add table
Reference in a new issue