mirror of
https://github.com/openhwgroup/cva5.git
synced 2025-04-22 13:07:33 -04:00
added invalid fetch propagation and dedicated commit port zero to the ALU
This commit is contained in:
parent
a0d2ce867e
commit
11cd4151cc
5 changed files with 97 additions and 33 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue