mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 13:57:19 -04:00
(Likely) fix the following warnings from Xcelium (we cannot actually confirm that without the tool): ``` |fill_ext_req; | xmvlog: *W,DUPBWO (../src/lowrisc_ibex_ibex_icache_0.1/rtl/ibex_icache.sv,830|22): error prone bit-wise OR ('|') sequence detected [4.1.11(IEEE)]. `ASSERT_IF(BranchInsTypeOneHot, $onehot0({instr_j, instr_b, instr_cj, instr_cb}), fetch_valid_i); | xmvlog: *W,UEXPSC (../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_branch_predict.sv,91|98): Ignored unexpected semicolon following SystemVerilog description keyword (end). `ASSERT(NoPredictSkid, instr_skid_valid_q |-> ~predict_branch_taken); | xmvlog: *W,UEXPSC (../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_if_stage.sv,488|72): Ignored unexpected semicolon following SystemVerilog description keyword (end). `ASSERT(NoPredictIllegal, predict_branch_taken |-> ~illegal_c_insn); | xmvlog: *W,UEXPSC (../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_if_stage.sv,489|71): Ignored unexpected semicolon following SystemVerilog description keyword (end). ```
100 lines
3.3 KiB
Systemverilog
100 lines
3.3 KiB
Systemverilog
// Copyright lowRISC contributors.
|
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
/**
|
|
* Branch Predictor
|
|
*
|
|
* This implements static branch prediction. It takes an instruction and its PC and determines if
|
|
* it's a branch or a jump and calculates its target. For jumps it will always predict taken. For
|
|
* branches it will predict taken if the PC offset is negative.
|
|
*
|
|
* This handles both compressed and uncompressed instructions. Compressed instructions must be in
|
|
* the lower 16-bits of instr.
|
|
*
|
|
* The predictor is entirely combinational but takes clk/rst_n signals for use by assertions.
|
|
*/
|
|
|
|
`include "prim_assert.sv"
|
|
|
|
module ibex_branch_predict (
|
|
input logic clk_i,
|
|
input logic rst_ni,
|
|
|
|
// Instruction from fetch stage
|
|
input logic [31:0] fetch_rdata_i,
|
|
input logic [31:0] fetch_pc_i,
|
|
input logic fetch_valid_i,
|
|
|
|
// Prediction for supplied instruction
|
|
output logic predict_branch_taken_o,
|
|
output logic [31:0] predict_branch_pc_o
|
|
);
|
|
import ibex_pkg::*;
|
|
|
|
logic [31:0] imm_j_type;
|
|
logic [31:0] imm_b_type;
|
|
logic [31:0] imm_cj_type;
|
|
logic [31:0] imm_cb_type;
|
|
|
|
logic [31:0] branch_imm;
|
|
|
|
logic [31:0] instr;
|
|
|
|
logic instr_j;
|
|
logic instr_b;
|
|
logic instr_cj;
|
|
logic instr_cb;
|
|
|
|
logic instr_b_taken;
|
|
|
|
// Provide short internal name for fetch_rdata_i due to reduce line wrapping
|
|
assign instr = fetch_rdata_i;
|
|
|
|
// Extract and sign-extend to 32-bit the various immediates that may be used to calculate the
|
|
// target
|
|
|
|
// Uncompressed immediates
|
|
assign imm_j_type = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 };
|
|
assign imm_b_type = { {19{instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0 };
|
|
|
|
// Compressed immediates
|
|
assign imm_cj_type = { {20{instr[12]}}, instr[12], instr[8], instr[10:9], instr[6], instr[7],
|
|
instr[2], instr[11], instr[5:3], 1'b0 };
|
|
|
|
assign imm_cb_type = { {23{instr[12]}}, instr[12], instr[6:5], instr[2], instr[11:10],
|
|
instr[4:3], 1'b0};
|
|
|
|
// Determine if the instruction is a branch or a jump
|
|
|
|
// Uncompressed branch/jump
|
|
assign instr_b = opcode_e'(instr[6:0]) == OPCODE_BRANCH;
|
|
assign instr_j = opcode_e'(instr[6:0]) == OPCODE_JAL;
|
|
|
|
// Compressed branch/jump
|
|
assign instr_cb = (instr[1:0] == 2'b01) & ((instr[15:13] == 3'b110) | (instr[15:13] == 3'b111));
|
|
assign instr_cj = (instr[1:0] == 2'b01) & ((instr[15:13] == 3'b101) | (instr[15:13] == 3'b001));
|
|
|
|
// Select out the branch offset for target calculation based upon the instruction type
|
|
always_comb begin
|
|
branch_imm = imm_b_type;
|
|
|
|
unique case (1'b1)
|
|
instr_j : branch_imm = imm_j_type;
|
|
instr_b : branch_imm = imm_b_type;
|
|
instr_cj : branch_imm = imm_cj_type;
|
|
instr_cb : branch_imm = imm_cb_type;
|
|
default : ;
|
|
endcase
|
|
end
|
|
|
|
`ASSERT_IF(BranchInsTypeOneHot, $onehot0({instr_j, instr_b, instr_cj, instr_cb}), fetch_valid_i)
|
|
|
|
// Determine branch prediction, taken if offset is negative
|
|
assign instr_b_taken = (instr_b & imm_b_type[31]) | (instr_cb & imm_cb_type[31]);
|
|
|
|
// Always predict jumps taken otherwise take prediction from `instr_b_taken`
|
|
assign predict_branch_taken_o = fetch_valid_i & (instr_j | instr_cj | instr_b_taken);
|
|
// Calculate target
|
|
assign predict_branch_pc_o = fetch_pc_i + branch_imm;
|
|
endmodule
|