diff --git a/core/decode_and_issue.sv b/core/decode_and_issue.sv index 1b96ade..3867373 100755 --- a/core/decode_and_issue.sv +++ b/core/decode_and_issue.sv @@ -158,6 +158,7 @@ module decode_and_issue ( if (issue_stage_ready) begin issue.pc <= decode.pc; issue.instruction <= decode.instruction; + issue.addr_valid <= decode.addr_valid; issue.fn3 <= fn3; issue.opcode <= opcode; issue.rs_addr[RS1] <= rs1_addr; @@ -537,6 +538,11 @@ module decode_and_issue ( //////////////////////////////////////////////////// //Assertions + //TODO: convert into exception and expand support into all fetch stage exceptions + //If an invalid fetch address has reached the issue stage and has not been flushed as a branch, processor state is corrupted + invalid_fetch_address_assertion: + assert property (@(posedge clk) disable iff (rst) (issue.stage_valid & ~issue.addr_valid) |-> (gc_fetch_flush)) + else $error("invalid fetch address"); //////////////////////////////////////////////////// //Trace Interface diff --git a/core/fetch.sv b/core/fetch.sv index c5d474d..bab8f13 100755 --- a/core/fetch.sv +++ b/core/fetch.sv @@ -39,6 +39,7 @@ module fetch( input logic pc_id_available, output logic pc_id_assigned, output logic fetch_complete, + output logic fetch_address_valid, branch_predictor_interface.fetch bp, ras_interface.fetch ras, @@ -70,13 +71,19 @@ module fetch( logic [31:0] unit_data_array [NUM_SUB_UNITS-1:0]; logic units_ready; - logic units_data_valid; + + typedef struct packed{ + logic address_valid; + logic [NUM_SUB_UNITS_W-1:0] subunit_id; + } fetch_attributes_t; + fetch_attributes_t fetch_attr_next; + fetch_attributes_t fetch_attr; logic [31:0] next_pc; logic [31:0] pc; logic flush_or_rst; - fifo_interface #(.DATA_WIDTH(NUM_SUB_UNITS_W)) next_unit(); + fifo_interface #(.DATA_WIDTH($bits(fetch_attributes_t))) fetch_attr_fifo(); logic new_mem_request; @@ -137,19 +144,24 @@ module fetch( ////////////////////////////////////////////// //Subunit Tracking - assign next_unit.push = new_mem_request; - assign next_unit.potential_push = new_mem_request; - assign next_unit.pop = units_data_valid; - one_hot_to_integer #(NUM_SUB_UNITS) hit_way_conv (.*, .one_hot(sub_unit_address_match), .int_out(next_unit.data_in)); - taiga_fifo #(.DATA_WIDTH(NUM_SUB_UNITS_W), .FIFO_DEPTH(NEXT_ID_DEPTH)) - attributes_fifo (.fifo(next_unit), .rst(flush_or_rst), .*); + assign fetch_attr_fifo.push = new_mem_request; + assign fetch_attr_fifo.potential_push = new_mem_request; + assign fetch_attr_fifo.pop = fetch_complete; + one_hot_to_integer #(NUM_SUB_UNITS) hit_way_conv (.*, .one_hot(sub_unit_address_match), .int_out(fetch_attr_next.subunit_id)); + assign fetch_attr_next.address_valid = |sub_unit_address_match; + + assign fetch_attr_fifo.data_in = fetch_attr_next; + + taiga_fifo #(.DATA_WIDTH($bits(fetch_attributes_t)), .FIFO_DEPTH(NEXT_ID_DEPTH)) + attributes_fifo (.fifo(fetch_attr_fifo), .rst(flush_or_rst), .*); + + assign fetch_attr = fetch_attr_fifo.data_out; //////////////////////////////////////////////////// //Subunit Interfaces //In the case of a gc_fetch_flush, a request may already be in progress //for any sub unit. That request can either be completed or aborted. //In either case, data_valid must NOT be asserted. - logic cache_address_match; generate for (i = 0; i < NUM_SUB_UNITS; i++) begin assign unit_ready[i] = fetch_sub[i].ready; @@ -162,24 +174,30 @@ module fetch( end endgenerate assign units_ready = &unit_ready; - assign units_data_valid = |unit_data_valid; generate if (USE_I_SCRATCH_MEM) begin ibram i_bram (.*, .fetch_sub(fetch_sub[BRAM_ID])); - assign sub_unit_address_match[BRAM_ID] = USE_ICACHE ? ~cache_address_match : 1'b1; + assign sub_unit_address_match[BRAM_ID] = tlb.physical_address[31:32-SCRATCH_BIT_CHECK] == SCRATCH_ADDR_L[31:32-SCRATCH_BIT_CHECK]; end endgenerate generate if (USE_ICACHE) begin icache i_cache (.*, .fetch_sub(fetch_sub[ICACHE_ID])); - assign cache_address_match = tlb.physical_address[31:32-MEMORY_BIT_CHECK] == MEMORY_ADDR_L[31:32-MEMORY_BIT_CHECK]; - assign sub_unit_address_match[ICACHE_ID] = cache_address_match; + assign sub_unit_address_match[ICACHE_ID] = tlb.physical_address[31:32-MEMORY_BIT_CHECK] == MEMORY_ADDR_L[31:32-MEMORY_BIT_CHECK]; end endgenerate //////////////////////////////////////////////////// //Instruction metada updates assign if_pc = pc; - assign fetch_instruction = unit_data_array[next_unit.data_out]; - assign fetch_complete = units_data_valid; + 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_address_valid = fetch_attr.address_valid; -endmodule + //////////////////////////////////////////////////// + //End of Implementation + //////////////////////////////////////////////////// + + //////////////////////////////////////////////////// + //Assertions + +endmodule \ No newline at end of file diff --git a/core/instruction_metadata_and_id_management.sv b/core/instruction_metadata_and_id_management.sv index 2aaa7df..8d07d59 100644 --- a/core/instruction_metadata_and_id_management.sv +++ b/core/instruction_metadata_and_id_management.sv @@ -41,6 +41,7 @@ module instruction_metadata_and_id_management output id_t fetch_id, input logic fetch_complete, input logic [31:0] fetch_instruction, + input logic fetch_address_valid, //Decode ID output decode_packet_t decode, @@ -82,6 +83,9 @@ module instruction_metadata_and_id_management ////////////////////////////////////////// logic [31:0] pc_table [MAX_IDS]; logic [31:0] instruction_table [MAX_IDS]; + logic valid_fetch_addr_table [MAX_IDS]; + + logic [4:0] rd_addr_table [MAX_IDS]; logic [$bits(branch_metadata_t)-1:0] branch_metadata_table [MAX_IDS]; logic [31:0] rd_table [MAX_IDS]; @@ -135,6 +139,19 @@ module instruction_metadata_and_id_management instruction_table[fetch_id] <= fetch_instruction; end + //rd table + always_ff @ (posedge clk) begin + if (fetch_complete) + rd_addr_table[fetch_id] <= fetch_instruction[11:7]; + end + + //valid fetched address table + always_ff @ (posedge clk) begin + if (fetch_complete) + valid_fetch_addr_table[fetch_id] <= fetch_address_valid; + end + + //Operand inuse determination initial rd_to_id_table = '{default: 0}; always_ff @ (posedge clk) begin @@ -324,6 +341,7 @@ module instruction_metadata_and_id_management assign decode.valid = fetched_count[LOG2_MAX_IDS]; assign decode.pc = pc_table[decode_id]; assign decode.instruction = instruction_table[decode_id]; + assign decode.addr_valid = valid_fetch_addr_table[decode_id]; //Branch Predictor assign branch_metadata_ex = branch_metadata_table[branch_id]; @@ -332,14 +350,19 @@ module instruction_metadata_and_id_management always_comb begin for (int i = 0; i < REGFILE_READ_PORTS; i++) begin rs_id[i] = gc_init_clear ? clear_index : rd_to_id_table[issue.rs_addr[i]]; - rs_inuse[i] = (|issue.rs_addr[i]) & (issue.rs_addr[i] == instruction_table[rs_id[i]][11:7]);//11:7 is rd_addr + rs_inuse[i] = (|issue.rs_addr[i]) & (issue.rs_addr[i] == rd_addr_table[rs_id[i]]); end end //Writeback support + always_comb begin + retired_rd_addr[0] = issue.rd_addr; + for (int i = 1; i < COMMIT_PORTS; i++) begin + retired_rd_addr[i] = rd_addr_table[ids_retiring[i]]; + end + end always_comb begin for (int i = 0; i < COMMIT_PORTS; i++) begin - retired_rd_addr[i] = instruction_table[ids_retiring[i]][11:7]; id_for_rd[i] = rd_to_id_table[retired_rd_addr[i]]; end end diff --git a/core/register_file_and_writeback.sv b/core/register_file_and_writeback.sv index eb2409a..64b94f0 100755 --- a/core/register_file_and_writeback.sv +++ b/core/register_file_and_writeback.sv @@ -58,7 +58,8 @@ module register_file_and_writeback //aliases for write-back-interface signals id_t unit_instruction_id [NUM_WB_UNITS]; logic unit_done [NUM_WB_UNITS]; - logic [XLEN-1:0] unit_rd [NUM_WB_UNITS]; + typedef logic [XLEN-1:0] unit_rd_t [NUM_WB_UNITS]; + unit_rd_t unit_rd [COMMIT_PORTS]; //Per-ID muxes for commit buffer logic [$clog2(NUM_WB_UNITS)-1:0] retiring_unit_select [COMMIT_PORTS]; logic [31:0] retiring_data [COMMIT_PORTS]; @@ -66,17 +67,26 @@ module register_file_and_writeback typedef logic [31:0] rs_data_set_t [REGFILE_READ_PORTS]; rs_data_set_t rs_data_set [COMMIT_PORTS]; - genvar i; + genvar i, j; //////////////////////////////////////////////////// //Implementation //Re-assigning interface inputs to array types so that they can be dynamically indexed generate for (i=0; i< NUM_WB_UNITS; i++) begin : wb_interfaces_to_arrays_g assign unit_instruction_id[i] = unit_wb[i].id; assign unit_done[i] = unit_wb[i].done; - assign unit_rd[i] = unit_wb[i].rd; assign unit_wb[i].ack = unit_ack[i]; end endgenerate + //As units are selected for commit ports based on their unit ID, + //for each additional commit port one unit can be skipped for the commit mux + generate for (i = 0; i < COMMIT_PORTS; i++) begin + initial unit_rd[i] = '{default: '0}; + for (j=i; j< NUM_WB_UNITS; j++) begin + assign unit_rd[i][j] = unit_wb[j].rd; + end + end endgenerate + + //////////////////////////////////////////////////// //Unit select for register file //Iterating through all commit ports: @@ -86,7 +96,12 @@ module register_file_and_writeback unit_ack = '{default: 0}; retired = '{default: 0}; - for (int i = 0; i < COMMIT_PORTS; i++) begin + unit_ack[0] = alu_issued; + retired[0] = alu_issued; + ids_retiring[0] = unit_instruction_id[ALU_UNIT_WB_ID]; + retiring_data[0] = unit_rd[0][ALU_UNIT_WB_ID]; + + for (int i = 1; i < COMMIT_PORTS; i++) begin retiring_unit_select[i] = WB_UNITS_WIDTH'(i); for (int j = i; j < NUM_WB_UNITS; j++) begin //Unit index i will always be handled by commit port i or lower, so can be skipped when checking higher commit port indicies if (unit_done[j] & ~unit_ack[j] & ~retired[i]) begin @@ -98,11 +113,11 @@ module register_file_and_writeback //ID and data muxes ids_retiring[i] = unit_instruction_id[retiring_unit_select[i]]; - retiring_data[i] = unit_rd[retiring_unit_select[i]]; + retiring_data[i] = unit_rd[i][retiring_unit_select[i]]; end //Late cycle abort for when ALU is not issued to - alu_selected = (retiring_unit_select[0] == ALU_UNIT_WB_ID); - if (alu_selected) retired[0] &= alu_issued; + //alu_selected = (retiring_unit_select[0] == ALU_UNIT_WB_ID); + //if (alu_selected) retired[0] &= alu_issued; end //////////////////////////////////////////////////// @@ -129,9 +144,9 @@ module register_file_and_writeback //the most recently issued write to any given register will be committed logic update_lvt [COMMIT_PORTS]; always_comb begin - update_lvt[0] = retired[0] & (alu_selected ? alu_issued : (id_for_rd[0] == ids_retiring[0])); + update_lvt[0] = retired[0];// & (alu_selected ? alu_issued : (id_for_rd[0] == ids_retiring[0])); for (int i = 1; i < COMMIT_PORTS; i++) - update_lvt[i] = retired[i] & (id_for_rd[i] == ids_retiring[i]) & ~(alu_selected & retired[0] & retired_rd_addr[0] == retired_rd_addr[i]); + update_lvt[i] = retired[i] & (id_for_rd[i] == ids_retiring[i]) & ~(retired[0] & retired_rd_addr[0] == retired_rd_addr[i]); end regfile_bank_sel regfile_lvt ( @@ -152,29 +167,29 @@ module register_file_and_writeback //////////////////////////////////////////////////// //Store Forwarding Support - logic [31:0] commit_regs [COMMIT_PORTS]; + logic [31:0] commit_regs [COMMIT_PORTS-1]; logic [$clog2(COMMIT_PORTS)-1:0] store_reg_sel; logic [$clog2(COMMIT_PORTS)-1:0] store_reg_sel_r; - generate for (i = 0; i < COMMIT_PORTS; i++) begin + generate for (i = 1; i < COMMIT_PORTS; i++) begin always_ff @ (posedge clk) begin if (wb_store.possibly_waiting & retired[i] & (wb_store.id_needed == ids_retiring[i])) - commit_regs[i] <= retiring_data[i]; + commit_regs[i-1] <= retiring_data[i]; end end endgenerate logic [COMMIT_PORTS-1:0] store_id_match; always_comb begin store_id_match = 0; - for (int i = 0; i < COMMIT_PORTS; i++) begin + for (int i = 1; i < COMMIT_PORTS; i++) begin if (wb_store.waiting & retired[i] & (wb_store.id_needed == ids_retiring[i])) store_id_match[i] = 1; end store_reg_sel = 0; - for (int i = 1; i < COMMIT_PORTS; i++) begin + for (int i = 2; i < COMMIT_PORTS; i++) begin if (retired[i] & (wb_store.id_needed == ids_retiring[i])) - store_reg_sel = ($clog2(COMMIT_PORTS))'(i); + store_reg_sel = ($clog2(COMMIT_PORTS))'(i-1); end end diff --git a/core/taiga_types.sv b/core/taiga_types.sv index 4a32964..8599661 100755 --- a/core/taiga_types.sv +++ b/core/taiga_types.sv @@ -78,6 +78,7 @@ package taiga_types; logic [31:0] pc; logic [31:0] instruction; logic valid; + logic addr_valid; } decode_packet_t; typedef struct packed{ @@ -94,6 +95,7 @@ package taiga_types; logic uses_rd; id_t id; logic stage_valid; + logic addr_valid; } issue_packet_t; typedef struct packed{