diff --git a/src/ariane.sv b/src/ariane.sv index 85dc67927..4d45b65e4 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -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 ), .* ); diff --git a/src/branch_engine.sv b/src/branch_engine.sv index 3542b45e9..b974efdc7 100644 --- a/src/branch_engine.sv +++ b/src/branch_engine.sv @@ -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 \ No newline at end of file diff --git a/src/controller.sv b/src/controller.sv index 4dd49968c..ba9b161c9 100644 --- a/src/controller.sv +++ b/src/controller.sv @@ -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 diff --git a/src/decoder.sv b/src/decoder.sv index 01c10f8a3..7523c13c7 100644 --- a/src/decoder.sv +++ b/src/decoder.sv @@ -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) diff --git a/src/ex_stage.sv b/src/ex_stage.sv index e0d99af37..045a53bd5 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -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 .* ); diff --git a/src/id_stage.sv b/src/id_stage.sv index 6d62156dc..8803def82 100644 --- a/src/id_stage.sv +++ b/src/id_stage.sv @@ -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 diff --git a/src/if_stage.sv b/src/if_stage.sv index dc4e7e0cf..b9771e14c 100644 --- a/src/if_stage.sv +++ b/src/if_stage.sv @@ -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 //------------- diff --git a/src/issue_read_operands.sv b/src/issue_read_operands.sv index 9a161d0ee..52e288314 100644 --- a/src/issue_read_operands.sv +++ b/src/issue_read_operands.sv @@ -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 diff --git a/src/pcgen.sv b/src/pcgen.sv index 71acd2349..ef3c85645 100644 --- a/src/pcgen.sv +++ b/src/pcgen.sv @@ -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