lsq updates

This commit is contained in:
Eric Matthews 2020-03-10 11:37:22 -07:00
parent bb534d617f
commit 8ea982f1ab
12 changed files with 382 additions and 340 deletions

View file

@ -96,7 +96,6 @@ module decode_and_issue (
logic nop;
logic issue_valid;
logic load_store_operands_ready;
logic operands_ready;
logic [NUM_UNITS-1:0] unit_operands_ready;
logic mult_div_op;
@ -155,6 +154,7 @@ module decode_and_issue (
assign ti.inflight_packet.is_store = is_store;
assign ti.issued = instruction_issued & (uses_rd | unit_needed[LS_UNIT_WB_ID]);
assign ti.issue_unit_id = unit_needed_for_id_gen_int;
assign ti.exception_possible = opcode_trim inside {LOAD_T, STORE_T, AMO_T};
////////////////////////////////////////////////////
//Unit Determination
assign mult_div_op = fb.instruction[25];
@ -185,20 +185,17 @@ module decode_and_issue (
assign issue_valid = fb_valid & ti.id_available & ~gc_issue_hold & ~gc_fetch_flush;
assign operands_ready = ~rf_issue.rs1_conflict & ~rf_issue.rs2_conflict;
assign load_store_operands_ready = operands_ready;//~rf_issue.rs1_conflict & (~rf_issue.rs2_conflict | (rf_issue.rs2_conflict & (opcode_trim == STORE_T) & load_store_forwarding_possible));
//All units share the same operand ready logic except load-store which has an internal forwarding path
always_comb begin
unit_operands_ready = {NUM_UNITS{operands_ready}};
unit_operands_ready[LS_UNIT_WB_ID] = load_store_operands_ready;
unit_operands_ready[LS_UNIT_WB_ID] = ~rf_issue.rs1_conflict;
end
assign issue_ready = unit_needed & unit_ready;
assign issue = {NUM_UNITS{issue_valid}} & unit_operands_ready & issue_ready;
//If not all units can provide constant ready signals:
//((|issue_ready) & issue_valid & load_store_operands_ready);
assign instruction_issued = (|issue_ready) & issue_valid & load_store_operands_ready;
assign instruction_issued = issue_valid & |(unit_operands_ready & issue_ready);
assign instruction_issued_no_rd = instruction_issued & ~uses_rd;
assign instruction_issued_with_rd = instruction_issued & uses_rd;
@ -273,7 +270,7 @@ module decode_and_issue (
assign ls_inputs.fn3 = amo_op ? LS_W_fn3 : fn3;
assign ls_inputs.load = is_load;
assign ls_inputs.store = is_store;
assign ls_inputs.forwarded_store = 0;//rf_issue.rs2_conflict & load_store_forwarding_possible;
assign ls_inputs.forwarded_store = rf_issue.rs2_conflict;
assign ls_inputs.store_forward_id = rf_issue.rs2_id;
////////////////////////////////////////////////////
@ -368,7 +365,7 @@ module decode_and_issue (
//Unit EX signals
generate
for (i = 0; i < NUM_UNITS; i++) begin
assign unit_issue[i].possible_issue = unit_needed[i] & unit_ready[i] & unit_operands_ready[i] & fb_valid & ti.id_available & ~gc_issue_hold;//Every condition other than a pipeline flush
assign unit_issue[i].possible_issue = unit_needed[i] & unit_operands_ready[i] & fb_valid & ti.id_available;
assign unit_issue[i].new_request = issue[i];
assign unit_issue[i].instruction_id = ti.issue_id;
always_ff @(posedge clk) begin
@ -403,9 +400,9 @@ module decode_and_issue (
////////////////////////////////////////////////////
//Trace Interface
generate if (ENABLE_TRACE_INTERFACE) begin
assign tr_operand_stall = |(unit_needed & unit_ready) & issue_valid & ~load_store_operands_ready;
assign tr_unit_stall = ~|(unit_needed & unit_ready) & issue_valid & load_store_operands_ready;
assign tr_no_id_stall = |(unit_needed & unit_ready) & (fb_valid & ~ti.id_available & ~gc_issue_hold & ~gc_fetch_flush) & load_store_operands_ready;
assign tr_operand_stall = |(unit_needed & unit_ready) & issue_valid & ~|(unit_operands_ready & issue_ready);
assign tr_unit_stall = ~|(unit_needed & unit_ready) & issue_valid & |(unit_operands_ready & issue_ready);
assign tr_no_id_stall = |(unit_needed & unit_ready) & (fb_valid & ~ti.id_available & ~gc_issue_hold & ~gc_fetch_flush) & |(unit_operands_ready & issue_ready);
assign tr_no_instruction_stall = ~fb_valid | gc_fetch_flush;
assign tr_other_stall = fb_valid & ~instruction_issued & ~(tr_operand_stall | tr_unit_stall | tr_no_id_stall | tr_no_instruction_stall);
assign tr_branch_operand_stall = tr_operand_stall & unit_needed[BRANCH_UNIT_ID];

View file

@ -150,9 +150,10 @@ interface tracking_interface;
inflight_instruction_packet inflight_packet;
logic issued;
logic [WB_UNITS_WIDTH-1:0] issue_unit_id;
logic exception_possible;
modport decode (input issue_id, id_available, output inflight_packet, issued, issue_unit_id);
modport wb (output issue_id, id_available, input inflight_packet, issued, issue_unit_id);
modport decode (input issue_id, id_available, output inflight_packet, issued, issue_unit_id, exception_possible);
modport wb (output issue_id, id_available, input inflight_packet, issued, issue_unit_id, exception_possible);
endinterface
interface fifo_interface #(parameter DATA_WIDTH = 42);//#(parameter type data_type = logic[31:0]);
@ -209,40 +210,24 @@ interface tlb_interface;
endinterface
interface store_buffer_request_interface;
//Request signals
logic [31:0] addr;
logic [2:0] fn3;
interface load_store_queue_interface;
logic ready;
data_access_shared_inputs_t transaction_in;
logic valid;
logic [31:0] data;
logic data_valid;
instruction_id_t data_id;
logic valid;
instruction_id_t id;
logic ready;
modport store_buffer (input addr, fn3, data, data_valid, data_id, valid, id, output ready);
modport ls (output addr, fn3, data, data_valid, data_id, valid, id, input ready);
endinterface
interface store_buffer_output_interface;
logic [31:0] addr;
logic [3:0] be;
logic [2:0] fn3;
logic [31:0] data;
logic valid;
instruction_id_t id;
data_access_shared_inputs_t transaction_out;
logic transaction_ready;
logic accepted;
modport store_buffer (output addr, be, fn3, data, valid, id, input accepted);
modport ls (input addr, be, fn3, data, valid, id, output accepted);
modport queue (input transaction_in, data_valid, data_id, valid, accepted, output ready, transaction_out, transaction_ready);
modport ls (output transaction_in, data_valid, data_id, valid, accepted, input ready, transaction_out, transaction_ready);
endinterface
interface ls_sub_unit_interface #(parameter BASE_ADDR = 32'h00000000, parameter UPPER_BOUND = 32'hFFFFFFFF, parameter BIT_CHECK = 4);
logic data_valid;
logic ready;

195
core/load_store_queue.sv Normal file
View file

@ -0,0 +1,195 @@
/*
* 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_store_queue (
input logic clk,
input logic rst,
load_store_queue_interface.queue lsq,
//Address collision checking
input logic [31:0] compare_addr,
input logic compare,
output logic address_conflict,
//Writeback data
input logic potential_exception,
input instruction_id_t writeback_id,
input logic [31:0] writeback_data,
input logic writeback_valid
);
logic [MAX_INFLIGHT_COUNT-1:0] valid;
logic [MAX_INFLIGHT_COUNT-1:0] waiting_for_data;
instruction_id_t oldest_id;
localparam TAG_W = 3;
localparam TAG_OFFSET = 2;
logic [TAG_W-1:0] tag_addr [MAX_INFLIGHT_COUNT];
data_access_shared_inputs_t transactions [MAX_INFLIGHT_COUNT];
data_access_shared_inputs_t oldest_transaction;
instruction_id_t data_ids [MAX_INFLIGHT_COUNT];
instruction_id_t data_id;
logic [31:0] store_data [MAX_INFLIGHT_COUNT];
logic [31:0] data_for_alignment;
logic [1:0] data_address_alignment;
logic writeback_data_match;
logic update_store_data;
logic [MAX_INFLIGHT_COUNT-1:0] issuing_one_hot;
logic [MAX_INFLIGHT_COUNT-1:0] new_id_one_hot;
logic [MAX_INFLIGHT_COUNT-1:0] is_store;
logic [MAX_INFLIGHT_COUNT-1:0] need_data_one_hot;
logic [MAX_INFLIGHT_COUNT-1:0] new_data;
logic [MAX_INFLIGHT_COUNT-1:0] writeback_store_one_hot;
fifo_interface #(.DATA_WIDTH($bits(instruction_id_t))) oldest_id_fifo ();
////////////////////////////////////////////////////
//Implementation
////////////////////////////////////////////////////
taiga_fifo #(.DATA_WIDTH($bits(instruction_id_t)), .FIFO_DEPTH(MAX_INFLIGHT_COUNT)) id_fifo (.fifo(oldest_id_fifo), .*);
assign oldest_id_fifo.data_in = lsq.transaction_in.id;
assign oldest_id_fifo.push = lsq.valid;
assign oldest_id_fifo.supress_push = 0;
assign oldest_id_fifo.pop = lsq.accepted;
assign oldest_id = oldest_id_fifo.data_out;
//Request attributes that need only a single read-port
always_ff @ (posedge clk) begin
if (lsq.valid) begin
transactions[lsq.transaction_in.id] <= lsq.transaction_in;
data_ids[lsq.transaction_in.id] <= lsq.data_valid ? lsq.transaction_in.id : lsq.data_id;
end
end
assign writeback_data_match = writeback_valid & waiting_for_data[writeback_id];
//LUTRAM for the store data
assign update_store_data = (lsq.valid & lsq.data_valid) | writeback_data_match;
always_ff @ (posedge clk) begin
if (update_store_data)
store_data[writeback_data_match ? writeback_id : lsq.transaction_in.id] <= writeback_data_match ? writeback_data : lsq.transaction_in.data_in;
end
always_comb begin
new_id_one_hot = 0;
new_id_one_hot[lsq.transaction_in.id] = lsq.valid;
need_data_one_hot = 0;
need_data_one_hot[lsq.data_id] = lsq.valid & lsq.transaction_in.store & ~lsq.data_valid;
issuing_one_hot = 0;
issuing_one_hot[oldest_id] = lsq.accepted;
writeback_store_one_hot = 0;
writeback_store_one_hot[writeback_id] = writeback_valid;
end
always_ff @ (posedge clk) begin
if (rst)
valid <= 0;
else
valid <= (new_id_one_hot | valid) & ~issuing_one_hot;
end
always_ff @ (posedge clk) begin
if (rst)
is_store <= 0;
else
is_store <= ((new_id_one_hot & {MAX_INFLIGHT_COUNT{lsq.transaction_in.store}}) | is_store) & ~issuing_one_hot;
end
always_ff @ (posedge clk) begin
if (rst)
waiting_for_data <= 0;
else
waiting_for_data <= (need_data_one_hot | waiting_for_data) & ~writeback_store_one_hot;
end
////////////////////////////////////////////////////
//Collision checking
always_ff @ (posedge clk) begin
foreach(tag_addr[i]) begin
if (new_id_one_hot[i])
tag_addr[i] <= lsq.transaction_in.addr[0+:TAG_W];
end
end
always_comb begin
address_conflict = 0;
for (int i=0; i < MAX_INFLIGHT_COUNT; i++) begin
address_conflict |= (tag_addr[i] == compare_addr[0+:TAG_W]) && valid[i] && is_store[i];
end
end
////////////////////////////////////////////////////
//Output
assign data_id = data_ids[oldest_id];
assign oldest_transaction = transactions[oldest_id];
//Can accept an input so long as it is a load or an update from writeback for an exisiting store is not in progress
assign lsq.ready = (lsq.transaction_in.load | ~writeback_data_match);
assign lsq.transaction_ready = valid[oldest_id] & (oldest_transaction.load | ~waiting_for_data[data_id]);
always_comb begin
data_for_alignment = lsq.transaction_ready ? store_data[data_id] : lsq.transaction_in.data_in;
lsq.transaction_out = lsq.transaction_ready ? oldest_transaction : lsq.transaction_in;
lsq.transaction_out.id = lsq.transaction_ready ? oldest_id : lsq.transaction_in.id;
//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
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//Assertions
endmodule

View file

@ -50,6 +50,11 @@ module load_store_unit (
//Store-Writeback Interface
input instruction_id_t oldest_id,
output logic load_store_exception_clear,
output instruction_id_t load_store_exception_id,
input logic potential_exception,
input instruction_id_t writeback_id,
input logic [31:0] writeback_data,
input logic writeback_valid,
output instruction_id_t store_done_id,
@ -82,20 +87,19 @@ module load_store_unit (
logic units_ready;
logic unit_switch_stall;
logic ready_for_store;
logic ready_for_load;
logic ready_for_delayed_store;
logic ready_for_bypass_store;
logic ready_for_issue;
logic bypass_possible;
logic issue_request;
logic load_complete;
logic use_store_buffer;
logic [31:0] virtual_address;
logic [31:0] unit_muxed_load_data;
logic [31:0] aligned_load_data;
logic [31:0] final_load_data;
logic [31:0] unit_data_array [NUM_SUB_UNITS-1:0];
logic [NUM_SUB_UNITS-1:0] unit_ready;
logic [NUM_SUB_UNITS-1:0] unit_data_valid;
@ -115,86 +119,28 @@ module load_store_unit (
} load_attributes_t;
load_attributes_t load_attributes_in, stage2_attr;
logic [3:0] be;
//FIFOs
fifo_interface #(.DATA_WIDTH($bits(load_attributes_t))) load_attributes();
store_buffer_request_interface sb_request();
store_buffer_output_interface sb_output();
load_store_queue_interface lsq();
logic [31:0] compare_addr;
logic compare;
logic address_conflict;
logic store_buffer_bypassable;
////////////////////////////////////////////////////
//Implementation
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//Unit tracking
assign current_unit = sub_unit_address_match;
initial last_unit = BRAM_ID;
always_ff @ (posedge clk) begin
if (load_attributes.push)
last_unit <= sub_unit_address_match;
end
////////////////////////////////////////////////////
//Store buffer
assign sb_request.addr = tlb.physical_address;
assign sb_request.fn3 = ls_inputs.fn3;
assign sb_request.data = ls_inputs.rs2;
assign sb_request.data_valid = ~ls_inputs.forwarded_store;
assign sb_request.data_id = ls_inputs.store_forward_id;
assign sb_request.valid = issue.new_request & ls_inputs.store;
assign sb_request.id = issue.instruction_id;
assign sb_output.accepted = use_store_buffer & units_ready;
store_buffer sb (.*);
assign compare_addr = virtual_address;
assign compare = ls_inputs.load;
assign store_done_id = sb_output.id;
assign store_complete = sb_output.accepted;
////////////////////////////////////////////////////
//Primary Control Signals
assign units_ready = &unit_ready;
assign load_complete = |unit_data_valid;
assign use_store_buffer = sb_output.valid;
assign ready_for_load = ls_inputs.load & (~address_conflict) & (~unit_switch_stall) & units_ready & (~sb_output.valid);
assign ready_for_store = ls_inputs.store & sb_request.ready;
assign issue.ready = (ready_for_load | ready_for_store);
always_ff @ (posedge clk) begin
if (rst)
unit_switch_stall <= 0;
else if (issue_request && (current_unit != last_unit) && load_attributes.valid)
unit_switch_stall <= 1;
else if (!load_attributes.valid)
unit_switch_stall <= 0;
end
//When switching units, ensure no outstanding loads so that there can be no timing collisions with results
assign unit_stall = (current_unit != last_unit) && load_attributes.valid;
assign issue_request = issue.new_request | sb_output.accepted;
////////////////////////////////////////////////////
//TLB interface
assign virtual_address = ls_inputs.rs1 + 32'(signed'(ls_inputs.offset));
assign tlb.virtual_address = virtual_address;
assign tlb.new_request = issue_request;
assign tlb.execute = 0;
assign tlb.rnw = ls_inputs.load & ~ls_inputs.store;
////////////////////////////////////////////////////
//Alignment Exception
assign load_store_exception_clear = issue.new_request;
assign load_store_exception_id = issue.instruction_id;
always_comb begin
case(ls_inputs.fn3)
LS_H_fn3 : unaligned_addr = virtual_address[0];
@ -216,26 +162,100 @@ module load_store_unit (
// assign ls_exception.id = issue.instruction_id;
////////////////////////////////////////////////////
//Unit Inputs
assign shared_inputs.addr = use_store_buffer ? sb_output.addr : virtual_address;
assign shared_inputs.load = ~use_store_buffer;
assign shared_inputs.store = use_store_buffer;
assign shared_inputs.be = use_store_buffer ? sb_output.be : 0;
assign shared_inputs.fn3 = use_store_buffer ? sb_output.fn3 : ls_inputs.fn3;
assign shared_inputs.data_in = sb_output.data;
//TLB interface
assign virtual_address = ls_inputs.rs1 + 32'(signed'(ls_inputs.offset));
assign tlb.virtual_address = virtual_address;
assign tlb.new_request = issue_request;
assign tlb.execute = 0;
assign tlb.rnw = ls_inputs.load & ~ls_inputs.store;
////////////////////////////////////////////////////
//Byte enable generation
//Only set on store
// SW: all bytes
// SH: upper or lower half of bytes
// SB: specific byte
always_comb begin
be = 0;
case(ls_inputs.fn3[1:0])
LS_B_fn3[1:0] : be[virtual_address[1:0]] = 1;
LS_H_fn3[1:0] : begin
be[virtual_address[1:0]] = 1;
be[{virtual_address[1], 1'b1}] = 1;
end
default : be = '1;
endcase
be &= {4{~ls_inputs.load}};
end
////////////////////////////////////////////////////
//Load Store Queue
assign lsq.transaction_in.addr = virtual_address;
assign lsq.transaction_in.fn3 = ls_inputs.fn3;
assign lsq.transaction_in.be = be;
assign lsq.transaction_in.data_in = ls_inputs.rs2;
assign lsq.transaction_in.load = ls_inputs.load;
assign lsq.transaction_in.store = ls_inputs.store;
assign lsq.transaction_in.id = issue.instruction_id;
assign lsq.data_valid = ~ls_inputs.forwarded_store;
assign lsq.data_id = ls_inputs.store_forward_id;
assign lsq.valid = issue.new_request & ~bypass_possible;
load_store_queue lsq_block (.*);
assign compare_addr = virtual_address;
assign compare = 1;//ls_inputs.load;
assign lsq.accepted = lsq.transaction_ready & ready_for_issue;
assign store_done_id = shared_inputs.id;
assign store_complete = (lsq.accepted & shared_inputs.store) | (issue.new_request & ls_inputs.store & bypass_possible);
assign shared_inputs = lsq.transaction_out;
////////////////////////////////////////////////////
//Unit tracking
assign current_unit = sub_unit_address_match;
initial last_unit = BRAM_ID;
always_ff @ (posedge clk) begin
if (load_attributes.push)
last_unit <= sub_unit_address_match;
end
//When switching units, ensure no outstanding loads so that there can be no timing collisions with results
assign unit_stall = (current_unit != last_unit) && load_attributes.valid;
always_ff @ (posedge clk) begin
if (rst)
unit_switch_stall <= 0;
else if (issue_request && (current_unit != last_unit) && load_attributes.valid)
unit_switch_stall <= 1;
else if (~load_attributes.valid)
unit_switch_stall <= 0;
end
////////////////////////////////////////////////////
//Primary Control Signals
assign units_ready = &unit_ready;
assign load_complete = |unit_data_valid;
assign ready_for_issue = units_ready & (~unit_switch_stall);
assign bypass_possible = ready_for_issue & (~address_conflict) & (~lsq.transaction_ready) & (~ls_inputs.forwarded_store);
assign issue.ready = lsq.ready;
assign issue_request = (issue.new_request & bypass_possible) | lsq.accepted;
////////////////////////////////////////////////////
//Load attributes FIFO
one_hot_to_integer #(NUM_SUB_UNITS) hit_way_conv (.*, .one_hot(sub_unit_address_match), .int_out(load_attributes_in.subunit_id));
taiga_fifo #(.DATA_WIDTH($bits(load_attributes_t)), .FIFO_DEPTH(ATTRIBUTES_DEPTH))
attributes_fifo (.fifo(load_attributes), .*);
assign load_attributes_in.fn3 = ls_inputs.fn3;
assign load_attributes_in.byte_addr = virtual_address[1:0];
assign load_attributes_in.instruction_id = issue.instruction_id;
one_hot_to_integer #(NUM_SUB_UNITS) sub_unit_select (.*, .one_hot(sub_unit_address_match), .int_out(load_attributes_in.subunit_id));
taiga_fifo #(.DATA_WIDTH($bits(load_attributes_t)), .FIFO_DEPTH(ATTRIBUTES_DEPTH)) attributes_fifo (.fifo(load_attributes), .*);
assign load_attributes_in.fn3 = shared_inputs.fn3;
assign load_attributes_in.byte_addr = shared_inputs.addr[1:0];
assign load_attributes_in.instruction_id = shared_inputs.id;
assign load_attributes.data_in = load_attributes_in;
assign load_attributes.push = issue_request & ~use_store_buffer;
assign load_attributes.push = issue_request & shared_inputs.load;
assign load_attributes.pop = load_complete;
assign load_attributes.supress_push = 0;
@ -311,17 +331,33 @@ module load_store_unit (
////////////////////////////////////////////////////
//Output bank
assign wb.rd = ls_done ? final_load_data : csr_rd;
logic exception_complete;
logic ls_done;
always_ff @ (posedge clk) begin
exception_complete <= (issue_request & ls_exception_valid & ls_inputs.load);
end
assign ls_done = load_complete | exception_complete;
assign exception_complete = (issue_request & ls_exception_valid & ls_inputs.load);
assign wb.rd = ls_done ? final_load_data : csr_rd;
assign wb.done = csr_done | ls_done;
assign wb.id = csr_done ? csr_id : stage2_attr.instruction_id;
// always_ff @ (posedge clk) begin
// exception_complete <= (issue_request & ls_exception_valid & ls_inputs.load);
// wb.rd <= ls_done ? final_load_data : csr_rd;
// if (rst)
// wb.done <= 0;
// else
// wb.done <= csr_done | ls_done;
// wb.id <= csr_done ? csr_id : stage2_attr.instruction_id;
// end
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
@ -330,6 +366,7 @@ module load_store_unit (
//Assertions
always_ff @ (posedge clk) begin
assert ((issue_request & |sub_unit_address_match) || (!issue_request)) else $error("invalid L/S address");
assert ((issue_request & ready_for_issue) || (!issue_request)) else $error("L/S internal request issued without subunits ready");
end
endmodule

View file

@ -1,201 +0,0 @@
/*
* 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_buffer (
input logic clk,
input logic rst,
store_buffer_request_interface.store_buffer sb_request,
store_buffer_output_interface.store_buffer sb_output,
//Load address collision checking
input logic [31:0] compare_addr,
input logic compare,
output logic address_conflict,
//Writeback data
input instruction_id_t oldest_id,
input logic [31:0] writeback_data,
input logic writeback_valid
);
localparam NUM_ENTRIES = MAX_INFLIGHT_COUNT;
localparam NUM_ENTRIES_W = $clog2(NUM_ENTRIES);
logic [NUM_ENTRIES-1:0] valid;
logic [NUM_ENTRIES-1:0] data_valid;
instruction_id_t required_id_to_store_id_table [NUM_ENTRIES];
instruction_id_t store_waiting_id;
localparam TAG_W = 16;
localparam TAG_OFFSET = 2;
logic [TAG_W-1:0] tag_addr [NUM_ENTRIES];
typedef struct packed{
logic [31:TAG_W] upper_addr;
logic [1:0] lower_addr;
logic [2:0] fn3;
} transaction_attributes_t;
transaction_attributes_t new_transaction;
transaction_attributes_t transaction_attributes [NUM_ENTRIES];
logic [31:0] store_data [NUM_ENTRIES];
logic [31:0] new_store_data;
logic [31:0] new_store_data_aligned;
logic [1:0] data_address_alignment;
logic writeback_data_match;
logic update_store_data;
logic [NUM_ENTRIES-1:0] store_issuing_one_hot;
logic [NUM_ENTRIES-1:0] new_id_one_hot;
logic [NUM_ENTRIES-1:0] writeback_store_one_hot;
////////////////////////////////////////////////////
//Implementation
////////////////////////////////////////////////////
//Request attributes that need only a single read-port
assign new_transaction.upper_addr = sb_request.addr[31:TAG_W];
assign new_transaction.lower_addr = sb_request.addr[1:0];
assign new_transaction.fn3 = sb_request.fn3;
always_ff @ (posedge clk) begin
if (sb_request.valid)
transaction_attributes[sb_request.id] <= new_transaction;
end
//Address tags in registers for parallel comparisons
always_ff @ (posedge clk) begin
foreach(tag_addr[i]) begin
if (new_id_one_hot[i])
tag_addr[i] <= sb_request.addr[0+:TAG_W];
end
end
//ID translation table for looking up the store ID from the ID needed by the store
always_ff @ (posedge clk) begin
if (sb_request.valid)
required_id_to_store_id_table[sb_request.data_id] <= sb_request.id;
end
assign store_waiting_id = required_id_to_store_id_table[oldest_id];
assign new_store_data = sb_request.valid ? sb_request.data : writeback_data;
assign data_address_alignment = sb_request.valid ? sb_request.addr[1:0] : transaction_attributes[store_waiting_id].lower_addr[1:0];
//Input: ABCD
//Assuming aligned requests,
//Possible byte selections: (A/C/D, B/D, C/D, D)
always_comb begin
new_store_data_aligned[7:0] = new_store_data[7:0];
new_store_data_aligned[15:8] = (data_address_alignment[1:0] == 2'b01) ? new_store_data[7:0] : new_store_data[15:8];
new_store_data_aligned[23:16] = (data_address_alignment[1:0] == 2'b10) ? new_store_data[7:0] : new_store_data[23:16];
case(data_address_alignment[1:0])
2'b10 : new_store_data_aligned[31:24] = new_store_data[15:8];
2'b11 : new_store_data_aligned[31:24] = new_store_data[7:0];
default : new_store_data_aligned[31:24] = new_store_data[31:24];
endcase
end
//LUTRAM for the store data
assign writeback_data_match = valid[store_waiting_id] & ~data_valid[store_waiting_id];
assign update_store_data = (sb_request.valid & sb_request.data_valid) | (writeback_data_match & writeback_valid);
always_ff @ (posedge clk) begin
if (update_store_data)
store_data[sb_request.valid ? sb_request.id : oldest_id] <= new_store_data_aligned;
end
always_comb begin
new_id_one_hot = 0;
new_id_one_hot[sb_request.id] = sb_request.valid;
store_issuing_one_hot = 0;
store_issuing_one_hot[oldest_id] = sb_output.accepted;
writeback_store_one_hot = 0;
writeback_store_one_hot[store_waiting_id] = writeback_data_match & writeback_valid;
end
always_ff @ (posedge clk) begin
if (rst)
valid <= 0;
else
valid <= (new_id_one_hot | valid) & ~store_issuing_one_hot;
end
always_ff @ (posedge clk) begin
if (rst)
data_valid <= 0;
else
data_valid <= (({NUM_ENTRIES{sb_request.data_valid}} & new_id_one_hot) | writeback_store_one_hot | data_valid) & ~store_issuing_one_hot;
end
assign sb_request.ready = 1;
////////////////////////////////////////////////////
//Collision checking
always_comb begin
address_conflict = 0;
for (int i=0; i < NUM_ENTRIES; i++) begin
address_conflict |= (tag_addr[i] == compare_addr[0+:TAG_W]) && valid[i];
end
address_conflict &= compare;// & |valid;//&= compare;
end
////////////////////////////////////////////////////
//Output
assign sb_output.addr = {transaction_attributes[oldest_id].upper_addr, tag_addr[oldest_id]};//jukiiiyuhhhhhhhhhhhhh , transaction_attributes[oldest_id].lower_addr};
assign sb_output.fn3 = transaction_attributes[oldest_id].fn3;
assign sb_output.data = store_data[oldest_id];
assign sb_output.valid = valid[oldest_id] & data_valid[oldest_id];
assign sb_output.id = oldest_id;
//Byte enable generation
//Only set on store
// SW: all bytes
// SH: upper or lower half of bytes
// SB: specific byte
always_comb begin
sb_output.be = 0;
case(sb_output.fn3[1:0])
LS_B_fn3[1:0] : sb_output.be[sb_output.addr[1:0]] = 1;
LS_H_fn3[1:0] : begin
sb_output.be[sb_output.addr[1:0]] = 1;
sb_output.be[{sb_output.addr[1], 1'b1}] = 1;
end
default : sb_output.be = '1;
endcase
end
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//Assertions
endmodule

View file

@ -119,10 +119,13 @@ module taiga (
//LS
instruction_id_t store_done_id;
logic store_complete;
instruction_id_t writeback_id;
logic [31:0] writeback_data;
logic writeback_valid;
post_issue_forwarding_interface store_forwarding();
logic load_store_exception_clear;
instruction_id_t load_store_exception_id;
logic potential_exception;
//Trace Interface Signals
logic tr_operand_stall;

View file

@ -156,7 +156,7 @@ package taiga_config;
////////////////////////////////////////////////////
//Branch Predictor Options
parameter USE_BRANCH_PREDICTOR = 1;
parameter BRANCH_PREDICTOR_WAYS = 2;
parameter BRANCH_PREDICTOR_WAYS = 1;
parameter BRANCH_TABLE_ENTRIES = 512;
parameter RAS_DEPTH = 8;
@ -169,7 +169,7 @@ package taiga_config;
////////////////////////////////////////////////////
//Trace Options
parameter ENABLE_TRACE_INTERFACE = 1;
parameter ENABLE_TRACE_INTERFACE = 0;
////////////////////////////////////////////////////

View file

@ -216,6 +216,7 @@ package taiga_types;
logic [3:0] be;
logic [2:0] fn3;
logic [31:0] data_in;
instruction_id_t id;
} data_access_shared_inputs_t;
typedef enum {

View file

@ -38,8 +38,15 @@ module write_back(
output logic instruction_queue_empty,
output instruction_id_t oldest_id,
input logic load_store_exception_clear,
input instruction_id_t load_store_exception_id,
output logic potential_exception,
output instruction_id_t writeback_id,
output logic [31:0] writeback_data,
output logic writeback_valid,
input instruction_id_t store_done_id,
input logic store_complete,
@ -67,6 +74,8 @@ module write_back(
inflight_instruction_packet retiring_instruction_packet;
logic [MAX_INFLIGHT_COUNT-1:0] id_inuse;
logic [MAX_INFLIGHT_COUNT-1:0] id_potential_exception;
logic [MAX_INFLIGHT_COUNT-1:0] exception_cleared_one_hot;
logic [MAX_INFLIGHT_COUNT-1:0] id_writeback_pending;
logic [MAX_INFLIGHT_COUNT-1:0] id_writeback_pending_r;
@ -161,6 +170,20 @@ module write_back(
end
assign retiring_instruction_packet = id_metadata[id_retiring];
////////////////////////////////////////////////////
//Potential Exception Tracking
// always_comb begin
// exception_cleared_one_hot = 0;
// exception_cleared_one_hot[load_store_exception_id] = load_store_exception_clear;
// end
// always_ff @ (posedge clk) begin
// if (rst)
// id_potential_exception <= 0;
// else
// id_potential_exception <= (id_potential_exception | {MAX_INFLIGHT_COUNT{ti.exception_possible}} & id_issued_one_hot) & ~exception_cleared_one_hot;
// end
// assign potential_exception = |id_potential_exception;
////////////////////////////////////////////////////
//Register File Interface
//Track whether the ID has a pending write to the register file
@ -195,8 +218,10 @@ module write_back(
assign rf_wb.rd_nzero = |retiring_instruction_packet.rd_addr;
assign rf_wb.rd_data = results_by_id[id_retiring];
assign writeback_data = results_by_id[id_retiring];
assign writeback_valid = instruction_complete;
//Store Buffer data
assign writeback_id = rf_wb.id;
assign writeback_data = rf_wb.rd_data;
assign writeback_valid = rf_wb.retiring;
//Register bypass for issue operands
assign rf_wb.rs1_valid = id_writeback_pending_r[rf_wb.rs1_id];//includes the instruction writing to the register file
@ -223,8 +248,8 @@ module write_back(
tr_num_instructions_in_flight = 0;
tr_num_of_instructions_pending_writeback = 0;
for (int i=0; i<MAX_INFLIGHT_COUNT-1; i++) begin
tr_num_instructions_in_flight += id_inuse[i];
tr_num_of_instructions_pending_writeback += id_writeback_pending[i];
tr_num_instructions_in_flight += ID_W'(id_inuse[i]);
tr_num_of_instructions_pending_writeback += ID_W'(id_writeback_pending[i]);
end
end
end

View file

@ -75,10 +75,10 @@ void TaigaTracer<TB>::update_stats() {
template <class TB>
void TaigaTracer<TB>::print_stats() {
std::cout << " Taiga trace stats:\n";
std::cout << " Taiga trace stats\n";
std::cout << "--------------------------------------------------------------\n";
for (int i=0; i < numEvents; i++)
std::cout << " " << eventNames[i] << ": " << event_counters[i] << std::endl;
std::cout << " " << eventNames[i] << ":" << event_counters[i] << std::endl;
std::cout << "--------------------------------------------------------------\n\n";
}

View file

@ -68,7 +68,7 @@ int main(int argc, char **argv) {
#endif
taigaTracer->reset();
cout << "--------------------------------------------------------------\n";
cout << " Starting Simulation, logging to: " << argv[1] << "\n";
cout << " Starting Simulation, logging to " << argv[1] << "\n";
cout << "--------------------------------------------------------------\n";
// Tick the clock until we are done
@ -85,7 +85,7 @@ int main(int argc, char **argv) {
}
cout << "--------------------------------------------------------------\n";
cout << " Simulation Completed: " << taigaTracer->get_cycle_count() << " cycles.\n";
cout << " Simulation Completed. " << taigaTracer->get_cycle_count() << " cycles.\n";
taigaTracer->print_stats();
logFile.close();

View file

@ -45,7 +45,7 @@
../core/dtag_banks.sv
../core/amo_alu.sv
../core/dcache.sv
../core/store_buffer.sv
../core/load_store_queue.sv
../core/load_store_unit.sv