mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 21:57:11 -04:00
🐛 Branching in frontend works now
This commit is contained in:
parent
742fb2b307
commit
5ec741da4c
6 changed files with 65 additions and 66 deletions
15
src/btb.sv
15
src/btb.sv
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ),
|
||||
|
|
25
src/pcgen.sv
25
src/pcgen.sv
|
@ -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
|
||||
|
|
21
src/tlb.sv
21
src/tlb.sv
|
@ -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
|
||||
//--------------
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue