mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 21:57:11 -04:00
Fix issue #31
This commit is contained in:
parent
b3173ab6f2
commit
18090c8c1c
9 changed files with 84 additions and 124 deletions
|
@ -84,7 +84,7 @@ module ariane
|
|||
logic halt_if;
|
||||
logic [63:0] pc_if;
|
||||
exception ex_commit; // exception from commit stage
|
||||
branchpredict branchpredict;
|
||||
branchpredict resolved_branch;
|
||||
// --------------
|
||||
// PCGEN <-> IF
|
||||
// --------------
|
||||
|
@ -113,9 +113,7 @@ module ariane
|
|||
logic illegal_c_insn_id_if;
|
||||
logic [63:0] pc_id_if_id;
|
||||
exception exception_if_id;
|
||||
logic branch_valid_if_id;
|
||||
logic [63:0] predict_address_if_id;
|
||||
logic predict_taken_if_id;
|
||||
branchpredict_sbe branch_predict_if_id;
|
||||
// --------------
|
||||
// ID <-> EX
|
||||
// --------------
|
||||
|
@ -137,9 +135,7 @@ module ariane
|
|||
exception alu_exception_ex_id;
|
||||
// Branches and Jumps
|
||||
logic branch_valid_id_ex;
|
||||
logic predict_branch_valid_id_ex;
|
||||
logic [63:0] predict_address_id_ex;
|
||||
logic predict_taken_id_ex;
|
||||
branchpredict_sbe branch_predict_id_ex;
|
||||
// LSU
|
||||
logic [TRANS_ID_BITS-1:0] lsu_trans_id_ex_id;
|
||||
logic lsu_valid_id_ex;
|
||||
|
@ -224,7 +220,7 @@ module ariane
|
|||
pcgen pcgen_i (
|
||||
.flush_i ( flush ),
|
||||
.pc_if_i ( pc_if ),
|
||||
.branchpredict_i ( branchpredict ),
|
||||
.resolved_branch_i ( resolved_branch ),
|
||||
.pc_if_o ( pc_pcgen_if ),
|
||||
.set_pc_o ( set_pc_pcgen_if ),
|
||||
.is_branch_o ( is_branch_pcgen_if ),
|
||||
|
@ -245,9 +241,7 @@ module ariane
|
|||
.halt_if_i ( halt_if ),
|
||||
.set_pc_i ( set_pc_pcgen_if ),
|
||||
.is_branch_i ( is_branch_pcgen_if ),
|
||||
.branch_valid_o ( branch_valid_if_id ),
|
||||
.predict_address_o ( predict_address_if_id ),
|
||||
.predict_taken_o ( predict_taken_if_id ),
|
||||
.branch_predict_o ( branch_predict_if_id ),
|
||||
.fetch_addr_i ( pc_pcgen_if ),
|
||||
.instr_req_o ( fetch_req_if_ex ),
|
||||
.instr_addr_o ( fetch_vaddr_if_ex ),
|
||||
|
@ -298,14 +292,10 @@ module ariane
|
|||
.alu_ready_i ( alu_ready_ex_id ),
|
||||
.alu_valid_o ( alu_valid_id_ex ),
|
||||
// Branches and Jumps
|
||||
.branch_valid_i ( branch_valid_if_id ),
|
||||
.predict_address_i ( predict_address_if_id ),
|
||||
.predict_taken_i ( predict_taken_if_id ),
|
||||
.branch_valid_o ( branch_valid_id_ex ),
|
||||
.predict_branch_valid_o ( predict_branch_valid_id_ex ),
|
||||
.predict_address_o ( predict_address_id_ex ),
|
||||
.predict_taken_o ( predict_taken_id_ex ),
|
||||
.branchpredict_i ( branchpredict ), // in order to resolve the branch
|
||||
.branch_valid_o ( branch_valid_id_ex ), // branch is valid
|
||||
.branch_predict_i ( branch_predict_if_id ), // branch predict from if
|
||||
.branch_predict_o ( branch_predict_id_ex ), // branch predict to ex
|
||||
.resolved_branch_i ( resolved_branch ), // in order to resolve the branch
|
||||
// LSU
|
||||
.lsu_ready_i ( lsu_ready_ex_id ),
|
||||
.lsu_valid_o ( lsu_valid_id_ex ),
|
||||
|
@ -351,10 +341,8 @@ module ariane
|
|||
.alu_exception_o ( alu_exception_ex_id ),
|
||||
// Branches and Jumps
|
||||
.branch_valid_i ( branch_valid_id_ex ),
|
||||
.predict_branch_valid_i ( predict_branch_valid_id_ex ),
|
||||
.predict_address_i ( predict_address_id_ex ),
|
||||
.predict_taken_i ( predict_taken_id_ex ),
|
||||
.branchpredict_o ( branchpredict ),
|
||||
.branch_predict_i ( branch_predict_id_ex ), // branch predict to ex
|
||||
.resolved_branch_o ( resolved_branch ),
|
||||
// LSU
|
||||
.lsu_ready_o ( lsu_ready_ex_id ),
|
||||
.lsu_valid_i ( lsu_valid_id_ex ),
|
||||
|
@ -441,7 +429,6 @@ module ariane
|
|||
// Controller
|
||||
// ------------
|
||||
logic flush_commit_i;
|
||||
logic branchpredict_i;
|
||||
|
||||
controller controller_i (
|
||||
.flush_bp_o ( ),
|
||||
|
@ -454,7 +441,7 @@ module ariane
|
|||
.flush_ready_lsu_i ( ),
|
||||
.flush_commit_i ( flush_commit_i ),
|
||||
.flush_csr_i ( flush_csr_ctrl ),
|
||||
.branchpredict_i ( branchpredict ),
|
||||
.resolved_branch_i ( resolved_branch ),
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
|
@ -20,20 +20,18 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module branch_engine (
|
||||
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 [63:0] pc_i,
|
||||
input logic is_compressed_instr_i,
|
||||
input logic valid_i,
|
||||
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 [63:0] pc_i,
|
||||
input logic is_compressed_instr_i,
|
||||
input logic valid_i,
|
||||
|
||||
input logic [63:0] predict_address_i, // this is the address we predicted
|
||||
input logic predict_branch_valid_i, // we predicted that this was a valid branch
|
||||
input logic predict_taken_i,
|
||||
output branchpredict branchpredict_o, // this is the actual address we are targeting
|
||||
output exception branch_ex_o // branch exception out
|
||||
input branchpredict_sbe branch_predict_i, // this is the address we predicted
|
||||
output branchpredict resolved_branch_o, // this is the actual address we are targeting
|
||||
output exception branch_ex_o // branch exception out
|
||||
);
|
||||
logic [63:0] target_address;
|
||||
logic [63:0] next_pc;
|
||||
|
@ -59,36 +57,43 @@ module branch_engine (
|
|||
default: comparison_result = 1'b1;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb begin : target_address_calc
|
||||
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;
|
||||
// here we handle the various possibilities of mis-predicts
|
||||
always_comb begin : mispredict_handler
|
||||
target_address = 64'b0;
|
||||
resolved_branch_o.pc = 64'b0;
|
||||
resolved_branch_o.target_address = 64'b0;
|
||||
resolved_branch_o.is_taken = 1'b0;
|
||||
resolved_branch_o.valid = valid_i;
|
||||
resolved_branch_o.is_mispredict = 1'b0;
|
||||
// calculate next PC, depending on whether the instruction is compressed or not this may be different
|
||||
next_pc = pc_i + (is_compressed_instr_i) ? 64'h2 : 64'h4;
|
||||
// calculate target address simple 64 bit addition
|
||||
target_address = $signed(operand_c_i) + $signed(imm_i);
|
||||
// save pc
|
||||
branchpredict_o.pc = pc_i;
|
||||
resolved_branch_o.pc = pc_i;
|
||||
// write target address which goes to pc gen
|
||||
branchpredict_o.target_address = (comparison_result) ? target_address : next_pc;
|
||||
branchpredict_o.is_taken = comparison_result;
|
||||
|
||||
resolved_branch_o.target_address = (comparison_result) ? target_address : next_pc;
|
||||
resolved_branch_o.is_taken = comparison_result;
|
||||
// we've detected a branch in ID with the following parameters
|
||||
if (valid_i) begin
|
||||
// we mis-predicted e.g.: the predicted address is unequal to the actual address
|
||||
if (target_address[1:0] == 2'b0) begin
|
||||
// TODO in case of branch which is not taken it is not necessary to check for the address
|
||||
if ( target_address != predict_address_i // we mis-predicted the address of the branch
|
||||
|| predict_taken_i != comparison_result // we mis-predicted the outcome of the branch
|
||||
|| predict_branch_valid_i == 1'b0 // this means branch-prediction thought it was no branch but in reality it was one
|
||||
if ( target_address != branch_predict_i.predict_address_i // we mis-predicted the address of the branch
|
||||
|| branch_predict_i.predict_taken_i != comparison_result // we mis-predicted the outcome of the branch
|
||||
|| branch_predict_i.valid == 1'b0 // this means branch-prediction thought it was no branch but in reality it was one
|
||||
) begin
|
||||
branchpredict_o.is_mispredict = 1'b1;
|
||||
resolved_branch_o.is_mispredict = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
// the other case would be that this instruction was no branch but branchprediction thought that it was one
|
||||
// this is essentially also a mis-predict
|
||||
if (branch_predict_i.valid) begin
|
||||
// re-set the branch to the next PC
|
||||
resolved_branch_o.is_mispredict = 1'b1;
|
||||
resolved_branch_o.target_address = next_pc;
|
||||
end
|
||||
end
|
||||
// use ALU exception signal for storing instruction fetch exceptions if
|
||||
// the target address is not aligned to a 4 byte boundary
|
||||
|
@ -96,8 +101,8 @@ module branch_engine (
|
|||
branch_ex_o.cause = INSTR_ADDR_MISALIGNED;
|
||||
branch_ex_o.tval = 64'b0; // TODO
|
||||
branch_ex_o.valid = 1'b0;
|
||||
|
||||
if (target_address[1:0] != 2'b0)
|
||||
// only throw exception if this is indeed a branch
|
||||
if (valid_i && target_address[1:0] != 2'b0)
|
||||
branch_ex_o.valid = 1'b1;
|
||||
end
|
||||
endmodule
|
|
@ -33,7 +33,7 @@ module controller (
|
|||
input logic flush_ready_lsu_i, // we need to wait for this signal from LSU
|
||||
input logic flush_commit_i, // flush request from commit stage in
|
||||
input logic flush_csr_i,
|
||||
input branchpredict branchpredict_i
|
||||
input branchpredict resolved_branch_i
|
||||
);
|
||||
assign flush_bp_o = 1'b0;
|
||||
|
||||
|
@ -42,7 +42,7 @@ module controller (
|
|||
flush_scoreboard_o = 1'b0;
|
||||
flush_if_o = 1'b0;
|
||||
// flush on mispredict
|
||||
if (branchpredict_i.is_mispredict) begin
|
||||
if (resolved_branch_i.is_mispredict) begin
|
||||
flush_unissued_instr_o = 1'b1;
|
||||
flush_if_o = 1'b1;
|
||||
end
|
||||
|
|
|
@ -11,14 +11,15 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module decoder (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic [63:0] pc_i, // PC from IF
|
||||
input logic is_compressed_i, // is a compressed instruction
|
||||
input logic [31:0] instruction_i, // instruction from IF
|
||||
input exception ex_i, // if an exception occured in if
|
||||
output scoreboard_entry instruction_o, // scoreboard entry to scoreboard
|
||||
output logic is_control_flow_instr_o // this instruction will change the control flow
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic [63:0] pc_i, // PC from IF
|
||||
input logic is_compressed_i, // is a compressed instruction
|
||||
input logic [31:0] instruction_i, // instruction from IF
|
||||
input branchpredict_sbe branch_predict_i,
|
||||
input exception ex_i, // if an exception occured in if
|
||||
output scoreboard_entry instruction_o, // scoreboard entry to scoreboard
|
||||
output logic is_control_flow_instr_o // this instruction will change the control flow
|
||||
);
|
||||
logic illegal_instr;
|
||||
instruction instr;
|
||||
|
@ -58,6 +59,7 @@ module decoder (
|
|||
instruction_o.trans_id = 5'b0;
|
||||
instruction_o.is_compressed = is_compressed_i;
|
||||
instruction_o.use_zimm = 1'b0;
|
||||
instruction_o.bp = branch_predict_i;
|
||||
|
||||
if (~ex_i.valid) begin
|
||||
case (instr.rtype.opcode)
|
||||
|
|
|
@ -44,10 +44,8 @@ module ex_stage #(
|
|||
output exception alu_exception_o,
|
||||
// Branches and Jumps
|
||||
input logic branch_valid_i, // we are using the branch unit
|
||||
input logic predict_branch_valid_i,
|
||||
input logic [63:0] predict_address_i,
|
||||
input logic predict_taken_i,
|
||||
output branchpredict branchpredict_o, // the branch engine uses the write back from the ALU
|
||||
input branchpredict_sbe branch_predict_i, // branch prediction in
|
||||
output branchpredict resolved_branch_o, // the branch engine uses the write back from the ALU
|
||||
// LSU
|
||||
output logic lsu_ready_o, // FU is ready
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
|
@ -112,7 +110,7 @@ module ex_stage #(
|
|||
.adder_result_ext_o ( ),
|
||||
.result_o ( alu_result_o ),
|
||||
.is_equal_result_o ( ),
|
||||
.comparison_result_o( ),
|
||||
.comparison_result_o ( ),
|
||||
.*
|
||||
);
|
||||
|
||||
|
@ -121,7 +119,7 @@ module ex_stage #(
|
|||
// --------------------
|
||||
branch_engine branch_engine_i (
|
||||
.valid_i ( branch_valid_i ),
|
||||
.branch_ex_o ( alu_exception_o ),
|
||||
.branch_ex_o ( alu_exception_o ), // we use the ALU exception WB for the branch exception
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
|
@ -50,23 +50,18 @@ module id_stage #(
|
|||
|
||||
input logic alu_ready_i,
|
||||
output logic alu_valid_o,
|
||||
output logic branch_valid_o, // use branch prediction unit
|
||||
// Branch predict In
|
||||
input logic branch_valid_i,
|
||||
input logic [63:0] predict_address_i,
|
||||
input logic predict_taken_i,
|
||||
// Branch predict Out
|
||||
output logic branch_valid_o, // use the branch engine
|
||||
output logic predict_branch_valid_o, // this is a valid prediction
|
||||
output logic [63:0] predict_address_o,
|
||||
output logic predict_taken_o,
|
||||
input branchpredict_sbe branch_predict_i,
|
||||
// ex just resolved our predicted branch, we are ready to accept new requests
|
||||
input branchpredict branchpredict_i,
|
||||
input branchpredict resolved_branch_i,
|
||||
|
||||
input logic lsu_ready_i,
|
||||
output logic lsu_valid_o,
|
||||
|
||||
input logic mult_ready_i,
|
||||
output logic mult_valid_o,
|
||||
output logic mult_valid_o, // Branch predict Out
|
||||
output branchpredict_sbe branch_predict_o,
|
||||
|
||||
input logic csr_ready_i,
|
||||
output logic csr_valid_o,
|
||||
|
@ -117,50 +112,31 @@ module id_stage #(
|
|||
// instructions past a branch. We need to resolve the branch beforehand.
|
||||
// This limitation is in place to ease the backtracking of mis-predicted branches as they
|
||||
// can simply be in the front-end of the processor.
|
||||
logic unresolved_branch_n, unresolved_branch_q;
|
||||
// branch predict registers
|
||||
logic branch_valid_n, branch_valid_q;
|
||||
logic [63:0] predict_address_n, predict_address_q;
|
||||
logic predict_taken_n, predict_taken_q;
|
||||
logic unresolved_branch_n, unresolved_branch_q;
|
||||
|
||||
always_comb begin : unresolved_branch
|
||||
unresolved_branch_n = unresolved_branch_q;
|
||||
// we just resolved the branch
|
||||
if (branchpredict_i.valid) begin
|
||||
if (resolved_branch_i.valid) begin
|
||||
unresolved_branch_n = 1'b0;
|
||||
end
|
||||
// if the instruction is valid and it is a control flow instruction
|
||||
if (instruction_valid_i && is_control_flow_instr) begin
|
||||
unresolved_branch_n = 1'b1;
|
||||
end
|
||||
|
||||
branch_valid_n = branch_valid_q;
|
||||
predict_address_n = predict_address_q;
|
||||
predict_taken_n = predict_taken_q;
|
||||
// save branch prediction information until the ex stage resolves the prediction
|
||||
if (~unresolved_branch_q) begin
|
||||
branch_valid_n = branch_valid_i;
|
||||
predict_address_n = predict_address_i;
|
||||
predict_taken_n = predict_taken_i;
|
||||
end
|
||||
end
|
||||
// we are ready if we are not full and don't have any unresolved branches, but it can be
|
||||
// the case that we have an unresolved branch which is cleared in that cycle (branchpredict_i.valid == 1)
|
||||
assign ready_o = ~full && (~unresolved_branch_q || branchpredict_i.valid) && ~(instruction_valid_i && is_control_flow_instr);
|
||||
// output branch prediction bits
|
||||
assign predict_branch_valid_o = branch_valid_q;
|
||||
assign predict_address_o = predict_address_q;
|
||||
assign predict_taken_o = predict_taken_q;
|
||||
// the case that we have an unresolved branch which is cleared in that cycle (resolved_branch_i.valid == 1)
|
||||
assign ready_o = ~full && (~unresolved_branch_q || resolved_branch_i.valid) && ~(instruction_valid_i && is_control_flow_instr);
|
||||
|
||||
decoder decoder_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.pc_i ( pc_if_i ),
|
||||
.is_compressed_i ( is_compressed_i ),
|
||||
.instruction_i ( instruction_i ),
|
||||
.ex_i ( ex_if_i ),
|
||||
.instruction_o ( decoded_instr_dc_sb ),
|
||||
.is_control_flow_instr_o ( is_control_flow_instr )
|
||||
.is_control_flow_instr_o ( is_control_flow_instr ),
|
||||
.*
|
||||
);
|
||||
|
||||
scoreboard #(
|
||||
|
@ -209,14 +185,8 @@ module id_stage #(
|
|||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
unresolved_branch_q <= 1'b0;
|
||||
branch_valid_q <= 1'b0;
|
||||
predict_address_q <= 64'b0;
|
||||
predict_taken_q <= 1'b0;
|
||||
end else begin
|
||||
unresolved_branch_q <= unresolved_branch_n;
|
||||
branch_valid_q <= branch_valid_n;
|
||||
predict_address_q <= predict_address_n;
|
||||
predict_taken_q <= predict_taken_n;
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -41,9 +41,7 @@ module if_stage (
|
|||
input logic set_pc_i, // set new PC
|
||||
input logic is_branch_i, // the new PC was a branch e.g.: branch or jump
|
||||
// branchpredict out
|
||||
output logic branch_valid_o,
|
||||
output logic [63:0] predict_address_o,
|
||||
output logic predict_taken_o,
|
||||
output branchpredict_sbe branch_predict_o,
|
||||
// instruction cache interface
|
||||
output logic instr_req_o,
|
||||
output logic [63:0] instr_addr_o,
|
||||
|
@ -269,10 +267,7 @@ module if_stage (
|
|||
assign if_ready = valid & id_ready_i;
|
||||
assign if_valid = (~halt_if_i) & if_ready;
|
||||
assign if_busy_o = prefetch_busy;
|
||||
assign branch_valid_o = branch_valid_q;
|
||||
assign predict_address_o = predict_address_q;
|
||||
assign predict_taken_o = predict_taken_q;
|
||||
|
||||
assign branch_predict_o = {predict_address_q, predict_taken_q, branch_valid_q};
|
||||
//-------------
|
||||
// Assertions
|
||||
//-------------
|
||||
|
|
|
@ -52,6 +52,7 @@ module issue_read_operands (
|
|||
output logic alu_valid_o, // Output is valid
|
||||
// Branches and Jumps
|
||||
output logic branch_valid_o, // this is a valid branch instruction
|
||||
output branchpredict_sbe branch_predict_o,
|
||||
// LSU
|
||||
input logic lsu_ready_i, // FU is ready
|
||||
output logic lsu_valid_o, // Output is valid
|
||||
|
@ -319,6 +320,7 @@ module issue_read_operands (
|
|||
trans_id_q <= 5'b0;
|
||||
pc_o <= 64'b0;
|
||||
is_compressed_instr_o <= 1'b0;
|
||||
branch_predict_o <= '{default: 0};
|
||||
end else begin
|
||||
operand_a_q <= operand_a_n;
|
||||
operand_b_q <= operand_b_n;
|
||||
|
@ -333,6 +335,7 @@ module issue_read_operands (
|
|||
trans_id_q <= trans_id_n;
|
||||
pc_o <= issue_instr_i.pc;
|
||||
is_compressed_instr_o <= issue_instr_i.is_compressed;
|
||||
branch_predict_o <= issue_instr_i.bp;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -25,7 +25,7 @@ module pcgen (
|
|||
|
||||
input logic flush_i,
|
||||
input logic [63:0] pc_if_i,
|
||||
input branchpredict branchpredict_i, // from controller signaling a branchpredict -> update BTB
|
||||
input branchpredict resolved_branch_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
|
||||
|
@ -74,7 +74,7 @@ module pcgen (
|
|||
btb_i
|
||||
(
|
||||
.vpc_i ( predict_pc ),
|
||||
.branchpredict_i ( branchpredict_i ),
|
||||
.branchpredict_i ( resolved_branch_i ),
|
||||
.is_branch_o ( is_branch ),
|
||||
.predict_taken_o ( predict_taken ),
|
||||
.branch_target_address_o ( branch_target_address ),
|
||||
|
@ -104,10 +104,10 @@ module pcgen (
|
|||
// 1.Debug
|
||||
|
||||
// 3. Control flow change request
|
||||
if (branchpredict_i.is_mispredict) begin
|
||||
if (resolved_branch_i.is_mispredict) begin
|
||||
set_pc_n = 1'b1;
|
||||
// we already got the correct target address
|
||||
npc_n = branchpredict_i.target_address;
|
||||
npc_n = resolved_branch_i.target_address;
|
||||
end
|
||||
// 2. Exception
|
||||
if (ex_i.valid) begin
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue