seperated load and store queues

This commit is contained in:
Eric Matthews 2020-09-16 15:33:24 -07:00
parent 19c7e419d3
commit 78155870c1
12 changed files with 555 additions and 185 deletions

50
core/addr_hash.sv Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright © 2020 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Initial code developed under the supervision of Dr. Lesley Shannon,
* Reconfigurable Computing Lab, Simon Fraser University.
*
* Author(s):
* Eric Matthews <ematthew@sfu.ca>
*/
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
module addr_hash (
input logic clk,
input logic rst,
input logic [31:0] addr,
output addr_hash_t addr_hash
);
////////////////////////////////////////////////////
//Implementation
//Xor addr in groups of 4-bits, truncating to the virtual/physical address invariant bits (11:0)
//lower two bits are not used due to complications in determining overlap between byte
//halfword and word operations.
assign addr_hash[0] = addr[2];// ^ addr[6] ^ addr[10];
//assign addr_hash[1] = addr[3] ^ addr[7] ^ addr[11];
//assign addr_hash[2] = addr[4] ^ addr[8];
//assign addr_hash[3] = addr[5] ^ addr[9];
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//Assertions
endmodule

View file

@ -231,12 +231,12 @@ module gc_unit(
PRE_CLEAR_STATE : next_state = INIT_CLEAR_STATE;
INIT_CLEAR_STATE : if (init_clear_done) next_state = IDLE_STATE;
IDLE_STATE : begin
if (ls_exception.valid | potential_branch_exception) begin
if (ls_exception.valid | potential_branch_exception | system_op_or_exception_complete) begin
next_state = IQ_DRAIN;
end
end
TLB_CLEAR_STATE : if (tlb_clear_done) next_state = IDLE_STATE;
IQ_DRAIN : next_state = IDLE_STATE;
IQ_DRAIN : if (ls_is_idle) next_state = IDLE_STATE;
default : next_state = RST_STATE;
endcase
end

70
core/load_queue.sv Normal file
View file

@ -0,0 +1,70 @@
/*
* Copyright © 2020 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Initial code developed under the supervision of Dr. Lesley Shannon,
* Reconfigurable Computing Lab, Simon Fraser University.
*
* Author(s):
* Eric Matthews <ematthew@sfu.ca>
*/
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
module load_queue # (
parameter SQ_DEPTH = 4
)
(
input logic clk,
input logic rst,
load_store_queue_interface.queue lsq,
output lq_entry_t lq_entry,
input logic [SQ_DEPTH-1:0] potential_store_conflicts,
input load_ack,
output lq_output_valid
);
localparam LQ_WIDTH = $bits(lq_entry_t);
fifo_interface #(.DATA_WIDTH(LQ_WIDTH)) load_fifo ();
////////////////////////////////////////////////////
//Implementation
taiga_fifo #(.DATA_WIDTH(LQ_WIDTH), .FIFO_DEPTH(MAX_IDS)) load_queue_fifo (
.clk(clk),
.rst(rst),
.fifo(load_fifo)
);
//FIFO control signals
assign load_fifo.push = lsq.new_issue & lsq.load;
assign load_fifo.potential_push = lsq.possible_issue;
assign load_fifo.pop = load_ack;
assign lq_output_valid = load_fifo.valid;
//FIFO data ports
assign load_fifo.data_in = {lsq.addr, lsq.fn3, lsq.id, potential_store_conflicts};
assign lq_entry = load_fifo.data_out;
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//Assertions
endmodule

View file

@ -33,154 +33,97 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
input logic gc_issue_flush,
load_store_queue_interface.queue lsq,
writeback_store_interface.ls wb_store,
//Writeback snooping
input wb_packet_t wb_snoop,
output logic ready_for_forwarded_store
//Writeback release
input id_t ids_released [COMMIT_PORTS],
input logic wb_released [COMMIT_PORTS],
output logic tr_possible_load_conflict_delay
);
localparam SQ_DEPTH = 4;
addr_hash_t addr_hash;
logic [MAX_IDS-1:0] valid;
id_t oldest_id;
lq_entry_t lq_entry;
logic [SQ_DEPTH-1:0] potential_store_conflicts;
logic load_ack;
logic lq_output_valid;
typedef struct packed {
logic [31:0] addr;
logic load;
logic store;
logic [3:0] be;
logic [2:0] fn3;
logic [31:0] data_in;
id_t id;
logic forwarded_store;
id_t data_id;
} lsq_entry_t;
logic sq_full;
logic sq_empty;
sq_entry_t sq_entry;
logic [31:0] sq_data;
logic store_conflict;
logic store_ack;
logic sq_output_valid;
lsq_entry_t new_lsq_entry;
logic [$bits(lsq_entry_t)-1:0] lsq_entries [MAX_IDS];
lsq_entry_t oldest_lsq_entry;
fifo_interface #(.DATA_WIDTH($bits(id_t))) oldest_fifo ();
////////////////////////////////////////////////////
//Implementation
//Can always buffer new requests
assign lsq.ready = 1;
//Can accept requests so long as store queue is not needed or is not full
assign lsq.ready = lsq.load | (~sq_full);
//FIFO to store ordering of IDs
taiga_fifo #(.DATA_WIDTH($bits(id_t)), .FIFO_DEPTH(MAX_IDS)) oldest_id_fifo (
.clk, .rst(rst | gc_issue_flush),
.fifo(oldest_fifo)
//Address hash for load-store collision checking
addr_hash lsq_addr_hash (
.clk (clk),
.rst (rst | gc_issue_flush),
.addr (lsq.addr),
.addr_hash (addr_hash)
);
assign oldest_fifo.data_in = lsq.id;
assign oldest_fifo.push = lsq.new_issue;
assign oldest_fifo.potential_push = lsq.possible_issue;
assign oldest_fifo.pop = lsq.accepted;
assign oldest_id = oldest_fifo.data_out;
assign lsq.empty = ~oldest_fifo.valid;
////////////////////////////////////////////////////
//Request attributes and input data (LUTRAMs)
always_comb begin
new_lsq_entry.addr = lsq.addr;
new_lsq_entry.load = lsq.load;
new_lsq_entry.store = lsq.store;
new_lsq_entry.be = lsq.be;
new_lsq_entry.fn3 = lsq.fn3;
new_lsq_entry.data_in = lsq.data_in;
new_lsq_entry.id = lsq.id;
new_lsq_entry.forwarded_store = lsq.forwarded_store;
new_lsq_entry.data_id = lsq.data_id;
end
always_ff @ (posedge clk) begin
if (lsq.possible_issue)
lsq_entries[lsq.id] <= new_lsq_entry;
end
////////////////////////////////////////////////////
//ID status registers
//for whether an ID is valid
// logic [MAX_INFLIGHT_COUNT-1:0] issuing_one_hot;
// logic [MAX_INFLIGHT_COUNT-1:0] new_id_one_hot;
// always_comb begin
// new_id_one_hot = 0;
// new_id_one_hot[lsq.id] = lsq.new_issue;
// issuing_one_hot = 0;
// issuing_one_hot[oldest_id] = lsq.accepted;
// end
// set_clr_reg_with_rst #(.SET_OVER_CLR(0), .WIDTH(MAX_INFLIGHT_COUNT), .RST_VALUE('0)) valid_m (
// .clk, .rst,
// .set(new_id_one_hot),
// .clr(issuing_one_hot),
// .result(valid)
// );
////////////////////////////////////////////////////
//Store Forwarding Support
//Only a single store can be forwarded at any given time
//The needed result is registered at the writeback stage when the
//needed ID is retired.
logic possible_new_forwarded_store;//To help shorten logic path for registering results in the writeback stage
logic new_forwarded_store;
logic forwarded_store_complete;
id_t needed_id_r;
logic waiting_r;
assign possible_new_forwarded_store = lsq.possible_issue & lsq.forwarded_store;
assign new_forwarded_store = lsq.new_issue & lsq.forwarded_store;
assign forwarded_store_complete = lsq.accepted & oldest_lsq_entry.forwarded_store;
always_ff @ (posedge clk) begin
if (rst)
waiting_r <= 0;
else
waiting_r <= new_forwarded_store | (waiting_r & ~wb_store.id_done);
end
assign wb_store.waiting = new_forwarded_store | waiting_r;
assign wb_store.possibly_waiting = possible_new_forwarded_store | waiting_r;
assign wb_store.ack = forwarded_store_complete;
assign ready_for_forwarded_store = ~(waiting_r | wb_store.id_done);
always_ff @ (posedge clk) begin
if (new_forwarded_store)
needed_id_r <= lsq.data_id;
end
assign wb_store.id_needed = waiting_r ? needed_id_r : lsq.data_id;
load_queue #(.SQ_DEPTH(SQ_DEPTH)) lq_block (
.clk (clk),
.rst (rst | gc_issue_flush),
.lsq (lsq),
.lq_entry (lq_entry),
.potential_store_conflicts (potential_store_conflicts),
.load_ack (load_ack),
.lq_output_valid (lq_output_valid)
);
store_queue #(.DEPTH(SQ_DEPTH)) sq_block (
.clk (clk),
.rst (rst | gc_issue_flush),
.lsq (lsq),
.sq_empty (sq_empty),
.sq_full (sq_full),
.addr_hash (addr_hash),
.potential_store_conflicts (potential_store_conflicts),
.load_issued (load_ack),
.prev_store_conflicts (lq_entry.potential_store_conflicts),
.store_conflict (store_conflict),
.sq_entry (sq_entry),
.sq_data (sq_data),
.wb_snoop (wb_snoop),
.ids_released (ids_released),
.wb_released (wb_released),
.store_ack (store_ack),
.sq_output_valid (sq_output_valid)
);
////////////////////////////////////////////////////
//Output
logic [31:0] data_for_alignment;
logic load_selected;
assign oldest_lsq_entry = lsq_entries[oldest_id];
assign lsq.transaction_ready = oldest_fifo.valid & (~oldest_lsq_entry.forwarded_store | wb_store.id_done);
//Priority is for loads over stores.
//A store will be selected only if either no loads are ready, OR if the store queue is full and a store is ready
assign load_selected = lq_output_valid & ~store_conflict & ~(sq_full & sq_output_valid);
always_comb begin
lsq.transaction_out.addr = oldest_lsq_entry.addr;
lsq.transaction_out.load = oldest_lsq_entry.load;
lsq.transaction_out.store = oldest_lsq_entry.store;
lsq.transaction_out.be = oldest_lsq_entry.be;
lsq.transaction_out.fn3 = oldest_lsq_entry.fn3;
lsq.transaction_out.id = oldest_id;
assign lsq.transaction_ready = (lq_output_valid & ~store_conflict) | sq_output_valid;
assign load_ack = lsq.accepted & load_selected;
assign store_ack = lsq.accepted & ~load_selected;
data_for_alignment = oldest_lsq_entry.forwarded_store ? wb_store.data : oldest_lsq_entry.data_in;
//Input: ABCD
//Assuming aligned requests,
//Possible byte selections: (A/C/D, B/D, C/D, D)
lsq.transaction_out.data_in[7:0] = data_for_alignment[7:0];
lsq.transaction_out.data_in[15:8] = (lsq.transaction_out.addr[1:0] == 2'b01) ? data_for_alignment[7:0] : data_for_alignment[15:8];
lsq.transaction_out.data_in[23:16] = (lsq.transaction_out.addr[1:0] == 2'b10) ? data_for_alignment[7:0] : data_for_alignment[23:16];
case(lsq.transaction_out.addr[1:0])
2'b10 : lsq.transaction_out.data_in[31:24] = data_for_alignment[15:8];
2'b11 : lsq.transaction_out.data_in[31:24] = data_for_alignment[7:0];
default : lsq.transaction_out.data_in[31:24] = data_for_alignment[31:24];
endcase
end
assign lsq.transaction_out.addr = load_selected ? lq_entry.addr : sq_entry.addr;
assign lsq.transaction_out.load = load_selected;
assign lsq.transaction_out.store = ~load_selected;
assign lsq.transaction_out.be = load_selected ? '0 : sq_entry.be;
assign lsq.transaction_out.fn3 = load_selected ? lq_entry.fn3 : sq_entry.fn3;
assign lsq.transaction_out.data_in = sq_data;
assign lsq.transaction_out.id = lq_entry.id;
assign lsq.empty = ~lq_output_valid & sq_empty;
////////////////////////////////////////////////////
//End of Implementation
@ -189,4 +132,11 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
////////////////////////////////////////////////////
//Assertions
////////////////////////////////////////////////////
//Trace Interface
generate if (ENABLE_TRACE_INTERFACE) begin
assign tr_possible_load_conflict_delay = lq_output_valid & store_conflict;
end
endgenerate
endmodule

View file

@ -54,7 +54,7 @@ module load_store_unit (
output id_t store_id,
//Writeback-Store Interface
writeback_store_interface.ls wb_store,
input wb_packet_t wb_snoop,
//CSR support
input logic[31:0] csr_rd,
@ -65,7 +65,9 @@ module load_store_unit (
output exception_packet_t ls_exception,
output logic ls_exception_is_store,
unit_writeback_interface.unit wb
unit_writeback_interface.unit wb,
output logic tr_load_conflict_delay
);
localparam NUM_SUB_UNITS = USE_D_SCRATCH_MEM+USE_BUS+USE_DCACHE;
@ -119,10 +121,8 @@ module load_store_unit (
fifo_interface #(.DATA_WIDTH($bits(load_attributes_t))) load_attributes();
load_store_queue_interface lsq();
logic tr_possible_load_conflict_delay;
logic [31:0] compare_addr;
logic address_conflict;
logic ready_for_forwarded_store;
////////////////////////////////////////////////////
//Implementation
////////////////////////////////////////////////////
@ -173,7 +173,6 @@ endgenerate
end
default : be = '1;
endcase
be &= {4{~ls_inputs.load}};
end
////////////////////////////////////////////////////
@ -191,15 +190,16 @@ endgenerate
assign lsq.possible_issue = issue.possible_issue;
assign lsq.new_issue = issue.new_request & ~unaligned_addr & (~tlb_on | tlb.done);
logic [MAX_IDS-1:0] wb_hold_for_store_ids;
load_store_queue lsq_block (
.clk (clk),
.rst (rst),
.gc_fetch_flush (gc_fetch_flush),
.gc_issue_flush (gc_issue_flush),
.lsq (lsq),
.wb_store (wb_store),
.ready_for_forwarded_store (ready_for_forwarded_store)
.wb_snoop (wb_snoop),
.ids_released ('{LOG2_MAX_IDS'(1'b0), store_id}),
.wb_released ('{1'b0, store_complete}),
.tr_possible_load_conflict_delay (tr_possible_load_conflict_delay)
);
assign shared_inputs = lsq.transaction_out;
@ -207,9 +207,13 @@ endgenerate
////////////////////////////////////////////////////
//ID Management
assign store_complete = lsq.accepted & lsq.transaction_out.store;
assign store_id = lsq.transaction_out.id;
always_ff @ (posedge clk) begin
store_id <= lsq.id;
if (rst)
store_complete <= 0;
else
store_complete <= lsq.new_issue & lsq.store;
end
////////////////////////////////////////////////////
//Unit tracking
assign current_unit = sub_unit_address_match;
@ -238,7 +242,7 @@ endgenerate
assign ready_for_issue_from_lsq = units_ready & (~unit_switch_stall);
assign issue.ready = (~tlb_on | tlb.ready) & (ls_inputs.forwarded_store ? lsq.ready & ready_for_forwarded_store : lsq.ready);
assign issue.ready = (~tlb_on | tlb.ready) & lsq.ready;
assign issue_request = lsq.transaction_ready & ready_for_issue_from_lsq;
////////////////////////////////////////////////////
@ -402,4 +406,11 @@ endgenerate
else $error("invalid L/S address");
`endif
////////////////////////////////////////////////////
//Trace Interface
generate if (ENABLE_TRACE_INTERFACE) begin
assign tr_load_conflict_delay = tr_possible_load_conflict_delay & ready_for_issue_from_lsq;
end
endgenerate
endmodule

View file

@ -39,7 +39,7 @@ module register_file_and_writeback
input id_t id_for_rd [COMMIT_PORTS],
//Writeback
unit_writeback_interface.wb unit_wb[NUM_WB_UNITS],
writeback_store_interface.wb wb_store,
output wb_packet_t wb_snoop,
//Trace signals
output logic tr_rs1_forwarding_needed,
@ -167,46 +167,16 @@ module register_file_and_writeback
////////////////////////////////////////////////////
//Store Forwarding Support
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 = 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-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 = 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 = 2; i < COMMIT_PORTS; i++) begin
if (retired[i] & (wb_store.id_needed == ids_retiring[i]))
store_reg_sel = ($clog2(COMMIT_PORTS))'(i-1);
end
end
always_ff @ (posedge clk) begin
if (|store_id_match)
store_reg_sel_r <= store_reg_sel;
if (rst)
wb_snoop.valid <= 0;
else
wb_snoop.valid <= retired[1];
end
always_ff @ (posedge clk) begin
if (rst | wb_store.ack)
wb_store.id_done <= 0;
else if (|store_id_match)
wb_store.id_done <= 1;
wb_snoop.data <= retiring_data[1];
wb_snoop.id <= ids_retiring[1];
end
assign wb_store.data = commit_regs[store_reg_sel_r];
////////////////////////////////////////////////////
//End of Implementation

284
core/store_queue.sv Normal file
View file

@ -0,0 +1,284 @@
/*
* Copyright © 2020 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Initial code developed under the supervision of Dr. Lesley Shannon,
* Reconfigurable Computing Lab, Simon Fraser University.
*
* Author(s):
* Eric Matthews <ematthew@sfu.ca>
*/
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
module store_queue # (
parameter DEPTH = 4
)
(
input logic clk,
input logic rst,
//Queue status
output logic sq_empty,
output logic sq_full,
//Request interface
load_store_queue_interface.queue lsq,
//Address hash (shared by loads and stores)
input addr_hash_t addr_hash,
//hash check on adding a load to the queue
output logic [DEPTH-1:0] potential_store_conflicts,
//Load issue collision check
input logic load_issued,
input logic [DEPTH-1:0] prev_store_conflicts,
output logic store_conflict,
//Writeback snooping
input wb_packet_t wb_snoop,
//Writeback release
input id_t ids_released [COMMIT_PORTS],
input wb_released [COMMIT_PORTS],
//lsq output
output sq_entry_t sq_entry,
output logic [31:0] sq_data,
//lsq request handling
output logic sq_output_valid,
input logic store_ack
);
localparam LOG2_DEPTH = $clog2(DEPTH);
typedef logic [LOG2_MAX_IDS-1:0] load_check_count_t;
//Register-based memory blocks
logic [DEPTH-1:0] valid;
addr_hash_t [DEPTH-1:0] hashes;
logic [DEPTH-1:0] released;
logic [DEPTH-1:0] waiting_for_data;
id_t [DEPTH-1:0] id_needed;
id_t [DEPTH-1:0] ids;
load_check_count_t [DEPTH-1:0] load_check_count;
logic [31:0] store_data [DEPTH];
//LUTRAM-based memory blocks
logic [$bits(sq_entry_t)-1:0] store_attr [DEPTH];
load_check_count_t [DEPTH-1:0] load_check_count_next;
logic [LOG2_DEPTH-1:0] sq_index;
logic [LOG2_DEPTH-1:0] sq_oldest;
logic [DEPTH-1:0] sq_index_one_hot;
logic [DEPTH-1:0] sq_oldest_one_hot;
logic [DEPTH-1:0] new_request_one_hot;
logic [DEPTH-1:0] issued_one_hot;
logic new_sq_request;
logic new_load_request;
logic [DEPTH-1:0] wb_id_match;
////////////////////////////////////////////////////
//Implementation
assign new_sq_request = lsq.new_issue & lsq.store;
assign new_load_request = lsq.new_issue & ~lsq.store;
always_ff @ (posedge clk) begin
if (rst)
sq_index <= 0;
else
sq_index <= sq_index + LOG2_DEPTH'(new_sq_request);
end
always_ff @ (posedge clk) begin
if (rst)
sq_oldest <= 0;
else
sq_oldest <= sq_oldest + LOG2_DEPTH'(store_ack);
end
always_comb begin
sq_index_one_hot = 0;
sq_index_one_hot[sq_index] = 1;
sq_oldest_one_hot = 0;
sq_oldest_one_hot[sq_oldest] = 1;
new_request_one_hot = sq_index_one_hot & {DEPTH{new_sq_request}};
issued_one_hot = sq_oldest_one_hot & {DEPTH{store_ack}};
end
always_ff @ (posedge clk) begin
if (rst)
valid <= '0;
else
valid <= (valid | new_request_one_hot) & ~issued_one_hot;
end
assign sq_empty = ~|valid;
assign sq_full = valid[sq_index] | (|load_check_count[sq_index]);//If next index is valid, or still has a load that must be cleared first
//Attributes LUTRAM
always_ff @ (posedge clk) begin
if (new_sq_request)
store_attr[sq_index] <= {lsq.addr, lsq.be, lsq.fn3};
end
//Hash mem
always_ff @ (posedge clk) begin
if (new_sq_request)
hashes[sq_index] <= addr_hash;
end
//Keep count of the number of pending loads that might need a store result
//Mask out any store completing on this cycle
logic [DEPTH-1:0] new_load_waiting;
logic [DEPTH-1:0] waiting_load_completed;
always_comb begin
for (int i = 0; i < DEPTH; i++) begin
potential_store_conflicts[i] = (valid[i] & ~issued_one_hot[i]) & (addr_hash == hashes[i]);
new_load_waiting[i] = potential_store_conflicts[i] & new_load_request;
waiting_load_completed[i] = prev_store_conflicts[i] & load_issued;
load_check_count_next[i] =
load_check_count[i]
+ LOG2_MAX_IDS'(new_load_waiting[i])
- LOG2_MAX_IDS'(waiting_load_completed[i]);
end
end
always_ff @ (posedge clk) begin
if (rst)
load_check_count <= '0;
else
load_check_count <= load_check_count_next;
end
//If a potential blocking store has not been issued yet, the load is blocked until the store(s) complete
assign store_conflict = |(prev_store_conflicts & valid);
////////////////////////////////////////////////////
//ID Handling
//ID mem
always_ff @ (posedge clk) begin
if (new_sq_request)
ids[sq_index] <= lsq.id;
end
//waiting on ID mem
always_ff @ (posedge clk) begin
if (new_sq_request)
id_needed[sq_index] <= lsq.data_id;
end
always_comb begin
for (int i = 0; i < DEPTH; i++) begin
wb_id_match[i] = (wb_snoop.id == id_needed[i]);
end
end
//Store forwarding support
//New request takes precedence over a wb_id_match
always_ff @ (posedge clk) begin
if (rst)
waiting_for_data <= '0;
else
waiting_for_data <= (waiting_for_data & ~(wb_id_match & {DEPTH{wb_snoop.valid}})) | (new_request_one_hot & {DEPTH{lsq.forwarded_store}});
end
////////////////////////////////////////////////////
//Release Handling
//Can be released on the same cycle the store arrives at the store queue
logic [DEPTH-1:0] newly_released;
always_comb begin
for (int i = 0; i < DEPTH; i++) begin
for (int j = 0; j < COMMIT_PORTS; j++) begin
newly_released[i] = (ids[i] == ids_released[j]) & wb_released[j];
end
end
end
always_ff @ (posedge clk) begin
if (rst)
released <= '0;
else
released <= (released & ~new_request_one_hot) | newly_released;
end
////////////////////////////////////////////////////
//Store Data
logic store_we [DEPTH];
logic [31:0] new_store_data [DEPTH];
always_comb begin
for (int i = 0; i < DEPTH; i++) begin
store_we[i] = (wb_id_match[i] & wb_snoop.valid & waiting_for_data[i]) | (new_request_one_hot[i] & ~lsq.forwarded_store);
end
end
always_comb begin
for (int i = 0; i < DEPTH; i++) begin
new_store_data[i] = (wb_id_match[i] & wb_snoop.valid & waiting_for_data[i]) ? wb_snoop.data : lsq.data_in;
end
end
always_ff @ (posedge clk) begin
for (int i = 0; i < DEPTH; i++) begin
if (store_we[i])
store_data[i] <= new_store_data[i];
end
end
////////////////////////////////////////////////////
//Store Transaction Outputs
logic [31:0] data_for_alignment;
sq_entry_t output_attr;
assign sq_output_valid = valid[sq_oldest] & released[sq_oldest] & ~waiting_for_data[sq_oldest];
assign output_attr = store_attr[sq_oldest];
assign sq_entry.addr = output_attr.addr;
assign sq_entry.be = output_attr.be;
assign sq_entry.fn3 = output_attr.fn3;
always_comb begin
//Input: ABCD
//Assuming aligned requests,
//Possible byte selections: (A/C/D, B/D, C/D, D)
data_for_alignment = store_data[sq_oldest];
sq_data[7:0] = data_for_alignment[7:0];
sq_data[15:8] = (sq_entry.addr[1:0] == 2'b01) ? data_for_alignment[7:0] : data_for_alignment[15:8];
sq_data[23:16] = (sq_entry.addr[1:0] == 2'b10) ? data_for_alignment[7:0] : data_for_alignment[23:16];
case(sq_entry.addr[1:0])
2'b10 : sq_data[31:24] = data_for_alignment[15:8];
2'b11 : sq_data[31:24] = data_for_alignment[7:0];
default : sq_data[31:24] = data_for_alignment[31:24];
endcase
end
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//Assertions
endmodule

View file

@ -143,7 +143,7 @@ module taiga (
logic gc_flush_required;
//LS
writeback_store_interface wb_store();
wb_packet_t wb_snoop;
//WB
id_t ids_retiring [COMMIT_PORTS];
@ -180,6 +180,8 @@ module taiga (
logic tr_return_correct;
logic tr_return_misspredict;
logic tr_load_conflict_delay;
logic tr_rs1_forwarding_needed;
logic tr_rs2_forwarding_needed;
logic tr_rs1_and_rs2_forwarding_needed;
@ -386,7 +388,7 @@ module taiga (
.retired_rd_addr (retired_rd_addr),
.id_for_rd (id_for_rd),
.unit_wb (unit_wb),
.wb_store (wb_store),
.wb_snoop (wb_snoop),
.tr_rs1_forwarding_needed (tr_rs1_forwarding_needed),
.tr_rs2_forwarding_needed (tr_rs2_forwarding_needed),
.tr_rs1_and_rs2_forwarding_needed (tr_rs1_and_rs2_forwarding_needed)
@ -444,14 +446,15 @@ module taiga (
.data_bram (data_bram),
.store_complete (store_complete),
.store_id (store_id),
.wb_store (wb_store),
.wb_snoop (wb_snoop),
.csr_rd (csr_rd),
.csr_id (csr_id),
.csr_done (csr_done),
.ls_is_idle (ls_is_idle),
.ls_exception (ls_exception),
.ls_exception_is_store (ls_exception_is_store),
.wb (unit_wb[LS_UNIT_WB_ID])
.wb (unit_wb[LS_UNIT_WB_ID]),
.tr_load_conflict_delay (tr_load_conflict_delay)
);
generate if (ENABLE_S_MODE) begin
@ -586,6 +589,7 @@ module taiga (
tr.events.branch_misspredict <= tr_branch_misspredict;
tr.events.return_correct <= tr_return_correct;
tr.events.return_misspredict <= tr_return_misspredict;
tr.events.load_conflict_delay <= tr_load_conflict_delay;
tr.events.rs1_forwarding_needed <= tr_rs1_forwarding_needed;
tr.events.rs2_forwarding_needed <= tr_rs2_forwarding_needed;
tr.events.rs1_and_rs2_forwarding_needed <= tr_rs1_and_rs2_forwarding_needed;

View file

@ -34,6 +34,8 @@ package taiga_types;
typedef logic[WB_UNITS_WIDTH-1:0] unit_id_t;
typedef logic[1:0] branch_predictor_metadata_t;
typedef logic [3:0] addr_hash_t;
typedef enum logic [1:0] {
ALU_LOGIC_XOR = 2'b00,
ALU_LOGIC_OR = 2'b01,
@ -215,6 +217,25 @@ package taiga_types;
logic con;
} to_l1_arbiter_packet;
typedef struct packed {
logic [31:0] addr;
logic [2:0] fn3;
id_t id;
logic [3:0] potential_store_conflicts;
} lq_entry_t;
typedef struct packed {
logic [31:0] addr;
logic [3:0] be;
logic [2:0] fn3;
} sq_entry_t;
typedef struct packed {
logic [31:0] data;
id_t id;
logic valid;
} wb_packet_t;
typedef struct packed {
logic [31:0] addr;
logic load;
@ -262,6 +283,9 @@ package taiga_types;
logic return_correct;
logic return_misspredict;
//Load Store Unit
logic load_conflict_delay;
//Register File
logic rs1_forwarding_needed;
logic rs2_forwarding_needed;

View file

@ -36,6 +36,9 @@ ${JG_TAIGA_RTL_PATH}/core/ddata_bank.sv \
${JG_TAIGA_RTL_PATH}/core/dtag_banks.sv \
${JG_TAIGA_RTL_PATH}/core/amo_alu.sv \
${JG_TAIGA_RTL_PATH}/core/dcache.sv \
${JG_TAIGA_RTL_PATH}/core/addr_hash.sv \
${JG_TAIGA_RTL_PATH}/core/load_queue.sv \
${JG_TAIGA_RTL_PATH}/core/store_queue.sv \
${JG_TAIGA_RTL_PATH}/core/load_store_queue.sv \
${JG_TAIGA_RTL_PATH}/core/load_store_unit.sv \
${JG_TAIGA_RTL_PATH}/core/ibram.sv \

View file

@ -61,6 +61,7 @@ static const char * const eventNames[] = {
"branch_misspredict",
"return_correct",
"return_misspredict",
"load_conflict_delay",
"rs1_forwarding_needed",
"rs2_forwarding_needed",
"rs1_and_rs2_forwarding_needed",

View file

@ -47,6 +47,9 @@ core/ddata_bank.sv
core/dtag_banks.sv
core/amo_alu.sv
core/dcache.sv
core/addr_hash.sv
core/load_queue.sv
core/store_queue.sv
core/load_store_queue.sv
core/load_store_unit.sv