From 5ec741da4cd7e898aa33907686e9a0611c50a43f Mon Sep 17 00:00:00 2001 From: Florian Zaruba Date: Thu, 11 May 2017 18:18:13 +0200 Subject: [PATCH] :bug: Branching in frontend works now --- src/btb.sv | 15 +++++++----- src/if_stage.sv | 62 +++++++++++++++++++++---------------------------- src/lsu.sv | 2 +- src/pcgen.sv | 25 +++++++++++++++++--- src/tlb.sv | 21 ++++------------- test/add_test.S | 6 ++--- 6 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/btb.sv b/src/btb.sv index 8df46cb06..0f669c611 100644 --- a/src/btb.sv +++ b/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 diff --git a/src/if_stage.sv b/src/if_stage.sv index 12e7d1ac6..14b05ef19 100644 --- a/src/if_stage.sv +++ b/src/if_stage.sv @@ -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 diff --git a/src/lsu.sv b/src/lsu.sv index 6ec80f70b..228c3c31b 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -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 ), diff --git a/src/pcgen.sv b/src/pcgen.sv index ac67543fc..71acd2349 100644 --- a/src/pcgen.sv +++ b/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 diff --git a/src/tlb.sv b/src/tlb.sv index 1bdc9bbf2..c464a9227 100644 --- a/src/tlb.sv +++ b/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 //-------------- diff --git a/test/add_test.S b/test/add_test.S index e90108cec..64c23bbcc 100755 --- a/test/add_test.S +++ b/test/add_test.S @@ -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 \ No newline at end of file