diff --git a/src/frontend/frontend.sv b/src/frontend/frontend.sv index 8416db0d814805ffb50c8b0f11904deb51710a45..f21ed5974f023be21f2c8e6d27aad5d24bbe8e66 100644 --- a/src/frontend/frontend.sv +++ b/src/frontend/frontend.sv @@ -21,7 +21,7 @@ module frontend import ariane_pkg::*; #( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low input logic flush_i, // flush request for PCGEN - input logic flush_bp_i, // flush branch prediction + input logic flush_bp_i, // flush branch prediction, unused input logic debug_mode_i, // global input input logic [riscv::XLEN-1:0] boot_addr_i, @@ -56,9 +56,6 @@ module frontend import ariane_pkg::*; #( logic [riscv::VLEN-1:0] icache_vaddr_q; logic instr_queue_ready; logic [ariane_pkg::INSTR_PER_FETCH-1:0] instr_queue_consumed; - // upper-most branch-prediction from last cycle - btb_prediction_t btb_q; - bht_prediction_t bht_q; // instruction fetch is ready logic if_ready; logic [riscv::VLEN-1:0] npc_d, npc_q; // next PC @@ -89,17 +86,9 @@ module frontend import ariane_pkg::*; #( logic [INSTR_PER_FETCH-1:0][31:0] instr; logic [INSTR_PER_FETCH-1:0][riscv::VLEN-1:0] addr; logic [INSTR_PER_FETCH-1:0] instruction_valid; - // BHT, BTB and RAS prediction - bht_prediction_t [INSTR_PER_FETCH-1:0] bht_prediction; - btb_prediction_t [INSTR_PER_FETCH-1:0] btb_prediction; - bht_prediction_t [INSTR_PER_FETCH-1:0] bht_prediction_shifted; - btb_prediction_t [INSTR_PER_FETCH-1:0] btb_prediction_shifted; - ras_t ras_predict; // branch-predict update logic is_mispredict; - logic ras_push, ras_pop; - logic [riscv::VLEN-1:0] ras_update; // Instruction FIFO logic [riscv::VLEN-1:0] predict_address; @@ -107,6 +96,8 @@ module frontend import ariane_pkg::*; #( logic [ariane_pkg::INSTR_PER_FETCH-1:0] taken_rvi_cf; logic [ariane_pkg::INSTR_PER_FETCH-1:0] taken_rvc_cf; + logic stalling_d, stalling_q; + logic serving_unaligned; // Re-align instructions instr_realign i_instr_realign ( @@ -124,19 +115,6 @@ module frontend import ariane_pkg::*; #( // -------------------- // Branch Prediction // -------------------- - // select the right branch prediction result - // in case we are serving an unaligned instruction in instr[0] we need to take - // the prediction we saved from the previous fetch - assign bht_prediction_shifted[0] = (serving_unaligned) ? bht_q : bht_prediction[0]; - assign btb_prediction_shifted[0] = (serving_unaligned) ? btb_q : btb_prediction[0]; - // for all other predictions we can use the generated address to index - // into the branch prediction data structures - for (genvar i = 1; i < INSTR_PER_FETCH; i++) begin : gen_prediction_address - assign bht_prediction_shifted[i] = bht_prediction[addr[i][$clog2(INSTR_PER_FETCH):1]]; - assign btb_prediction_shifted[i] = btb_prediction[addr[i][$clog2(INSTR_PER_FETCH):1]]; - end - // for the return address stack it doens't matter as we have the - // address of the call/return already logic bp_valid; assign branch_speculation_o = bp_valid; @@ -164,101 +142,88 @@ module frontend import ariane_pkg::*; #( assign is_cf[i] = instruction_valid[i] & (rvi_branch[i] | rvc_branch[i] | rvi_jalr[i] | rvc_jalr[i] | rvc_jr[i]); end + logic should_stall; + assign should_stall = (stalling_q | (|is_jalr)) & + (!resolved_branch_i.valid || + (resolved_branch_i.cf_type inside {Jump, Branch})); + // taken/not taken always_comb begin + stalling_d = stalling_q; taken_rvi_cf = '0; taken_rvc_cf = '0; predict_address = '0; + bp_valid = '0; + + if (replay) begin + stalling_d = 1'b0; + end else if (!stalling_q || (resolved_branch_i.valid && + !(resolved_branch_i.cf_type inside {Jump, Branch}))) begin + stalling_d = 1'b0; - for (int i = 0; i < INSTR_PER_FETCH; i++) cf_type[i] = ariane_pkg::NoCF; - - ras_push = 1'b0; - ras_pop = 1'b0; - ras_update = '0; - - // lower most prediction gets precedence - for (int i = INSTR_PER_FETCH - 1; i >= 0 ; i--) begin - unique case ({is_branch[i], is_jump[i], is_jalr[i]}) - 3'b000:; // regular instruction e.g.: no branch - // unconditional jump to register, we need the BTB to resolve this - 3'b001: begin - ras_pop = 1'b0; - ras_push = 1'b0; - if (btb_prediction_shifted[i].valid) begin - predict_address = btb_prediction_shifted[i].target_address; - cf_type[i] = ariane_pkg::JumpR; + for (int unsigned i = 0; i < INSTR_PER_FETCH; i++) begin + unique case ({is_branch[i], is_jalr[i], is_jump[i]}) + 3'b000: begin + cf_type[i] = ariane_pkg::NoCF; end - end - // its an unconditional jump to an immediate - 3'b010: begin - ras_pop = 1'b0; - ras_push = 1'b0; - taken_rvi_cf[i] = rvi_jump[i]; - taken_rvc_cf[i] = rvc_jump[i]; - cf_type[i] = ariane_pkg::Jump; - end - // branch prediction - 3'b100: begin - ras_pop = 1'b0; - ras_push = 1'b0; - // if we have a valid dynamic prediction use it - if (bht_prediction_shifted[i].valid) begin - taken_rvi_cf[i] = rvi_branch[i] & bht_prediction_shifted[i].taken; - taken_rvc_cf[i] = rvc_branch[i] & bht_prediction_shifted[i].taken; - // otherwise default to static prediction - end else begin - // set if immediate is negative - static prediction - taken_rvi_cf[i] = rvi_branch[i] & rvi_imm[i][riscv::VLEN-1]; - taken_rvc_cf[i] = rvc_branch[i] & rvc_imm[i][riscv::VLEN-1]; + + 3'b001: begin + if (!bp_valid) begin + predict_address = addr[i] + (rvc_jump[i] ? rvc_imm[i] : rvi_imm[i]); + + taken_rvi_cf[i] = rvi_jump[i]; + taken_rvc_cf[i] = rvc_jump[i]; + cf_type[i] = ariane_pkg::Jump; + bp_valid = 1'b1; + end end - if (taken_rvi_cf[i] || taken_rvc_cf[i]) cf_type[i] = ariane_pkg::Branch; - end - default:; - // default: $error("Decoded more than one control flow"); - endcase - // calculate the jump target address - if (taken_rvc_cf[i] || taken_rvi_cf[i]) begin - predict_address = addr[i] + (taken_rvc_cf[i] ? rvc_imm[i] : rvi_imm[i]); - end + + 3'b010: begin + if (!bp_valid) begin + predict_address = addr[i] + 'h4; + + taken_rvi_cf[i] = 1'b1; + taken_rvc_cf[i] = 1'b1; + bp_valid = 1'b1; + stalling_d = 1'b1; + end + end + + 3'b100: begin + if (!bp_valid) begin + taken_rvi_cf[i] = rvi_branch[i] & rvi_imm[i][riscv::VLEN-1]; + taken_rvc_cf[i] = rvc_branch[i] & rvc_imm[i][riscv::VLEN-1]; + bp_valid = 1'b1; + + if (taken_rvi_cf[i] | taken_rvc_cf[i]) begin + predict_address = addr[i] + (taken_rvc_cf[i] ? rvc_imm[i] : rvi_imm[i]); + cf_type[i] = ariane_pkg::Branch; + end else begin + predict_address = addr[i] + 'h4; + end + end + end + + default:; + endcase + end end end - // or reduce struct - always_comb begin - bp_valid = 1'b0; - // BP cannot be valid if we have a return instruction and the RAS is not giving a valid address - // Check that we encountered a control flow and that for a return the RAS - // contains a valid prediction. - for (int i = 0; i < INSTR_PER_FETCH; i++) bp_valid |= ((cf_type[i] != NoCF & cf_type[i] != Return) | ((cf_type[i] == Return) & ras_predict.valid)); - end + assign is_mispredict = resolved_branch_i.valid & resolved_branch_i.is_mispredict; // Cache interface - assign icache_dreq_o.req = instr_queue_ready; - assign if_ready = icache_dreq_i.ready & instr_queue_ready; + assign icache_dreq_o.req = instr_queue_ready & (!should_stall | replay); + assign if_ready = icache_dreq_i.ready & instr_queue_ready & (!should_stall); // We need to flush the cache pipeline if: // 1. We mispredicted // 2. Want to flush the whole processor front-end // 3. Need to replay an instruction because the fetch-fifo was full - assign icache_dreq_o.kill_s1 = is_mispredict | flush_i | replay; + assign icache_dreq_o.kill_s1 = is_mispredict | flush_i; // if we have a valid branch-prediction we need to only kill the last cache request // also if we killed the first stage we also need to kill the second stage (inclusive flush) assign icache_dreq_o.kill_s2 = icache_dreq_o.kill_s1 | bp_valid; - // Update Control Flow Predictions - bht_update_t bht_update; - btb_update_t btb_update; - - assign bht_update.valid = resolved_branch_i.valid - & (resolved_branch_i.cf_type == ariane_pkg::Branch); - assign bht_update.pc = resolved_branch_i.pc; - assign bht_update.taken = resolved_branch_i.is_taken; - // only update mispredicted branches e.g. no returns from the RAS - assign btb_update.valid = resolved_branch_i.valid - & resolved_branch_i.is_mispredict - & (resolved_branch_i.cf_type == ariane_pkg::JumpR); - assign btb_update.pc = resolved_branch_i.pc; - assign btb_update.target_address = resolved_branch_i.target_address; - // ------------------- // Next PC // ------------------- @@ -328,8 +293,7 @@ module frontend import ariane_pkg::*; #( icache_valid_q <= 1'b0; icache_vaddr_q <= 'b0; icache_ex_valid_q <= ariane_pkg::FE_NONE; - btb_q <= '0; - bht_q <= '0; + stalling_q <= 1'b0; end else begin npc_rst_load_q <= 1'b0; npc_q <= npc_d; @@ -343,49 +307,15 @@ module frontend import ariane_pkg::*; #( end else if (icache_dreq_i.ex.cause == riscv::INSTR_ACCESS_FAULT) begin icache_ex_valid_q <= ariane_pkg::FE_INSTR_ACCESS_FAULT; end else icache_ex_valid_q <= ariane_pkg::FE_NONE; - // save the uppermost prediction - btb_q <= btb_prediction[INSTR_PER_FETCH-1]; - bht_q <= bht_prediction[INSTR_PER_FETCH-1]; end + + if (flush_i) + stalling_q <= 1'b0; + else + stalling_q <= stalling_d; end end - ras #( - .DEPTH ( ArianeCfg.RASDepth ) - ) i_ras ( - .clk_i, - .rst_ni, - .flush_i( flush_bp_i ), - .push_i ( ras_push ), - .pop_i ( ras_pop ), - .data_i ( ras_update ), - .data_o ( ras_predict ) - ); - - btb #( - .NR_ENTRIES ( ArianeCfg.BTBEntries ) - ) i_btb ( - .clk_i, - .rst_ni, - .flush_i ( flush_bp_i ), - .debug_mode_i, - .vpc_i ( icache_vaddr_q ), - .btb_update_i ( btb_update ), - .btb_prediction_o ( btb_prediction ) - ); - - bht #( - .NR_ENTRIES ( ArianeCfg.BHTEntries ) - ) i_bht ( - .clk_i, - .rst_ni, - .flush_i ( flush_bp_i ), - .debug_mode_i, - .vpc_i ( icache_vaddr_q ), - .bht_update_i ( bht_update ), - .bht_prediction_o ( bht_prediction ) - ); - // we need to inspect up to INSTR_PER_FETCH instructions for branches // and jumps for (genvar i = 0; i < INSTR_PER_FETCH; i++) begin : gen_instr_scan