This commit is contained in:
Florian Zaruba 2017-05-12 19:21:42 +02:00
parent b3173ab6f2
commit 18090c8c1c
9 changed files with 84 additions and 124 deletions

View file

@ -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 ),
.*
);

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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
.*
);

View file

@ -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

View file

@ -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
//-------------

View file

@ -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

View file

@ -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