From 066ff472613f6785c8a46d990fd7dee3d1954991 Mon Sep 17 00:00:00 2001 From: christian-herber-nxp <101172126+christian-herber-nxp@users.noreply.github.com> Date: Thu, 20 Jul 2023 16:40:10 +0200 Subject: [PATCH] remove branch predictor (#49) * remove parameter BranchPredictor Signed-off-by: Szymon Bieganski * Remove references to the removed parameter(s) from examples Signed-off-by: Szymon Bieganski * remove references to the removed parameters from compliance verification Signed-off-by: Szymon Bieganski * remove references to the removed parameters from core lists Signed-off-by: Szymon Bieganski * remove references to the removed parameters from the example configurations Signed-off-by: Szymon Bieganski * Remove references to the removed parameter from documentation Signed-off-by: Szymon Bieganski * Remove related and dead code Signed-off-by: Szymon Bieganski --------- Signed-off-by: Szymon Bieganski Co-authored-by: Szymon Bieganski --- cv32e20_manifest.flist | 1 - cve2_configs.yaml | 7 - cve2_top.core | 1 - cve2_top_tracing.core | 7 - doc/02_user/integration.rst | 3 - doc/03_reference/coverage_plan.rst | 3 - doc/03_reference/instruction_fetch.rst | 10 - .../cve2_riscv_compliance.core | 7 - .../rtl/cve2_riscv_compliance.sv | 2 - .../simple_system/cve2_simple_system.core | 7 - .../simple_system/rtl/cve2_simple_system.sv | 2 - rtl/cve2_controller.sv | 19 +- rtl/cve2_core.sv | 16 +- rtl/cve2_id_stage.sv | 32 +-- rtl/cve2_if_stage.sv | 243 +----------------- rtl/cve2_prefetch_buffer.sv | 24 +- rtl/cve2_top.sv | 2 - rtl/cve2_top_tracing.sv | 2 - 18 files changed, 24 insertions(+), 364 deletions(-) diff --git a/cv32e20_manifest.flist b/cv32e20_manifest.flist index 9284d9154..4a0142d80 100644 --- a/cv32e20_manifest.flist +++ b/cv32e20_manifest.flist @@ -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 diff --git a/cve2_configs.yaml b/cve2_configs.yaml index 96de10aa4..1dba358d0 100644 --- a/cve2_configs.yaml +++ b/cve2_configs.yaml @@ -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 diff --git a/cve2_top.core b/cve2_top.core index 05806e45e..cb4e23b4c 100644 --- a/cve2_top.core +++ b/cve2_top.core @@ -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: diff --git a/cve2_top_tracing.core b/cve2_top_tracing.core index da631231d..65d2b5b77 100644 --- a/cve2_top_tracing.core +++ b/cve2_top_tracing.core @@ -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 diff --git a/doc/02_user/integration.rst b/doc/02_user/integration.rst index 0d42fe10b..b4bb9340f 100644 --- a/doc/02_user/integration.rst +++ b/doc/02_user/integration.rst @@ -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 | diff --git a/doc/03_reference/coverage_plan.rst b/doc/03_reference/coverage_plan.rst index 9d8e4b2d3..7b21a74a5 100644 --- a/doc/03_reference/coverage_plan.rst +++ b/doc/03_reference/coverage_plan.rst @@ -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: diff --git a/doc/03_reference/instruction_fetch.rst b/doc/03_reference/instruction_fetch.rst index 36bea79df..0d6106d7c 100644 --- a/doc/03_reference/instruction_fetch.rst +++ b/doc/03_reference/instruction_fetch.rst @@ -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 --------------------------------- diff --git a/dv/riscv_compliance/cve2_riscv_compliance.core b/dv/riscv_compliance/cve2_riscv_compliance.core index 43e599660..bcc129bab 100644 --- a/dv/riscv_compliance/cve2_riscv_compliance.core +++ b/dv/riscv_compliance/cve2_riscv_compliance.core @@ -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 diff --git a/dv/riscv_compliance/rtl/cve2_riscv_compliance.sv b/dv/riscv_compliance/rtl/cve2_riscv_compliance.sv index e256291c6..6ef4272d2 100644 --- a/dv/riscv_compliance/rtl/cve2_riscv_compliance.sv +++ b/dv/riscv_compliance/rtl/cve2_riscv_compliance.sv @@ -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 ), diff --git a/examples/simple_system/cve2_simple_system.core b/examples/simple_system/cve2_simple_system.core index 95832d783..c7cfef70c 100644 --- a/examples/simple_system/cve2_simple_system.core +++ b/examples/simple_system/cve2_simple_system.core @@ -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 diff --git a/examples/simple_system/rtl/cve2_simple_system.sv b/examples/simple_system/rtl/cve2_simple_system.sv index 3f6c35295..9ad289c72 100644 --- a/examples/simple_system/rtl/cve2_simple_system.sv +++ b/examples/simple_system/rtl/cve2_simple_system.sv @@ -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 ( diff --git a/rtl/cve2_controller.sv b/rtl/cve2_controller.sv index fb4a1ae06..69dd95ab1 100644 --- a/rtl/cve2_controller.sv +++ b/rtl/cve2_controller.sv @@ -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, diff --git a/rtl/cve2_core.sv b/rtl/cve2_core.sv index afd4537e2..ea2693c85 100644 --- a/rtl/cve2_core.sv +++ b/rtl/cve2_core.sv @@ -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), diff --git a/rtl/cve2_id_stage.sv b/rtl/cve2_id_stage.sv index 0e4500514..e989ff295 100644 --- a/rtl/cve2_id_stage.sv +++ b/rtl/cve2_id_stage.sv @@ -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 diff --git a/rtl/cve2_if_stage.sv b/rtl/cve2_if_stage.sv index a74f97b49..61df66b75 100644 --- a/rtl/cve2_if_stage.sv +++ b/rtl/cve2_if_stage.sv @@ -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) diff --git a/rtl/cve2_prefetch_buffer.sv b/rtl/cve2_prefetch_buffer.sv index 95dee2e4f..51b1195ce 100644 --- a/rtl/cve2_prefetch_buffer.sv +++ b/rtl/cve2_prefetch_buffer.sv @@ -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 diff --git a/rtl/cve2_top.sv b/rtl/cve2_top.sv index caa56b10e..2783025fb 100644 --- a/rtl/cve2_top.sv +++ b/rtl/cve2_top.sv @@ -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), diff --git a/rtl/cve2_top_tracing.sv b/rtl/cve2_top_tracing.sv index 04d891885..3ca0ec673 100644 --- a/rtl/cve2_top_tracing.sv +++ b/rtl/cve2_top_tracing.sv @@ -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 ),