Move branch-prediction to separate if stage

This commit is contained in:
Florian Zaruba 2017-06-23 23:58:45 +02:00
parent bfae40e2a8
commit 3b4f20ade6
3 changed files with 31 additions and 21 deletions

View file

@ -46,13 +46,11 @@ module btb #(
logic [$clog2(NR_ENTRIES)-1:0] index, update_pc;
logic [BITS_SATURATION_COUNTER-1:0] saturation_counter;
// branch-predict input register
branchpredict branch_predict_q;
// get actual index positions
// we ignore the 0th bit since all instructions are aligned on
// a half word boundary
assign update_pc = branch_predict_q.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
assign update_pc = branch_predict_i.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
assign index = vpc_i[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
// we combinatorially predict the branch and the target address
@ -66,32 +64,32 @@ module btb #(
btb_n = btb_q;
saturation_counter = btb_q[update_pc].saturation_counter;
if (branch_predict_q.valid) begin
if (branch_predict_i.valid) begin
btb_n[update_pc].valid = 1'b1;
// update saturation counter
// first check if counter is already saturated in the positive regime e.g.: branch taken
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}}) begin
// we can safely decrease it
if (~branch_predict_q.is_taken)
if (~branch_predict_i.is_taken)
btb_n[update_pc].saturation_counter = saturation_counter - 1;
// then check if it saturated in the negative regime e.g.: branch not taken
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}}) begin
// we can safely increase it
if (branch_predict_q.is_taken)
if (branch_predict_i.is_taken)
btb_n[update_pc].saturation_counter = saturation_counter + 1;
end else begin // otherwise we are not in any boundaries and can decrease or increase it
if (branch_predict_q.is_taken)
if (branch_predict_i.is_taken)
btb_n[update_pc].saturation_counter = saturation_counter + 1;
else
btb_n[update_pc].saturation_counter = saturation_counter - 1;
end
// the target address is simply updated
btb_n[update_pc].target_address = branch_predict_q.target_address;
btb_n[update_pc].target_address = branch_predict_i.target_address;
// as is the information whether this was a compressed branch
btb_n[update_pc].is_lower_16 = branch_predict_q.is_lower_16;
btb_n[update_pc].is_lower_16 = branch_predict_i.is_lower_16;
// check if we should invalidate this entry, this happens in case we predicted a branch
// where actually none-is (aliasing)
if (branch_predict_q.clear) begin
if (branch_predict_i.clear) begin
btb_n[update_pc].valid = 1'b0;
end
end
@ -103,8 +101,6 @@ module btb #(
// Bias the branches to be taken upon first arrival
for (int i = 0; i < NR_ENTRIES; i++)
btb_q[i] <= '{1'b0, 64'b0, 2'b10, 1'b0};
branch_predict_q <= '0;
end else begin
// evict all entries
if (flush_i) begin
@ -115,7 +111,7 @@ module btb #(
end else begin
btb_q <= btb_n;
end
branch_predict_q <= branch_predict_i;
end
end
endmodule

View file

@ -338,7 +338,7 @@ module issue_read_operands (
`ifndef verilator
assert property (
@(posedge clk_i) (alu_valid_q || lsu_valid_q || csr_valid_q) |-> (!$isunknown(operand_a_q) && !$isunknown(operand_b_q)))
else $error ("Got unknown value in one of the operands");
else $warning ("Got unknown value in one of the operands");
`endif
`endif
endmodule

View file

@ -44,9 +44,10 @@ module pcgen (
);
logic [63:0] npc_n, npc_q;
logic set_pc_n, set_pc_q;
branchpredict_sbe branch_predict_btb;
assign fetch_address_o = npc_q;
// branch-predict input register -> this path is critical
branchpredict resolved_branch_q;
btb #(
.NR_ENTRIES ( BTB_ENTRIES ),
@ -57,7 +58,7 @@ module pcgen (
// Use the PC from last cycle to perform branch lookup for the current cycle
.flush_i ( flush_bp_i ),
.vpc_i ( npc_q ),
.branch_predict_i ( resolved_branch_i ), // update port
.branch_predict_i ( resolved_branch_q ), // update port
.branch_predict_o ( branch_predict_btb ), // read port
.*
);
@ -73,8 +74,12 @@ module pcgen (
// 5. Return from exception
// 6. Pipeline Flush because of CSR side effects
always_comb begin : npc_select
// set fetch address
fetch_address_o = npc_q;
branch_predict_o = branch_predict_btb;
fetch_valid_o = 1'b1;
// this tells us whether it is a consecutive PC or a completely new PC
set_pc_n = 1'b0;
// -------------------------------
// 0. Default assignment
@ -103,9 +108,11 @@ module pcgen (
// -------------------------------
// 3. Control flow change request
// -------------------------------
if (resolved_branch_i.is_mispredict) begin
// check if had a mis-predict the cycle earlier and if we can reset the PC (e.g.: it was a predicted or consecutive PC
// which was set a cycle earlier)
if (resolved_branch_q.is_mispredict && !set_pc_q) begin
// we already got the correct target address
npc_n = resolved_branch_i.target_address;
fetch_address_o = resolved_branch_q.target_address;
end
// -------------------------------
@ -114,6 +121,7 @@ module pcgen (
if (ex_i.valid) begin
npc_n = trap_vector_base_i;
branch_predict_o.valid = 1'b0;
set_pc_n = 1'b1;
end
// -------------------------------
@ -121,6 +129,7 @@ module pcgen (
// -------------------------------
if (eret_i) begin
npc_n = epc_i;
set_pc_n = 1'b1;
end
// -----------------------------------------------
@ -133,6 +142,7 @@ module pcgen (
// as CSR instructions do not exist in a compressed form
// we can unconditionally do PC + 4 here
npc_n = pc_commit_i + 64'h4;
set_pc_n = 1'b1;
end
// fetch enable
@ -146,9 +156,13 @@ module pcgen (
// PCGEN -> IF Pipeline Stage
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
npc_q <= boot_addr_i;
npc_q <= boot_addr_i;
set_pc_q <= 1'b0;
resolved_branch_q <= '0;
end else begin
npc_q <= npc_n;
npc_q <= npc_n;
set_pc_q <= set_pc_n;
resolved_branch_q <= resolved_branch_i;
end
end