Skip to content
Snippets Groups Projects
Commit 21c907cb authored by Alban Gruin's avatar Alban Gruin
Browse files

frontend: remove the BTB and the BHT


Signed-off-by: default avatarAlban Gruin <alban.gruin@irit.fr>
parent 04a4e12b
Branches
No related tags found
No related merge requests found
...@@ -21,7 +21,7 @@ module frontend import ariane_pkg::*; #( ...@@ -21,7 +21,7 @@ module frontend import ariane_pkg::*; #(
input logic clk_i, // Clock input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush request for PCGEN 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, input logic debug_mode_i,
// global input // global input
input logic [riscv::XLEN-1:0] boot_addr_i, input logic [riscv::XLEN-1:0] boot_addr_i,
...@@ -56,9 +56,6 @@ module frontend import ariane_pkg::*; #( ...@@ -56,9 +56,6 @@ module frontend import ariane_pkg::*; #(
logic [riscv::VLEN-1:0] icache_vaddr_q; logic [riscv::VLEN-1:0] icache_vaddr_q;
logic instr_queue_ready; logic instr_queue_ready;
logic [ariane_pkg::INSTR_PER_FETCH-1:0] instr_queue_consumed; 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 // instruction fetch is ready
logic if_ready; logic if_ready;
logic [riscv::VLEN-1:0] npc_d, npc_q; // next PC logic [riscv::VLEN-1:0] npc_d, npc_q; // next PC
...@@ -89,17 +86,9 @@ module frontend import ariane_pkg::*; #( ...@@ -89,17 +86,9 @@ module frontend import ariane_pkg::*; #(
logic [INSTR_PER_FETCH-1:0][31:0] instr; 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][riscv::VLEN-1:0] addr;
logic [INSTR_PER_FETCH-1:0] instruction_valid; 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 // branch-predict update
logic is_mispredict; logic is_mispredict;
logic ras_push, ras_pop;
logic [riscv::VLEN-1:0] ras_update;
// Instruction FIFO // Instruction FIFO
logic [riscv::VLEN-1:0] predict_address; logic [riscv::VLEN-1:0] predict_address;
...@@ -107,6 +96,8 @@ module frontend import ariane_pkg::*; #( ...@@ -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_rvi_cf;
logic [ariane_pkg::INSTR_PER_FETCH-1:0] taken_rvc_cf; logic [ariane_pkg::INSTR_PER_FETCH-1:0] taken_rvc_cf;
logic stalling_d, stalling_q;
logic serving_unaligned; logic serving_unaligned;
// Re-align instructions // Re-align instructions
instr_realign i_instr_realign ( instr_realign i_instr_realign (
...@@ -124,19 +115,6 @@ module frontend import ariane_pkg::*; #( ...@@ -124,19 +115,6 @@ module frontend import ariane_pkg::*; #(
// -------------------- // --------------------
// Branch Prediction // 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; logic bp_valid;
assign branch_speculation_o = bp_valid; assign branch_speculation_o = bp_valid;
...@@ -164,101 +142,88 @@ module frontend import ariane_pkg::*; #( ...@@ -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]); assign is_cf[i] = instruction_valid[i] & (rvi_branch[i] | rvc_branch[i] | rvi_jalr[i] | rvc_jalr[i] | rvc_jr[i]);
end 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 // taken/not taken
always_comb begin always_comb begin
stalling_d = stalling_q;
taken_rvi_cf = '0; taken_rvi_cf = '0;
taken_rvc_cf = '0; taken_rvc_cf = '0;
predict_address = '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; for (int unsigned i = 0; i < INSTR_PER_FETCH; i++) begin
unique case ({is_branch[i], is_jalr[i], is_jump[i]})
ras_push = 1'b0; 3'b000: begin
ras_pop = 1'b0; cf_type[i] = ariane_pkg::NoCF;
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;
end end
end
// its an unconditional jump to an immediate 3'b001: begin
3'b010: begin if (!bp_valid) begin
ras_pop = 1'b0; predict_address = addr[i] + (rvc_jump[i] ? rvc_imm[i] : rvi_imm[i]);
ras_push = 1'b0;
taken_rvi_cf[i] = rvi_jump[i]; taken_rvi_cf[i] = rvi_jump[i];
taken_rvc_cf[i] = rvc_jump[i]; taken_rvc_cf[i] = rvc_jump[i];
cf_type[i] = ariane_pkg::Jump; cf_type[i] = ariane_pkg::Jump;
end bp_valid = 1'b1;
// branch prediction end
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];
end end
if (taken_rvi_cf[i] || taken_rvc_cf[i]) cf_type[i] = ariane_pkg::Branch;
end 3'b010: begin
default:; if (!bp_valid) begin
// default: $error("Decoded more than one control flow"); predict_address = addr[i] + 'h4;
endcase
// calculate the jump target address taken_rvi_cf[i] = 1'b1;
if (taken_rvc_cf[i] || taken_rvi_cf[i]) begin taken_rvc_cf[i] = 1'b1;
predict_address = addr[i] + (taken_rvc_cf[i] ? rvc_imm[i] : rvi_imm[i]); bp_valid = 1'b1;
end 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
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; assign is_mispredict = resolved_branch_i.valid & resolved_branch_i.is_mispredict;
// Cache interface // Cache interface
assign icache_dreq_o.req = instr_queue_ready; assign icache_dreq_o.req = instr_queue_ready & (!should_stall | replay);
assign if_ready = icache_dreq_i.ready & instr_queue_ready; assign if_ready = icache_dreq_i.ready & instr_queue_ready & (!should_stall);
// We need to flush the cache pipeline if: // We need to flush the cache pipeline if:
// 1. We mispredicted // 1. We mispredicted
// 2. Want to flush the whole processor front-end // 2. Want to flush the whole processor front-end
// 3. Need to replay an instruction because the fetch-fifo was full // 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 // 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) // 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; 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 // Next PC
// ------------------- // -------------------
...@@ -328,8 +293,7 @@ module frontend import ariane_pkg::*; #( ...@@ -328,8 +293,7 @@ module frontend import ariane_pkg::*; #(
icache_valid_q <= 1'b0; icache_valid_q <= 1'b0;
icache_vaddr_q <= 'b0; icache_vaddr_q <= 'b0;
icache_ex_valid_q <= ariane_pkg::FE_NONE; icache_ex_valid_q <= ariane_pkg::FE_NONE;
btb_q <= '0; stalling_q <= 1'b0;
bht_q <= '0;
end else begin end else begin
npc_rst_load_q <= 1'b0; npc_rst_load_q <= 1'b0;
npc_q <= npc_d; npc_q <= npc_d;
...@@ -343,49 +307,15 @@ module frontend import ariane_pkg::*; #( ...@@ -343,49 +307,15 @@ module frontend import ariane_pkg::*; #(
end else if (icache_dreq_i.ex.cause == riscv::INSTR_ACCESS_FAULT) begin end else if (icache_dreq_i.ex.cause == riscv::INSTR_ACCESS_FAULT) begin
icache_ex_valid_q <= ariane_pkg::FE_INSTR_ACCESS_FAULT; icache_ex_valid_q <= ariane_pkg::FE_INSTR_ACCESS_FAULT;
end else icache_ex_valid_q <= ariane_pkg::FE_NONE; 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 end
if (flush_i)
stalling_q <= 1'b0;
else
stalling_q <= stalling_d;
end end
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 // we need to inspect up to INSTR_PER_FETCH instructions for branches
// and jumps // and jumps
for (genvar i = 0; i < INSTR_PER_FETCH; i++) begin : gen_instr_scan for (genvar i = 0; i < INSTR_PER_FETCH; i++) begin : gen_instr_scan
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment