🐛 Branching in frontend works now

This commit is contained in:
Florian Zaruba 2017-05-11 18:18:13 +02:00
parent 742fb2b307
commit 5ec741da4c
6 changed files with 65 additions and 66 deletions

View file

@ -68,13 +68,15 @@ module btb #(
btb_n[$unsigned(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}} && ~branchpredict_i.is_taken) begin
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}}) begin
// we can safely decrease it
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
if (~branchpredict_i.is_taken)
btb_n[$unsigned(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}} && branchpredict_i.is_taken) begin
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}}) begin
// we can safely increase it
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
if (branchpredict_i.is_taken)
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
end else begin // otherwise we are not in any boundaries and can decrease or increase it
if (branchpredict_i.is_taken)
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
@ -89,8 +91,9 @@ module btb #(
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
// TODO: think about the reset value
btb_q <= '{default: 0};
// 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};
end else begin
// evict all entries
if (flush_i) begin

View file

@ -38,7 +38,7 @@ module if_stage (
input logic halt_if_i, // pipeline stall
// ctrl flow instruction in
input logic [63:0] fetch_addr_i,
input logic set_pc_i, // set new PC
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,
@ -170,24 +170,23 @@ module if_stage (
// We need to pass those registers on to ID in the case we've set
// a new branch target (or jump) and we got a valid instruction
always_comb begin
branch_valid_n = branch_valid_q;
// this is the latch case we keep the values
predict_address_n = predict_address_q;
predict_taken_n = predict_taken_q;
// we got a branch redirect from PCGEN
if (is_branch_i) begin
// set the registers to the correct address
branch_valid_n = 1'b1;
branch_valid_n = branch_valid_q;
// a new branch target has been set by PCGEN
// save this in the register stage
if (set_pc_i && is_branch_i) begin
predict_address_n = fetch_addr_i;
// whether we took the branch or not can be seen from the set PC
// nevertheless we also need to keep branches not taken
predict_taken_n = set_pc_i;
end
// we have a valid instruction and id excepted it so we consider all the
// branch information to be sampled correctly
if (if_valid && clear_instr_valid_i) begin
branch_valid_n = 1'b0;
branch_valid_n = is_branch_i;
end
if (if_valid) begin
branch_valid_n = is_branch_i;
end
end
// --------------------------------------------------------------
@ -209,38 +208,29 @@ module if_stage (
end
else
begin
if (flush_i) begin
// offset FSM state
offset_fsm_cs <= IDLE;
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0;
illegal_c_insn_id_o <= 1'b0;
is_compressed_id_o <= 1'b0;
pc_id_o <= '0;
ex_o <= '{default: 0};
branch_valid_q <= 1'b0;
predict_address_q <= 64'b0;
predict_taken_q <= 1'b0;
end else begin
offset_fsm_cs <= offset_fsm_ns;
branch_valid_q <= branch_valid_n;
predict_address_q <= predict_address_n;
predict_taken_q <= predict_taken_n;
branch_valid_q <= branch_valid_n;
if (if_valid) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
illegal_c_insn_id_o <= illegal_c_insn;
is_compressed_id_o <= instr_compressed_int;
pc_id_o <= pc_if_o;
ex_o.cause <= 64'b0; // TODO: Output exception
ex_o.tval <= 64'b0; // TODO: Output exception
ex_o.valid <= 1'b0; // TODO: Output exception
// in case of a flush simply say that the next instruction
// is not valid anymore
if (flush_i) begin
instr_valid_id_o <= 1'b0;
end else
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
illegal_c_insn_id_o <= illegal_c_insn;
is_compressed_id_o <= instr_compressed_int;
pc_id_o <= pc_if_o;
ex_o.cause <= 64'b0; // TODO: Output exception
ex_o.tval <= 64'b0; // TODO: Output exception
ex_o.valid <= 1'b0; // TODO: Output exception
end else if (clear_instr_valid_i) begin
instr_valid_id_o <= 1'b0;
instr_valid_id_o <= 1'b0;
end
end
end
end

View file

@ -170,7 +170,7 @@ module lsu #(
.INSTR_TLB_ENTRIES ( 16 ),
.DATA_TLB_ENTRIES ( 16 ),
.ASID_WIDTH ( ASID_WIDTH )
) i_mmu (
) mmu_i (
.lsu_req_i ( translation_req ),
.lsu_vaddr_i ( vaddr ),
.lsu_valid_o ( translation_valid ),

View file

@ -29,7 +29,7 @@ module pcgen (
// 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
output logic is_branch_o, // to check if we branchpredicted we need to save whether this was a branch or not
output logic is_branch_o, // to check if we branchpredicted we need to save whether this was a branch or not <- LOL
// global input
input logic [63:0] boot_addr_i,
// CSR input
@ -44,18 +44,36 @@ module pcgen (
logic is_branch;
logic is_branch_n, is_branch_q;
logic set_pc_n, set_pc_q;
// pc which is used to look up the prediction in the BTB
logic [63:0] predict_pc;
assign pc_if_o = npc_q;
assign set_pc_o = set_pc_q;
assign is_branch_o = is_branch_q;
// Predict PC source select
// the PC which we use for lookup in the BTB can come from two sources:
// 1. PC from if stage plus + 4
// 2. or PC which we just predicted + 4
always_comb begin : pc_btb_lookup
// Ad 2: From PC of previous cycle (which is now in IF)
if (set_pc_q) begin
predict_pc = npc_q;
// Ad 1:
// in the previous cycle we set the PC to npc_q
// calculate the plus one version
end else begin
predict_pc = {pc_if_i[62:2], 2'b0} + 64'h4;
end
end
btb #(
.NR_ENTRIES(64),
.BITS_SATURATION_COUNTER(2)
)
btb_i
(
.vpc_i ( pc_if_i ),
.vpc_i ( predict_pc ),
.branchpredict_i ( branchpredict_i ),
.is_branch_o ( is_branch ),
.predict_taken_o ( predict_taken ),
@ -79,7 +97,8 @@ module pcgen (
set_pc_n = 1'b0;
is_branch_n = is_branch;
// 4. Predict taken
if (predict_taken) begin
if (is_branch && predict_taken) begin
set_pc_n = 1'b1;
npc_n = branch_target_address;
end
// 1.Debug

View file

@ -61,16 +61,13 @@ module tlb #(
logic [8:0] vpn0, vpn1, vpn2;
logic [TLB_ENTRIES-1:0] lu_hit; // to replacement logic
logic [TLB_ENTRIES-1:0] replace_en; // replace the following entry, set by replacement strategy
// register signals
logic lu_access_q;
logic [63:0] lu_vaddr_q;
//-------------
// Translation
//-------------
always_comb begin : translation
vpn0 = lu_vaddr_q[20:12];
vpn1 = lu_vaddr_q[29:21];
vpn2 = lu_vaddr_q[38:30];
vpn0 = lu_vaddr_i[20:12];
vpn1 = lu_vaddr_i[29:21];
vpn2 = lu_vaddr_i[38:30];
// default assignment
lu_hit = '{default: 0};
@ -168,7 +165,7 @@ module tlb #(
// endcase
for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin
// we got a hit so update the pointer as it was least recently used
if (lu_hit[i] & lu_access_q) begin
if (lu_hit[i] & lu_access_i) begin
// Set the nodes to the values we would expect
for (int unsigned lvl = 0; lvl < $clog2(TLB_ENTRIES); lvl++) begin
automatic int unsigned idx_base = $unsigned((2**lvl)-1);
@ -225,16 +222,6 @@ module tlb #(
plru_tree_q <= plru_tree_n;
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
if(~rst_ni) begin
lu_access_q <= 1'b0;
lu_vaddr_q <= 64'b0;
end else begin
lu_access_q <= lu_access_i;
lu_vaddr_q <= lu_vaddr_i;
end
end
//--------------
// Sanity checks
//--------------

View file

@ -14,15 +14,15 @@
csrw mstatus, x7
add x9, x7, x8
csrr x1, mstatus
jal L1
nop
L0: jal L1
nop
nop
nop
nop
nop
nop
nop
L1: nop
L1: jal L0
nop
nop
addi x1, x0, 55