diff --git a/core/fetch.sv b/core/fetch.sv index 4dcd3ee..8e200b1 100755 --- a/core/fetch.sv +++ b/core/fetch.sv @@ -46,6 +46,7 @@ module fetch( ras_interface.fetch ras, //Instruction Metadata + output logic early_branch_flush, output logic [31:0] if_pc, output logic [31:0] fetch_instruction, @@ -53,7 +54,10 @@ module fetch( local_memory_interface.master instruction_bram, input logic icache_on, l1_arbiter_request_interface.master l1_request, - l1_arbiter_return_interface.master l1_response + l1_arbiter_return_interface.master l1_response, + + //Trace Interface + output logic tr_early_branch_correction ); localparam NUM_SUB_UNITS = USE_I_SCRATCH_MEM + USE_ICACHE; @@ -75,6 +79,7 @@ module fetch( logic address_valid; typedef struct packed{ + logic is_predicted_branch_or_jump; logic address_valid; logic mmu_fault; logic [NUM_SUB_UNITS_W-1:0] subunit_id; @@ -102,7 +107,7 @@ module fetch( //Implementation //////////////////////////////////////////////////// //Fetch PC - assign update_pc = new_mem_request | gc_fetch_flush; + assign update_pc = new_mem_request | gc_fetch_flush | early_branch_flush; always_ff @(posedge clk) begin if (rst) pc <= RESET_VEC; @@ -117,7 +122,7 @@ module fetch( next_pc = gc_fetch_pc; else if (branch_flush) next_pc = bp.branch_flush_pc; - else if (bp.use_prediction) + else if (bp.use_prediction & ~early_branch_flush) next_pc = bp.is_return ? ras.addr : bp.predicted_pc; else next_pc = pc_plus_4; @@ -127,7 +132,7 @@ module fetch( //hold the fetching of data from memory until the status of the //exception has been resolved always_ff @(posedge clk) begin - if (rst | gc_fetch_flush) + if (flush_or_rst) exception_pending <= 0; else if (tlb.is_fault | (new_mem_request & ~address_valid)) exception_pending <= 1; @@ -137,10 +142,10 @@ module fetch( assign bp.next_pc = next_pc; assign bp.if_pc = pc; - assign ras.pop = bp.use_prediction & bp.is_return & ~branch_flush & ~gc_fetch_pc_override & new_mem_request; - assign ras.push = bp.use_prediction & bp.is_call & ~branch_flush & ~gc_fetch_pc_override & new_mem_request; + assign ras.pop = bp.use_prediction & bp.is_return & ~branch_flush & ~gc_fetch_pc_override & new_mem_request & (~early_branch_flush); + assign ras.push = bp.use_prediction & bp.is_call & ~branch_flush & ~gc_fetch_pc_override & new_mem_request & (~early_branch_flush); assign ras.new_addr = pc_plus_4; - assign ras.branch_fetched = bp.use_prediction & bp.is_branch & new_mem_request; //flush not needed as FIFO resets inside of RAS + assign ras.branch_fetched = bp.use_prediction & bp.is_branch & new_mem_request & (~early_branch_flush); //flush not needed as FIFO resets inside of RAS //////////////////////////////////////////////////// //TLB @@ -157,9 +162,9 @@ module fetch( ////////////////////////////////////////////// //Issue Control Signals - assign flush_or_rst = (rst | gc_fetch_flush); + assign flush_or_rst = (rst | gc_fetch_flush | early_branch_flush); - assign new_mem_request = (~tlb_on | tlb.done) & pc_id_available & units_ready & ~gc_fetch_hold & ~exception_pending; + assign new_mem_request = (~tlb_on | tlb.done) & pc_id_available & units_ready & (~gc_fetch_hold) & (~exception_pending); assign pc_id_assigned = new_mem_request | tlb.is_fault; ////////////////////////////////////////////// @@ -173,6 +178,7 @@ module fetch( .one_hot (sub_unit_address_match), .int_out (fetch_attr_next.subunit_id) ); + assign fetch_attr_next.is_predicted_branch_or_jump = bp.use_prediction; assign fetch_attr_next.address_valid = address_valid; assign fetch_attr_next.mmu_fault = tlb.is_fault; @@ -231,12 +237,25 @@ module fetch( //////////////////////////////////////////////////// //Instruction metada updates + logic valid_fetch_result; + assign valid_fetch_result = fetch_attr_fifo.valid & fetch_attr.address_valid & (~fetch_attr.mmu_fault); + assign if_pc = pc; - assign fetch_instruction = unit_data_array[fetch_attr.subunit_id]; - assign fetch_complete = (|unit_data_valid) | (fetch_attr_fifo.valid & ~fetch_attr.address_valid);//allow instruction to propagate to decode if address is invalid - assign fetch_metadata.ok = fetch_attr.address_valid & ~fetch_attr.mmu_fault; + assign fetch_metadata.ok = valid_fetch_result; assign fetch_metadata.error_code = fetch_attr.mmu_fault ? FETCH_PAGE_FAULT : FETCH_ACCESS_FAULT; + assign fetch_instruction = unit_data_array[fetch_attr.subunit_id]; + assign fetch_complete = ((fetch_attr_fifo.valid & ~valid_fetch_result) | (|unit_data_valid) & (~early_branch_flush));//allow instruction to propagate to decode if address is invalid + + //////////////////////////////////////////////////// + //Branch Predictor correction + logic is_branch_or_jump; + assign is_branch_or_jump = fetch_instruction[6:2] inside {JAL_T, JALR_T, BRANCH_T}; + assign early_branch_flush = (valid_fetch_result & (|unit_data_valid)) & fetch_attr.is_predicted_branch_or_jump & (~is_branch_or_jump); + generate if (ENABLE_TRACE_INTERFACE) begin + assign tr_early_branch_correction = early_branch_flush; + end endgenerate + //////////////////////////////////////////////////// //End of Implementation //////////////////////////////////////////////////// diff --git a/core/instruction_metadata_and_id_management.sv b/core/instruction_metadata_and_id_management.sv index 032d9b9..85a37f8 100644 --- a/core/instruction_metadata_and_id_management.sv +++ b/core/instruction_metadata_and_id_management.sv @@ -39,6 +39,7 @@ module instruction_metadata_and_id_management input logic pc_id_assigned, output id_t fetch_id, + input logic early_branch_flush, input logic fetch_complete, input logic [31:0] fetch_instruction, input fetch_metadata_t fetch_metadata, @@ -176,8 +177,13 @@ module instruction_metadata_and_id_management //On a fetch buffer flush, the next ID is restored to the current decode ID. //This prevents a stall in the case where all IDs are either in-flight or //in the fetch buffer at the point of a fetch flush. + id_t next_pc_id_base; + id_t next_fetch_id_base; + assign next_pc_id_base = gc_fetch_flush ? decode_id : (early_branch_flush ? fetch_id : pc_id); + assign next_fetch_id_base = gc_fetch_flush ? decode_id : fetch_id; + assign pc_id_next = gc_init_clear ? clear_index : - ((gc_fetch_flush ? decode_id : pc_id) + LOG2_MAX_IDS'({pc_id_assigned & ~gc_fetch_flush})); + (next_pc_id_base + LOG2_MAX_IDS'({pc_id_assigned & ~gc_fetch_flush})); always_ff @ (posedge clk) begin if (rst) begin pc_id <= 0; @@ -185,8 +191,8 @@ module instruction_metadata_and_id_management decode_id <= 0; end else begin - pc_id <= (gc_fetch_flush ? decode_id : pc_id) + LOG2_MAX_IDS'({pc_id_assigned & ~gc_fetch_flush}); - fetch_id <= (gc_fetch_flush ? decode_id : fetch_id) + LOG2_MAX_IDS'({fetch_complete & ~gc_fetch_flush}); + pc_id <= next_pc_id_base + LOG2_MAX_IDS'({pc_id_assigned & (~gc_fetch_flush) & (~early_branch_flush)}); + fetch_id <= next_fetch_id_base + LOG2_MAX_IDS'({fetch_complete & ~gc_fetch_flush}); decode_id <= decode_id + LOG2_MAX_IDS'({decode_advance & ~gc_fetch_flush}); end end diff --git a/core/taiga.sv b/core/taiga.sv index b91fe76..721486c 100755 --- a/core/taiga.sv +++ b/core/taiga.sv @@ -94,6 +94,7 @@ module taiga ( id_t fetch_id; logic fetch_complete; logic [31:0] fetch_instruction; + logic early_branch_flush; fetch_metadata_t fetch_metadata; //Decode stage logic decode_advance; @@ -150,6 +151,7 @@ module taiga ( id_t id_for_rd [COMMIT_PORTS]; //Trace Interface Signals + logic tr_early_branch_correction; logic tr_operand_stall; logic tr_unit_stall; logic tr_no_id_stall; @@ -216,6 +218,7 @@ module taiga ( .if_pc (if_pc), .pc_id_assigned (pc_id_assigned), .fetch_id (fetch_id), + .early_branch_flush (early_branch_flush), .fetch_complete (fetch_complete), .fetch_instruction (fetch_instruction), .fetch_metadata (fetch_metadata), @@ -259,6 +262,7 @@ module taiga ( .fetch_metadata (fetch_metadata), .bp (bp), .ras (ras), + .early_branch_flush (early_branch_flush), .if_pc (if_pc), .fetch_instruction (fetch_instruction), .instruction_bram (instruction_bram), @@ -267,7 +271,8 @@ module taiga ( .tlb_on (tlb_on), .l1_request(l1_request[L1_ICACHE_ID]), .l1_response(l1_response[L1_ICACHE_ID]), - .exception(1'b0) + .exception(1'b0), + .tr_early_branch_correction (tr_early_branch_correction) ); branch_predictor bp_block ( @@ -291,7 +296,7 @@ module taiga ( tlb_lut_ram #(ITLB_WAYS, ITLB_DEPTH) i_tlb ( .clk (clk), .rst (rst), - .abort_request (gc_fetch_flush), + .abort_request (gc_fetch_flush | early_branch_flush), .gc_tlb_flush (gc_tlb_flush), .asid (asid), .tlb (itlb), @@ -556,6 +561,7 @@ module taiga ( //Trace Interface generate if (ENABLE_TRACE_INTERFACE) begin always_ff @(posedge clk) begin + tr.events.early_branch_correction <= tr_early_branch_correction; tr.events.operand_stall <= tr_operand_stall; tr.events.unit_stall <= tr_unit_stall; tr.events.no_id_stall <= tr_no_id_stall; diff --git a/core/taiga_types.sv b/core/taiga_types.sv index 0806c74..e1b154e 100755 --- a/core/taiga_types.sv +++ b/core/taiga_types.sv @@ -232,6 +232,9 @@ package taiga_types; } fifo_type_t; typedef struct packed { + //Fetch + logic early_branch_correction; + //Decode logic operand_stall; logic unit_stall; diff --git a/test_benches/verilator/TaigaTracer.h b/test_benches/verilator/TaigaTracer.h index c49d990..c51895d 100644 --- a/test_benches/verilator/TaigaTracer.h +++ b/test_benches/verilator/TaigaTracer.h @@ -39,6 +39,7 @@ template constexpr int arraySize(T(&)[N]) { return N; } static const char * const eventNames[] = { + "early_branch_correction", "operand_stall", "unit_stall", "no_id_stall",