Instruction and Data Cache reorganization and cleanup

Signed-off-by: Eric Matthews <ematthew@sfu.ca>
This commit is contained in:
Eric Matthews 2022-06-13 14:45:20 -04:00
parent 6aeac17b9d
commit 562a9c2ff6
4 changed files with 135 additions and 138 deletions

View file

@ -100,12 +100,11 @@ module dcache
logic hit_allowed;
logic read_hit_allowed;
logic read_hit_data_valid;
logic read_hit;
logic address_range_valid;
logic idle;
logic busy;
logic read_miss_complete;
logic store_complete;
@ -136,7 +135,6 @@ module dcache
//Signal is valid for a single cycle, RAM enables are used to hold outputs in case of pipeline stalls
always_ff @ (posedge clk) begin
read_hit_allowed <= ls.new_request & ls.re & dcache_on & ~(amo.is_lr | amo.is_amo) & ~uncacheable;
read_hit_data_valid <= read_hit_allowed;
second_cycle <= ls.new_request;
tag_update <= second_cycle & dcache_on & stage2.load & ~tag_hit & ~stage2.uncacheable;//Cache enabled, read miss
end
@ -144,14 +142,11 @@ module dcache
assign read_hit = tag_hit & read_hit_allowed;
//LR reservation, cleared on exceptions
always_ff @ (posedge clk) begin
if (rst)
reservation <= 0;
else if (second_cycle)
reservation <= stage2.amo.is_lr;
else if (sc_complete | clear_reservation)
reservation <= 0;
else
reservation <= (reservation & ~(sc_complete | clear_reservation)) | (second_cycle & stage2.amo.is_lr);
end
////////////////////////////////////////////////////
@ -165,10 +160,10 @@ module dcache
assign l1_request.amo = stage2.amo.op;
always_ff @ (posedge clk) begin
if (rst | line_complete)
if (ls.new_request)
word_count <= 0;
else if (l1_response.data_valid)
word_count <= word_count + 1;
else
word_count <= word_count + SCONFIG.SUB_LINE_ADDR_W'(l1_response.data_valid);
end
assign is_target_word = (stage2.addr[SCONFIG.SUB_LINE_ADDR_W-1:0] == word_count) | stage2.uncacheable;
@ -176,32 +171,30 @@ module dcache
always_ff @ (posedge clk) begin
if (rst)
arb_request_r <= 0;
else if (second_cycle & ~l1_request.ack)
arb_request_r <= new_arb_request;
else if (l1_request.ack)
arb_request_r <= 0;
else
arb_request_r <= (arb_request_r | new_arb_request) & ~l1_request.ack;
end
assign l1_request.request = new_arb_request | arb_request_r;
////////////////////////////////////////////////////
//Replacement policy (free runing one-hot cycler, i.e. pseudo random)
cycler #(CONFIG.DCACHE.WAYS) replacement_policy (
.clk (clk),
.rst (rst),
.en (1'b1),
.one_hot (replacement_way)
.clk (clk),
.rst (rst),
.en (1'b1),
.one_hot (replacement_way)
);
//One-hot tag hit / update logic to binary int
one_hot_to_integer #(CONFIG.DCACHE.WAYS)
hit_way_conv (
.one_hot(tag_hit_way),
.int_out(tag_hit_way_int)
.one_hot (tag_hit_way),
.int_out (tag_hit_way_int)
);
one_hot_to_integer #(CONFIG.DCACHE.WAYS)
update_way_conv (
.one_hot (replacement_way),
.int_out (replacement_way_int)
.one_hot (replacement_way),
.int_out (replacement_way_int)
);
@ -252,9 +245,9 @@ module dcache
endgenerate
always_comb begin
if (stage2.amo.is_amo & is_target_word)
if (CONFIG.INCLUDE_AMO & stage2.amo.is_amo & is_target_word)
new_line_data = amo_result;
else if (stage2.amo.is_sc)
else if (CONFIG.INCLUDE_AMO & stage2.amo.is_sc)
new_line_data = stage2.data;
else
new_line_data = l1_response.data;
@ -278,28 +271,27 @@ module dcache
assign data_bank_addr_b = {tag_update_way_int, stage2.addr[SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W-1:SCONFIG.SUB_LINE_ADDR_W], update_word_index};
end endgenerate
ddata_bank #(.LINES(DCACHE_SIZE_IN_WORDS)) data_bank (
.clk(clk),
.addr_a(data_bank_addr_a),
.addr_b(data_bank_addr_b),
.en_a(second_cycle),
.en_b((l1_response.data_valid & ~stage2.uncacheable) | (sc_complete & sc_success)),
.be_a(write_hit_be),
.data_in_a(stage2.data),
.data_in_b(new_line_data),
.data_out_a(dbank_data_out)
);
ddata_bank #(.LINES(DCACHE_SIZE_IN_WORDS))
data_bank (
.clk(clk),
.addr_a(data_bank_addr_a),
.addr_b(data_bank_addr_b),
.en_a(second_cycle),
.en_b((l1_response.data_valid & ~stage2.uncacheable) | (sc_complete & sc_success)),
.be_a(write_hit_be),
.data_in_a(stage2.data),
.data_in_b(new_line_data),
.data_out_a(dbank_data_out)
);
////////////////////////////////////////////////////
//Output
logic l1_data_valid_r;
always_ff @ (posedge clk) begin
if (l1_response.data_valid & is_target_word)
miss_data <= l1_response.data;
else if (sc_complete)
miss_data <= {31'b0, sc_success};
l1_data_valid_r <= l1_response.data_valid;
miss_data <= sc_complete ? {31'b0, sc_success} : l1_response.data;
end
assign ls.data_out = read_hit_data_valid ? dbank_data_out : miss_data;
assign ls.data_out = l1_data_valid_r ? miss_data : dbank_data_out;
////////////////////////////////////////////////////
//Pipeline Advancement
@ -321,15 +313,13 @@ module dcache
ls.data_valid <= (l1_response.data_valid & is_target_word) | read_hit | sc_complete;
end
assign ls.ready = read_hit | store_complete | read_miss_complete | idle;
assign ls.ready = read_hit | store_complete | read_miss_complete | ~busy;
always_ff @ (posedge clk) begin
if (rst)
idle <= 1;
else if (ls.new_request)
idle <= 0;
else if (ls.ready)
idle <= 1;
busy <= 0;
else
busy <= (busy & ~ls.ready) | ls.new_request;
end
////////////////////////////////////////////////////

View file

@ -42,6 +42,7 @@ module icache
);
localparam derived_cache_config_t SCONFIG = get_derived_cache_params(CONFIG, CONFIG.ICACHE, CONFIG.ICACHE_ADDR);
localparam bit [SCONFIG.SUB_LINE_ADDR_W-1:0] END_OF_LINE_COUNT = SCONFIG.SUB_LINE_ADDR_W'(CONFIG.ICACHE.LINE_W-1);
logic tag_hit;
logic [CONFIG.ICACHE.WAYS-1:0] tag_hit_way;
@ -51,20 +52,24 @@ module icache
logic [CONFIG.ICACHE.WAYS-1:0] tag_update_way;
logic [SCONFIG.SUB_LINE_ADDR_W-1:0] word_count;
logic [SCONFIG.SUB_LINE_ADDR_W-1:0] target_word;
logic is_target_word;
logic line_complete;
logic [31:0] data_out [CONFIG.ICACHE.WAYS-1:0];
logic [31:0] miss_data;
logic miss_in_progress;
logic linefill_in_progress;
logic request_in_progress;
logic miss_data_valid;
logic second_cycle;
logic [31:0] second_cycle_addr;
logic idle;
logic memory_complete;
fifo_interface #(.DATA_WIDTH(32)) input_fifo();
logic new_request;
logic [31:0] new_request_addr;
////////////////////////////////////////////////////
//Implementation
@ -72,18 +77,44 @@ module icache
//On the second cycle of a request hit/miss determination is performed
//On a miss, the memory request starts on the third cycle
assign new_request = (fetch_sub.new_request | input_fifo.valid) & ((~request_in_progress | tag_hit) & ~linefill_in_progress);
assign input_fifo.push = fetch_sub.new_request & (~new_request | input_fifo.valid);
assign input_fifo.potential_push = input_fifo.push;
assign input_fifo.pop = new_request & input_fifo.valid;
assign input_fifo.data_in = fetch_sub.addr;
assign new_request_addr = input_fifo.valid ? input_fifo.data_out : fetch_sub.addr;
cva5_fifo #(.DATA_WIDTH(32), .FIFO_DEPTH(2))
cache_input_fifo (
.clk (clk),
.rst (rst),
.fifo (input_fifo)
);
////////////////////////////////////////////////////
//Ready determination
always_ff @ (posedge clk) begin
if (rst)
request_in_progress <= 0;
else
request_in_progress <= (request_in_progress & ~fetch_sub.data_valid) | new_request;
end
assign fetch_sub.ready = ~input_fifo.full;
////////////////////////////////////////////////////
//General Control Logic
always_ff @ (posedge clk) begin
if (rst)
second_cycle <= 0;
else
second_cycle <= fetch_sub.new_request;
second_cycle <= new_request;
end
always_ff @(posedge clk) begin
if (fetch_sub.new_request)
second_cycle_addr <= fetch_sub.addr;
if (new_request)
second_cycle_addr <= new_request_addr;
end
//As request can be aborted on any cycle, only update tags if memory request is in progress
@ -96,13 +127,13 @@ module icache
//Replacement policy is psuedo random
cycler #(CONFIG.ICACHE.WAYS) replacement_policy (
.clk (clk),
.rst (rst),
.en (1'b1),
.one_hot (replacement_way)
.clk (clk),
.rst (rst),
.en (1'b1),
.one_hot (replacement_way)
);
always_ff @ (posedge clk) begin
if (second_cycle)
if (second_cycle & ~linefill_in_progress)
tag_update_way <= replacement_way;
end
@ -132,24 +163,24 @@ module icache
//Miss state tracking
always_ff @ (posedge clk) begin
if (rst)
miss_in_progress <= 0;
linefill_in_progress <= 0;
else
miss_in_progress <= l1_request.ack | (miss_in_progress & ~line_complete);
linefill_in_progress <= (linefill_in_progress & ~line_complete) | l1_request.ack;
end
////////////////////////////////////////////////////
//Tag banks
itag_banks #(.CONFIG(CONFIG), .SCONFIG(SCONFIG))
icache_tag_banks (
.clk(clk),
.rst(rst), //clears the read_hit_allowed flag
.stage1_addr(fetch_sub.addr),
.stage2_addr(second_cycle_addr),
.update_way(tag_update_way),
.update(tag_update),
.stage1_adv(fetch_sub.new_request & icache_on),
.tag_hit(tag_hit),
.tag_hit_way(tag_hit_way)
.clk(clk),
.rst(rst), //clears the read_hit_allowed flag
.stage1_addr(new_request_addr),
.stage2_addr(second_cycle_addr),
.update_way(tag_update_way),
.update(tag_update),
.stage1_adv(new_request & icache_on),
.tag_hit(tag_hit),
.tag_hit_way(tag_hit_way)
);
////////////////////////////////////////////////////
@ -158,9 +189,9 @@ module icache
generate for (i=0; i < CONFIG.ICACHE.WAYS; i++) begin : idata_bank_gen
byte_en_BRAM #(CONFIG.ICACHE.LINES*CONFIG.ICACHE.LINE_W) idata_bank (
.clk(clk),
.addr_a(fetch_sub.addr[2 +: SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W]),
.addr_a(new_request_addr[2 +: SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W]),
.addr_b({second_cycle_addr[(2+SCONFIG.SUB_LINE_ADDR_W) +: SCONFIG.LINE_ADDR_W], word_count}),
.en_a(fetch_sub.new_request),
.en_a(new_request),
.en_b(tag_update_way[i] & l1_response.data_valid),
.be_a('0),
.be_b('1),
@ -173,61 +204,42 @@ module icache
////////////////////////////////////////////////////
//Miss data path
assign target_word = second_cycle_addr[2 +: SCONFIG.SUB_LINE_ADDR_W];
assign is_target_word = (target_word == word_count);
always_ff @ (posedge clk) begin
if (rst)
word_count <= 0;
else if (l1_response.data_valid)
word_count <= word_count + 1;
end
assign is_target_word = (second_cycle_addr[2 +: SCONFIG.SUB_LINE_ADDR_W] == word_count);
always_ff @ (posedge clk) begin
if (l1_response.data_valid & is_target_word)
miss_data <= l1_response.data;
else
miss_data <= 0;
word_count <= word_count + SCONFIG.SUB_LINE_ADDR_W'(l1_response.data_valid);
end
always_ff @ (posedge clk) begin
if (rst)
miss_data_valid <= 0;
else
miss_data_valid <= miss_in_progress & l1_response.data_valid & is_target_word;
end
assign line_complete = (l1_response.data_valid && (word_count == SCONFIG.SUB_LINE_ADDR_W'(CONFIG.ICACHE.LINE_W-1)));
always_ff @ (posedge clk) begin
if (rst)
memory_complete <= 0;
else
memory_complete <= line_complete;
end
assign miss_data_valid = request_in_progress & l1_response.data_valid & is_target_word;
assign line_complete = l1_response.data_valid & (word_count == END_OF_LINE_COUNT);
////////////////////////////////////////////////////
//Output muxing
localparam OMUX_W = CONFIG.ICACHE.WAYS+1;
logic [OMUX_W-1:0] priority_vector;
logic [$clog2(OMUX_W)-1:0] output_sel;
logic [31:0] output_array [OMUX_W];
always_comb begin
fetch_sub.data_out = miss_data;//zero if not a miss
priority_vector[0] = miss_data_valid;
output_array[0] = l1_response.data;
for (int i = 0; i < CONFIG.ICACHE.WAYS; i++) begin
fetch_sub.data_out = fetch_sub.data_out | (data_out[i] & {32{tag_hit_way[i]}});
priority_vector[i+1] = tag_hit_way[i];
output_array[i+1] = data_out[i];
end
end
priority_encoder #(.WIDTH(OMUX_W))
arb_encoder
(
.priority_vector (priority_vector),
.encoded_result (output_sel)
);
assign fetch_sub.data_out = output_array[output_sel];
assign fetch_sub.data_valid = miss_data_valid | tag_hit;
////////////////////////////////////////////////////
//Ready determination
always_ff @ (posedge clk) begin
if (rst)
idle <= 1;
else if (fetch_sub.new_request)
idle <= 0;
else if (memory_complete | tag_hit) //read miss OR write through complete
idle <= 1;
end
assign fetch_sub.ready = tag_hit | memory_complete | idle;
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
@ -239,7 +251,7 @@ module icache
else $error("Spurious icache ack received from arbiter!");
icache_l1_arb_data_valid_assertion:
assert property (@(posedge clk) disable iff (rst) l1_response.data_valid |-> miss_in_progress)
assert property (@(posedge clk) disable iff (rst) l1_response.data_valid |-> linefill_in_progress)
else $error("Spurious icache data received from arbiter!");
endmodule

View file

@ -198,12 +198,12 @@ interface load_store_queue_interface;
lsq_entry_t data_in;
logic potential_push;
logic push;
logic full;
logic pop;
//LSQ outputs
data_access_shared_inputs_t data_out;
logic valid;
logic pop;
logic full;
//LSQ status
logic sq_empty;
@ -228,12 +228,11 @@ interface store_queue_interface;
//Issue inputs
lsq_entry_t data_in;
logic push;
logic full;
logic pop;
sq_entry_t data_out;
logic valid;
logic pop;
logic full;
//SQ status
logic empty;

View file

@ -50,7 +50,7 @@ module l1_arbiter
logic [L1_CONNECTIONS-1:0] acks;
logic [((L1_CONNECTIONS == 1) ? 0 : ($clog2(L1_CONNECTIONS)-1)) : 0] arb_sel;
logic push_ready;
logic fifos_full;
logic request_exists;
////////////////////////////////////////////////////
//Implementation
@ -69,14 +69,14 @@ module l1_arbiter
assign sc_success = CONFIG.INCLUDE_AMO & l2.con_result;
//Arbiter can pop address FIFO at a different rate than the data FIFO, so check that both have space.
assign push_ready = ~(l2.request_full | l2.data_full);
assign fifos_full = l2.request_full | l2.data_full;
assign request_exists = |requests;
assign l2.request_push = push_ready & request_exists;
assign l2.request_push = request_exists & ~fifos_full;
////////////////////////////////////////////////////
//Dcache Specific
assign l2.wr_data_push = CONFIG.INCLUDE_DCACHE & (push_ready & l1_request[L1_DCACHE_ID].request & ~l1_request[L1_DCACHE_ID].rnw); //Assumes data cache has highest priority
assign l2.wr_data_push = CONFIG.INCLUDE_DCACHE & (l1_request[L1_DCACHE_ID].request & ~l1_request[L1_DCACHE_ID].rnw & ~fifos_full); //Assumes data cache has highest priority
assign l2.wr_data = l1_request[L1_DCACHE_ID].data;
assign l2.inv_ack = CONFIG.DCACHE.USE_EXTERNAL_INVALIDATIONS ? l1_response[L1_DCACHE_ID].inv_ack : l2.inv_valid;
@ -86,30 +86,26 @@ module l1_arbiter
////////////////////////////////////////////////////
//Interface mapping
generate for (genvar i = 0; i < L1_CONNECTIONS; i++) begin : gen_l2_requests
always_comb begin
l2_requests[i].addr = l1_request[i].addr[31:2];
l2_requests[i].rnw = l1_request[i].rnw;
l2_requests[i].be = l1_request[i].be;
l2_requests[i].is_amo = l1_request[i].is_amo;
l2_requests[i].amo_type_or_burst_size = l1_request[i].size;
l2_requests[i].sub_id = L2_SUB_ID_W'(i);
end
assign l2_requests[i] = '{
addr : l1_request[i].addr[31:2],
rnw : l1_request[i].rnw,
be : l1_request[i].be,
is_amo : l1_request[i].is_amo,
amo_type_or_burst_size : l1_request[i].size,
sub_id : L2_SUB_ID_W'(i)
};
end endgenerate
////////////////////////////////////////////////////
//Arbitration
priority_encoder
#(.WIDTH(L1_CONNECTIONS))
priority_encoder #(.WIDTH(L1_CONNECTIONS))
arb_encoder
(
.priority_vector (requests),
.encoded_result (arb_sel)
);
always_comb begin
acks = '0;
acks[arb_sel] = l2.request_push;
end
assign acks = L1_CONNECTIONS'(l2.request_push) << arb_sel;
assign l2.addr = l2_requests[arb_sel].addr;
assign l2.rnw = l2_requests[arb_sel].rnw;
@ -120,7 +116,7 @@ module l1_arbiter
generate for (genvar i = 0; i < L1_CONNECTIONS; i++) begin : gen_l1_responses
assign l1_response[i].data = l2.rd_data;
assign l1_response[i].data_valid = l2.rd_data_valid && (l2.rd_sub_id == i);
assign l1_response[i].data_valid = l2.rd_data_valid & (l2.rd_sub_id == i);
end endgenerate
endmodule