mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 13:47:13 -04:00
Integrate branch prediction, fix #2
This commit is contained in:
parent
5a3c0e3fe2
commit
a07a8f0a00
8 changed files with 118 additions and 80 deletions
|
@ -40,11 +40,12 @@ package ariane_pkg;
|
|||
|
||||
// miss-predict
|
||||
typedef struct packed {
|
||||
logic [63:0] pc;
|
||||
logic [63:0] target_address;
|
||||
logic is_taken;
|
||||
logic valid; // is miss-predict
|
||||
} mispredict;
|
||||
logic [63:0] pc; // pc of predict or mis-predict
|
||||
logic [63:0] target_address; // target address at which to jump, or not
|
||||
logic is_mispredict; // set if this was a mis-predict
|
||||
logic is_taken; // branch is taken
|
||||
logic valid; // prediction with all its values is valid
|
||||
} branchpredict;
|
||||
|
||||
typedef enum logic[3:0] {
|
||||
NONE, LSU, ALU, MULT, CSR
|
||||
|
|
|
@ -93,7 +93,7 @@ module ariane
|
|||
// --------------
|
||||
// PCGEN <-> EX
|
||||
// --------------
|
||||
mispredict mispredict_ex_pcgen;
|
||||
branchpredict branchpredict_ex_pcgen;
|
||||
// --------------
|
||||
// PCGEN <-> CSR
|
||||
// --------------
|
||||
|
@ -121,12 +121,18 @@ module ariane
|
|||
fu_op operator_id_ex;
|
||||
logic [63:0] operand_a_id_ex;
|
||||
logic [63:0] operand_b_id_ex;
|
||||
logic [63:0] operand_c_id_ex;
|
||||
// ALU
|
||||
logic alu_ready_ex_id;
|
||||
logic alu_valid_id_ex;
|
||||
logic [TRANS_ID_BITS-1:0] alu_trans_id_ex_id;
|
||||
logic alu_valid_ex_id;
|
||||
logic [63:0] alu_result_ex_id;
|
||||
exception alu_exception_ex_id;
|
||||
// Branches and Jumps
|
||||
logic branch_valid_id_ex;
|
||||
logic [63:0] predict_address_id_ex;
|
||||
logic predict_taken_id_ex;
|
||||
// LSU
|
||||
logic [TRANS_ID_BITS-1:0] lsu_trans_id_ex_id;
|
||||
logic lsu_valid_id_ex;
|
||||
|
@ -205,7 +211,7 @@ module ariane
|
|||
pcgen pcgen_i (
|
||||
.flush_i ( flush ),
|
||||
.pc_if_i ( pc_if ),
|
||||
.mispredict_i ( mispredict_ex_pcgen ),
|
||||
.branchpredict_i ( branchpredict_ex_pcgen ),
|
||||
.pc_if_o ( pc_pcgen_if ),
|
||||
.set_pc_o ( set_pc_pcgen_if ),
|
||||
.is_branch_o ( is_branch_o ),
|
||||
|
@ -262,25 +268,30 @@ module ariane
|
|||
.operator_o ( operator_id_ex ),
|
||||
.operand_a_o ( operand_a_id_ex ),
|
||||
.operand_b_o ( operand_b_id_ex ),
|
||||
.operand_c_o ( operand_c_id_ex ),
|
||||
.imm_o ( imm_id_ex ),
|
||||
.trans_id_o ( trans_id_id_ex ),
|
||||
|
||||
// ALU
|
||||
.alu_ready_i ( alu_ready_ex_id ),
|
||||
.alu_valid_o ( alu_valid_id_ex ),
|
||||
|
||||
// Branches and Jumps
|
||||
.branch_valid_o ( branch_valid_id_ex ),
|
||||
.predict_address_o ( predict_address_id_ex ),
|
||||
.predict_taken_o ( predict_taken_id_ex ),
|
||||
// LSU
|
||||
.lsu_ready_i ( lsu_ready_ex_id ),
|
||||
.lsu_valid_o ( lsu_valid_id_ex ),
|
||||
|
||||
// Multiplier
|
||||
.mult_ready_i ( mult_ready_ex_id ),
|
||||
.mult_valid_o ( mult_valid_id_ex ),
|
||||
|
||||
// CSR
|
||||
.csr_ready_i ( csr_ready_ex_id ),
|
||||
.csr_valid_o ( csr_valid_id_ex ),
|
||||
|
||||
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id , csr_trans_id_ex_id} ),
|
||||
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, csr_result_ex_id} ),
|
||||
.ex_ex_i ( {{$bits(exception){1'b0}}, lsu_exception_ex_id, {$bits(exception){1'b0}} } ),
|
||||
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, csr_valid_ex_id} ),
|
||||
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, csr_trans_id_ex_id }),
|
||||
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, csr_result_ex_id }),
|
||||
.ex_ex_i ( {alu_exception_ex_id, lsu_exception_ex_id, {$bits(exception){1'b0}} }),
|
||||
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, csr_valid_ex_id }),
|
||||
|
||||
.waddr_a_i ( waddr_a_commit_id ),
|
||||
.wdata_a_i ( wdata_a_commit_id ),
|
||||
|
@ -298,15 +309,21 @@ module ariane
|
|||
.operator_i ( operator_id_ex ),
|
||||
.operand_a_i ( operand_a_id_ex ),
|
||||
.operand_b_i ( operand_b_id_ex ),
|
||||
.operand_c_i ( operand_c_id_ex ),
|
||||
.imm_i ( imm_id_ex ),
|
||||
.trans_id_i ( trans_id_id_ex ),
|
||||
.comparison_result_o ( ),
|
||||
// ALU
|
||||
.alu_ready_o ( alu_ready_ex_id ),
|
||||
.alu_valid_i ( alu_valid_id_ex ),
|
||||
.alu_result_o ( alu_result_ex_id ),
|
||||
.alu_trans_id_o ( alu_trans_id_ex_id ),
|
||||
.alu_valid_o ( alu_valid_ex_id ),
|
||||
.alu_exception_o ( alu_exception_ex_id ),
|
||||
// Branches and Jumps
|
||||
.branch_valid_i ( branch_valid_id_ex ),
|
||||
.predict_address_i ( predict_address_id_ex ),
|
||||
.predict_taken_i ( predict_taken_id_ex ),
|
||||
.branchpredict_o ( branchpredict_ex_pcgen ),
|
||||
// LSU
|
||||
.lsu_ready_o ( lsu_ready_ex_id ),
|
||||
.lsu_valid_i ( lsu_valid_id_ex ),
|
||||
|
@ -393,14 +410,13 @@ module ariane
|
|||
// Controller
|
||||
// ------------
|
||||
logic flush_commit_i;
|
||||
logic mispredict_i;
|
||||
mispredict mispredict_o;
|
||||
logic branchpredict_i;
|
||||
|
||||
controller i_controller (
|
||||
.clk_i (clk_i ),
|
||||
.rst_ni (rst_ni ),
|
||||
.flush_commit_i(flush_commit_i),
|
||||
.mispredict_i (mispredict_i ),
|
||||
.mispredict_o (mispredict_o )
|
||||
.clk_i (clk_i ),
|
||||
.rst_ni (rst_ni ),
|
||||
.flush_commit_i (flush_commit_i),
|
||||
.branchpredict_i (branchpredict_i )
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -20,36 +20,37 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module branch_engine (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
input logic [63:0] operand_a,
|
||||
input logic [63:0] operand_b,
|
||||
input logic valid_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic valid_i,
|
||||
|
||||
input logic comparison_result_i, // result of comparison
|
||||
input logic [63:0] predict_address_i, // this is the address we predicted
|
||||
output mispredict mispredict_o, // this is the actual address we are targeting
|
||||
output exception branch_ex_o // branch exception out
|
||||
input logic comparison_result_i, // result of comparison
|
||||
input logic [63:0] predict_address_i, // this is the address we predicted
|
||||
output branchpredict branchpredict_o, // this is the actual address we are targeting
|
||||
output exception branch_ex_o // branch exception out
|
||||
);
|
||||
logic [63:0] target_address;
|
||||
|
||||
always_comb begin : target_address_calc
|
||||
target_address = 64'b0;
|
||||
mispredict_o.pc = 64'b0;
|
||||
mispredict_o.target_address = 64'b0;
|
||||
mispredict_o.is_taken = 1'b0;
|
||||
mispredict_o.valid = 1'b0;
|
||||
target_address = 64'b0;
|
||||
branchpredict_o.pc = 64'b0;
|
||||
branchpredict_o.target_address = 64'b0;
|
||||
branchpredict_o.is_taken = 1'b0;
|
||||
branchpredict_o.valid = valid_i;
|
||||
branchpredict_o.is_mispredict = 1'b0;
|
||||
|
||||
if (valid_i) begin
|
||||
// calculate target address simple 64 bit addition
|
||||
target_address = $signed(operand_a) + $signed(operand_b);
|
||||
target_address = $signed(operand_a_i) + $signed(operand_b_i);
|
||||
// write target address
|
||||
branchpredict_o.target_address = target_address;
|
||||
branchpredict_o.is_taken = comparison_result_i;
|
||||
// we mis-predicted e.g.: the predicted address is unequal to the actual address
|
||||
if (target_address != predict_address_i && target_address[1:0] == 2'b0) begin
|
||||
// write target address
|
||||
mispredict_o.target_address = target_address;
|
||||
mispredict_o.is_taken = comparison_result_i;
|
||||
mispredict_o.valid = 1'b1;
|
||||
branchpredict_o.is_mispredict = 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
16
src/btb.sv
16
src/btb.sv
|
@ -28,7 +28,7 @@ module btb #(
|
|||
input logic flush_i, // flush the btb
|
||||
|
||||
input logic [63:0] vpc_i, // virtual PC from IF stage
|
||||
input mispredict mispredict_i, // a miss-predict happened -> update data structure
|
||||
input branchpredict branchpredict_i, // a miss-predict happened -> update data structure
|
||||
|
||||
output logic is_branch_o, // instruction at vpc_i is a branch
|
||||
output logic predict_taken_o, // the branch is taken
|
||||
|
@ -51,7 +51,7 @@ module btb #(
|
|||
// get actual index positions
|
||||
// we ignore the 0th bit since all instructions are aligned on
|
||||
// a half word boundary
|
||||
assign update_pc = mispredict_i.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
|
||||
assign update_pc = branchpredict_i.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
|
||||
assign index = vpc_i[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
|
||||
|
||||
// we combinatorially predict the branch and the target address
|
||||
|
@ -60,29 +60,29 @@ module btb #(
|
|||
assign branch_target_address_o = btb_q[$unsigned(index)].target_address;
|
||||
|
||||
// update on a miss-predict
|
||||
always_comb begin : update_mispredict
|
||||
always_comb begin : update_branchpredict
|
||||
btb_n = btb_q;
|
||||
saturation_counter = btb_q[$unsigned(update_pc)].saturation_counter;
|
||||
|
||||
if (mispredict_i.valid) begin
|
||||
if (branchpredict_i.valid) begin
|
||||
btb_n[$unsigned(update_pc)].valid = 1'b1;
|
||||
// update saturation counter
|
||||
// first check if counter is already saturated in the positive regime e.g.: branch taken
|
||||
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}} && ~mispredict_i.is_taken) begin
|
||||
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}} && ~branchpredict_i.is_taken) begin
|
||||
// we can safely decrease it
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
|
||||
// then check if it saturated in the negative regime e.g.: branch not taken
|
||||
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}} && mispredict_i.is_taken) begin
|
||||
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}} && branchpredict_i.is_taken) begin
|
||||
// we can safely increase it
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
|
||||
end else begin // otherwise we are not in any boundaries and can decrease or increase it
|
||||
if (mispredict_i.is_taken)
|
||||
if (branchpredict_i.is_taken)
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
|
||||
else
|
||||
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
|
||||
end
|
||||
// the target address is simply updated
|
||||
btb_n[$unsigned(update_pc)].target_address = mispredict_i.target_address;
|
||||
btb_n[$unsigned(update_pc)].target_address = branchpredict_i.target_address;
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -20,13 +20,11 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module controller (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
input logic flush_commit_i, // flush request from commit stage in
|
||||
input logic mispredict_i,
|
||||
|
||||
output mispredict mispredict_o // to pcgen update branch history table
|
||||
input logic flush_commit_i, // flush request from commit stage in
|
||||
input logic branchpredict_i
|
||||
);
|
||||
|
||||
// flush on mispredict
|
||||
|
|
|
@ -29,6 +29,7 @@ module ex_stage #(
|
|||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] operand_c_i,
|
||||
input logic [63:0] imm_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
|
||||
|
@ -37,8 +38,13 @@ module ex_stage #(
|
|||
input logic alu_valid_i, // Output is valid
|
||||
output logic alu_valid_o, // ALU result is valid
|
||||
output logic [63:0] alu_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output logic comparison_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output exception alu_exception_o,
|
||||
// Branches and Jumps
|
||||
input logic branch_valid_i,
|
||||
input logic [63:0] predict_address_i,
|
||||
output branchpredict branchpredict_o,
|
||||
input logic predict_taken_i,
|
||||
// LSU
|
||||
output logic lsu_ready_o, // FU is ready
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
|
@ -90,7 +96,8 @@ module ex_stage #(
|
|||
output logic mult_ready_o, // FU is ready
|
||||
input logic mult_valid_i // Output is valid
|
||||
);
|
||||
|
||||
// Wires
|
||||
logic comparison_result_alu_branch;
|
||||
|
||||
// ALU is a single cycle instructions, hence it is always ready
|
||||
assign alu_ready_o = 1'b1;
|
||||
|
@ -100,17 +107,27 @@ module ex_stage #(
|
|||
// ALU
|
||||
// -----
|
||||
alu alu_i (
|
||||
.adder_result_o ( ),
|
||||
.adder_result_ext_o ( ),
|
||||
.result_o ( alu_result_o ),
|
||||
.comparison_result_o ( comparison_result_o ),
|
||||
.is_equal_result_o ( ),
|
||||
.adder_result_o ( ),
|
||||
.adder_result_ext_o ( ),
|
||||
.result_o ( alu_result_o ),
|
||||
.comparison_result_o ( comparison_result_alu_branch ),
|
||||
.is_equal_result_o ( ),
|
||||
.*
|
||||
);
|
||||
// --------------------
|
||||
// Control Flow Change
|
||||
// -------------------
|
||||
|
||||
// --------------------
|
||||
// Branch Engine
|
||||
// --------------------
|
||||
branch_engine branch_engine_i (
|
||||
.operand_a_i ( operand_c_i ),
|
||||
.operand_b_i ( imm_i ),
|
||||
.valid_i ( branch_valid_i ),
|
||||
.comparison_result_i ( comparison_result_alu_branch ),
|
||||
.predict_address_i ( predict_address_i ),
|
||||
.branchpredict_o ( branchpredict_o ),
|
||||
.branch_ex_o ( alu_exception_o ),
|
||||
.*
|
||||
);
|
||||
|
||||
// ----------------
|
||||
// Multiplication
|
||||
|
|
|
@ -39,12 +39,17 @@ module id_stage #(
|
|||
output fu_op operator_o,
|
||||
output logic [63:0] operand_a_o,
|
||||
output logic [63:0] operand_b_o,
|
||||
output logic [63:0] operand_c_o,
|
||||
output logic [63:0] imm_o,
|
||||
output logic [TRANS_ID_BITS-1:0] trans_id_o,
|
||||
|
||||
input logic alu_ready_i,
|
||||
output logic alu_valid_o,
|
||||
|
||||
output logic branch_valid_o,
|
||||
output logic [63:0] predict_address_o,
|
||||
output logic predict_taken_o,
|
||||
|
||||
input logic lsu_ready_i,
|
||||
output logic lsu_valid_o,
|
||||
|
||||
|
|
26
src/pcgen.sv
26
src/pcgen.sv
|
@ -20,22 +20,22 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module pcgen (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
input logic flush_i,
|
||||
input logic [63:0] pc_if_i,
|
||||
input mispredict mispredict_i, // from controller signaling a mispredict -> update BTB
|
||||
input logic flush_i,
|
||||
input logic [63:0] pc_if_i,
|
||||
input branchpredict branchpredict_i, // from controller signaling a branchpredict -> update BTB
|
||||
// to IF
|
||||
output logic [63:0] pc_if_o, // new PC
|
||||
output logic set_pc_o, // request the PC to be set to pc_if_o
|
||||
output logic is_branch_o, // to check if we mispredicted we need to save whether this was a branch or not
|
||||
output logic [63:0] pc_if_o, // new PC
|
||||
output logic set_pc_o, // request the PC to be set to pc_if_o
|
||||
output logic is_branch_o, // to check if we branchpredicted we need to save whether this was a branch or not
|
||||
// global input
|
||||
input logic [63:0] boot_addr_i,
|
||||
input logic [63:0] boot_addr_i,
|
||||
// CSR input
|
||||
input logic [63:0] epc_i, // return from exception
|
||||
input logic [63:0] trap_vector_base_i, // base of trap vector
|
||||
input exception ex_i // exception in - from commit
|
||||
input logic [63:0] epc_i, // return from exception
|
||||
input logic [63:0] trap_vector_base_i, // base of trap vector
|
||||
input exception ex_i // exception in - from commit
|
||||
);
|
||||
|
||||
logic [63:0] branch_target_address;
|
||||
|
@ -56,7 +56,7 @@ module pcgen (
|
|||
btb_i
|
||||
(
|
||||
.vpc_i ( pc_if_i ),
|
||||
.mispredict_i ( mispredict_i ),
|
||||
.branchpredict_i ( branchpredict_i ),
|
||||
.is_branch_o ( is_branch ),
|
||||
.predict_taken_o ( predict_taken ),
|
||||
.branch_target_address_o ( branch_target_address ),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue