added invalid fetch propagation and dedicated commit port zero to the ALU

This commit is contained in:
Eric Matthews 2020-06-29 17:35:24 -07:00
parent a0d2ce867e
commit 11cd4151cc
5 changed files with 97 additions and 33 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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{