mirror of
https://github.com/openhwgroup/cva5.git
synced 2025-04-24 22:17:28 -04:00
dcache cleanups
This commit is contained in:
parent
9903073465
commit
162c360a66
2 changed files with 77 additions and 84 deletions
118
core/dcache.sv
118
core/dcache.sv
|
@ -40,6 +40,11 @@ module dcache(
|
||||||
ls_sub_unit_interface.sub_unit ls
|
ls_sub_unit_interface.sub_unit ls
|
||||||
);
|
);
|
||||||
|
|
||||||
|
localparam DCACHE_SIZE_IN_WORDS = DCACHE_LINES*DCACHE_LINE_W*DCACHE_WAYS;
|
||||||
|
|
||||||
|
logic [$clog2(DCACHE_SIZE_IN_WORDS)-1:0] data_bank_addr_a;
|
||||||
|
logic [$clog2(DCACHE_SIZE_IN_WORDS)-1:0] data_bank_addr_b;
|
||||||
|
|
||||||
logic tag_hit;
|
logic tag_hit;
|
||||||
logic [DCACHE_WAYS-1:0] tag_hit_way;
|
logic [DCACHE_WAYS-1:0] tag_hit_way;
|
||||||
|
|
||||||
|
@ -94,12 +99,11 @@ module dcache(
|
||||||
|
|
||||||
logic store_complete;
|
logic store_complete;
|
||||||
amo_alu_inputs_t amo_alu_inputs;
|
amo_alu_inputs_t amo_alu_inputs;
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
//Implementation
|
||||||
|
|
||||||
const bit[DCACHE_SUB_LINE_ADDR_W-1:0] SUBLINE_PADDING= '0;
|
////////////////////////////////////////////////////
|
||||||
|
//2nd Cycle Control Signals
|
||||||
/*************************************
|
|
||||||
* 2nd cycle signals
|
|
||||||
*************************************/
|
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
if (ls.new_request) begin
|
if (ls.new_request) begin
|
||||||
stage2_addr <= ls_inputs.addr;
|
stage2_addr <= ls_inputs.addr;
|
||||||
|
@ -112,26 +116,17 @@ module dcache(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
/*************************************
|
////////////////////////////////////////////////////
|
||||||
* General Control Logic
|
//General Control Logic
|
||||||
*************************************/
|
//LR and AMO ops are forced misses (if there is a tag hit they will reuse the same way)
|
||||||
//LR and AMO ops are forced misses (if there is a tag hit they will reuse the same way however)
|
//Signal is valid for a single cycle, RAM enables are used to hold outputs in case of pipeline stalls
|
||||||
//Signal is valid only for a single cycle, RAM enables are used to hold outputs in case of pipeline stalls
|
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
if (rst)
|
read_hit_allowed <= ls.new_request & ls_inputs.load & dcache_on & ~(amo.is_lr | amo.is_amo);
|
||||||
read_hit_allowed <= 0;
|
read_hit_data_valid <= read_hit_allowed;
|
||||||
else
|
second_cycle <= ls.new_request;
|
||||||
read_hit_allowed <= ls.new_request & ls_inputs.load & dcache_on & ~(amo.is_lr | amo.is_amo);
|
tag_update <= second_cycle & dcache_on & stage2_load & ~tag_hit;//Cache enabled, read miss
|
||||||
end
|
end
|
||||||
|
|
||||||
always_ff @ (posedge clk) begin
|
|
||||||
if (rst)
|
|
||||||
read_hit_data_valid <= 0;
|
|
||||||
else
|
|
||||||
read_hit_data_valid <= read_hit_allowed;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
//LR reservation, cleared on exceptions
|
//LR reservation, cleared on exceptions
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
if (rst)
|
if (rst)
|
||||||
|
@ -142,25 +137,8 @@ module dcache(
|
||||||
reservation <= 0;
|
reservation <= 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
always_ff @ (posedge clk) begin
|
////////////////////////////////////////////////////
|
||||||
if (rst)
|
//L1 Arbiter Interface
|
||||||
second_cycle <= 0;
|
|
||||||
else
|
|
||||||
second_cycle <= ls.new_request;
|
|
||||||
end
|
|
||||||
|
|
||||||
always_ff @ (posedge clk) begin
|
|
||||||
if (rst)
|
|
||||||
tag_update <= 0;
|
|
||||||
else if (second_cycle)
|
|
||||||
tag_update <= dcache_on & stage2_load & ~tag_hit; //Cache enabled, read miss
|
|
||||||
else
|
|
||||||
tag_update <= 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
/*************************************
|
|
||||||
* L1 Arbiter Interface
|
|
||||||
*************************************/
|
|
||||||
assign l1_request.addr = {stage2_addr[31:2], 2'b0} ;//Memory interface aligns request to burst size (done there to support AMO line-read word-write)
|
assign l1_request.addr = {stage2_addr[31:2], 2'b0} ;//Memory interface aligns request to burst size (done there to support AMO line-read word-write)
|
||||||
assign l1_request.data = stage2_data;
|
assign l1_request.data = stage2_data;
|
||||||
assign l1_request.rnw = stage2_load;
|
assign l1_request.rnw = stage2_load;
|
||||||
|
@ -187,10 +165,8 @@ module dcache(
|
||||||
end
|
end
|
||||||
assign l1_request.request = request | (second_cycle & (~(tag_hit & read_hit_allowed) | ~dcache_on));
|
assign l1_request.request = request | (second_cycle & (~(tag_hit & read_hit_allowed) | ~dcache_on));
|
||||||
|
|
||||||
/*************************************
|
////////////////////////////////////////////////////
|
||||||
* Cache Components
|
//Replacement policy (free runing one-hot cycler, i.e. pseudo random)
|
||||||
*************************************/
|
|
||||||
//Free running one hot cycler.
|
|
||||||
cycler #(DCACHE_WAYS) replacement_policy (.*, .en(1'b1), .one_hot(replacement_way));
|
cycler #(DCACHE_WAYS) replacement_policy (.*, .en(1'b1), .one_hot(replacement_way));
|
||||||
|
|
||||||
//One-hot tag hit / update logic to binary int
|
//One-hot tag hit / update logic to binary int
|
||||||
|
@ -208,7 +184,7 @@ module dcache(
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
//Tag banks
|
//Tag banks
|
||||||
dtag_banks dcache_tag_banks (.*,
|
dtag_banks dcache_tag_banks (.*,
|
||||||
.stage1_addr(ls_inputs.addr),
|
.stage1_addr(ls_inputs.addr),
|
||||||
|
@ -222,10 +198,8 @@ module dcache(
|
||||||
.extern_inv_complete(l1_response.inv_ack)
|
.extern_inv_complete(l1_response.inv_ack)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
assign write_hit_be = stage2_be & {4{tag_hit}};
|
//AMO logic
|
||||||
|
|
||||||
//AMO op processing on incoming data
|
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
amo_rs2 <= stage2_data;
|
amo_rs2 <= stage2_data;
|
||||||
end
|
end
|
||||||
|
@ -247,16 +221,23 @@ module dcache(
|
||||||
new_line_data = l1_response.data;
|
new_line_data = l1_response.data;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
assign sc_write_index = stage2_addr[DCACHE_SUB_LINE_ADDR_W+1:2];
|
assign sc_write_index = stage2_addr[DCACHE_SUB_LINE_ADDR_W+1:2];
|
||||||
assign update_word_index = stage2_amo.is_sc ? sc_write_index : word_count;
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
//Data Bank(s)
|
//Data Bank(s)
|
||||||
ddata_bank #(DCACHE_LINES*DCACHE_LINE_W*DCACHE_WAYS) data_bank (
|
//Tag bank selection done with upper address bits
|
||||||
|
//On miss, word index in line provided by: update_word_index
|
||||||
|
assign write_hit_be = stage2_be & {4{tag_hit}};
|
||||||
|
assign update_word_index = stage2_amo.is_sc ? sc_write_index : word_count;
|
||||||
|
|
||||||
|
assign data_bank_addr_a = {tag_hit_way_int, stage2_addr[DCACHE_LINE_ADDR_W+DCACHE_SUB_LINE_ADDR_W+2-1:2]};
|
||||||
|
assign data_bank_addr_b = {tag_update_way_int, stage2_addr[DCACHE_LINE_ADDR_W+DCACHE_SUB_LINE_ADDR_W+2-1:DCACHE_SUB_LINE_ADDR_W+2], update_word_index};
|
||||||
|
|
||||||
|
ddata_bank #(.LINES(DCACHE_SIZE_IN_WORDS)) data_bank (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.addr_a({tag_hit_way_int, stage2_addr[DCACHE_LINE_ADDR_W+DCACHE_SUB_LINE_ADDR_W+2-1:2]}),
|
.addr_a(data_bank_addr_a),
|
||||||
.addr_b({tag_update_way_int, stage2_addr[DCACHE_LINE_ADDR_W+DCACHE_SUB_LINE_ADDR_W+2-1:DCACHE_SUB_LINE_ADDR_W+2], update_word_index}),
|
.addr_b(data_bank_addr_b),
|
||||||
.en_a(second_cycle),
|
.en_a(second_cycle),
|
||||||
.en_b(l1_response.data_valid | (sc_complete & sc_success)),
|
.en_b(l1_response.data_valid | (sc_complete & sc_success)),
|
||||||
.be_a(write_hit_be),
|
.be_a(write_hit_be),
|
||||||
|
@ -265,10 +246,8 @@ module dcache(
|
||||||
.data_out_a(dbank_data_out)
|
.data_out_a(dbank_data_out)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
/*************************************
|
//Output
|
||||||
* Output Muxing
|
|
||||||
*************************************/
|
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
if (l1_response.data_valid & is_target_word)
|
if (l1_response.data_valid & is_target_word)
|
||||||
miss_data <= l1_response.data;
|
miss_data <= l1_response.data;
|
||||||
|
@ -280,19 +259,11 @@ module dcache(
|
||||||
|
|
||||||
assign data_out = miss_data | ({32{read_hit_data_valid}} & dbank_data_out);
|
assign data_out = miss_data | ({32{read_hit_data_valid}} & dbank_data_out);
|
||||||
|
|
||||||
/*************************************
|
////////////////////////////////////////////////////
|
||||||
* Pipeline Advancement
|
//Pipeline Advancement
|
||||||
*************************************/
|
|
||||||
assign line_complete = (l1_response.data_valid && (word_count == (DCACHE_LINE_W-1))); //covers load, LR, AMO
|
assign line_complete = (l1_response.data_valid && (word_count == (DCACHE_LINE_W-1))); //covers load, LR, AMO
|
||||||
assign store_complete = l1_request.ack & stage2_store & ~stage2_amo.is_sc;
|
assign store_complete = l1_request.ack & stage2_store & ~stage2_amo.is_sc;
|
||||||
|
|
||||||
always_ff @ (posedge clk) begin
|
|
||||||
if (rst)
|
|
||||||
ls.data_valid <= 0;
|
|
||||||
else
|
|
||||||
ls.data_valid <= ((l1_response.data_valid & is_target_word) | (read_hit_allowed & tag_hit) | sc_complete);
|
|
||||||
end
|
|
||||||
|
|
||||||
//read miss complete includes store conditional complete
|
//read miss complete includes store conditional complete
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
if (rst)
|
if (rst)
|
||||||
|
@ -301,6 +272,13 @@ module dcache(
|
||||||
read_miss_complete <= line_complete | sc_complete;
|
read_miss_complete <= line_complete | sc_complete;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
always_ff @ (posedge clk) begin
|
||||||
|
if (rst)
|
||||||
|
ls.data_valid <= 0;
|
||||||
|
else
|
||||||
|
ls.data_valid <= ((l1_response.data_valid & is_target_word) | (read_hit_allowed & tag_hit) | sc_complete);
|
||||||
|
end
|
||||||
|
|
||||||
assign ls.ready = (read_hit_allowed & tag_hit) | store_complete | (read_miss_complete) | idle;
|
assign ls.ready = (read_hit_allowed & tag_hit) | store_complete | (read_miss_complete) | idle;
|
||||||
|
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
|
|
|
@ -44,7 +44,10 @@ module dtag_banks(
|
||||||
output logic[DCACHE_WAYS-1:0] tag_hit_way
|
output logic[DCACHE_WAYS-1:0] tag_hit_way
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef logic [DCACHE_TAG_W : 0] dtag_entry_t;
|
typedef struct packed{
|
||||||
|
logic valid;
|
||||||
|
logic [DCACHE_TAG_W-1:0] tag;
|
||||||
|
} dtag_entry_t;
|
||||||
|
|
||||||
function logic[DCACHE_TAG_W-1:0] getTag(logic[31:0] addr);
|
function logic[DCACHE_TAG_W-1:0] getTag(logic[31:0] addr);
|
||||||
return addr[31 : 32 - DCACHE_TAG_W];
|
return addr[31 : 32 - DCACHE_TAG_W];
|
||||||
|
@ -57,8 +60,7 @@ module dtag_banks(
|
||||||
dtag_entry_t tag_line[DCACHE_WAYS - 1:0];
|
dtag_entry_t tag_line[DCACHE_WAYS - 1:0];
|
||||||
dtag_entry_t inv_tag_line[DCACHE_WAYS - 1:0];
|
dtag_entry_t inv_tag_line[DCACHE_WAYS - 1:0];
|
||||||
|
|
||||||
dtag_entry_t stage2_tag;
|
dtag_entry_t new_tagline;
|
||||||
dtag_entry_t new_tag;
|
|
||||||
|
|
||||||
logic miss_or_extern_invalidate;
|
logic miss_or_extern_invalidate;
|
||||||
logic [DCACHE_WAYS - 1:0] update_tag_way;
|
logic [DCACHE_WAYS - 1:0] update_tag_way;
|
||||||
|
@ -68,15 +70,18 @@ module dtag_banks(
|
||||||
logic[DCACHE_WAYS-1:0] inv_hit_way;
|
logic[DCACHE_WAYS-1:0] inv_hit_way;
|
||||||
logic[DCACHE_WAYS-1:0] inv_hit_way_r;
|
logic[DCACHE_WAYS-1:0] inv_hit_way_r;
|
||||||
|
|
||||||
|
|
||||||
logic [DCACHE_LINE_ADDR_W-1:0] update_port_addr;
|
logic [DCACHE_LINE_ADDR_W-1:0] update_port_addr;
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
//Implementation
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
//Muxing of cache miss or invalidation control logic and tags
|
||||||
assign miss_or_extern_invalidate = update | extern_inv;
|
assign miss_or_extern_invalidate = update | extern_inv;
|
||||||
|
|
||||||
assign update_port_addr = update ? getLineAddr(stage2_addr) : getLineAddr(inv_addr);
|
assign update_port_addr = update ? getLineAddr(stage2_addr) : getLineAddr(inv_addr);
|
||||||
|
|
||||||
assign stage2_tag = {1'b1, getTag(stage2_addr)};
|
assign new_tagline.valid = update;//If not update then an invalidation is being performed
|
||||||
assign new_tag = {update, getTag(stage2_addr)};
|
assign new_tagline.tag = getTag(stage2_addr);
|
||||||
|
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @ (posedge clk) begin
|
||||||
if (rst)
|
if (rst)
|
||||||
|
@ -87,29 +92,39 @@ module dtag_banks(
|
||||||
|
|
||||||
assign extern_inv_complete = (extern_inv & ~update) & inv_tags_accessed;
|
assign extern_inv_complete = (extern_inv & ~update) & inv_tags_accessed;
|
||||||
|
|
||||||
genvar i;
|
////////////////////////////////////////////////////
|
||||||
|
//Memory instantiation and hit detection
|
||||||
generate
|
generate
|
||||||
for (i=0; i < DCACHE_WAYS; i=i+1) begin : tag_bank_gen
|
genvar i;
|
||||||
|
dtag_entry_t stage2_hit_comparison_tagline;
|
||||||
|
dtag_entry_t inv_hit_comparison_tagline;
|
||||||
|
|
||||||
|
assign stage2_hit_comparison_tagline.valid = 1;
|
||||||
|
assign stage2_hit_comparison_tagline.tag = getTag(stage2_addr);
|
||||||
|
assign inv_hit_comparison_tagline.valid = 1;
|
||||||
|
assign inv_hit_comparison_tagline.tag = getTag(inv_addr);
|
||||||
|
|
||||||
|
for (i=0; i < DCACHE_WAYS; i=i+1) begin : dtag_bank_gen
|
||||||
assign update_tag_way[i] = update_way[i] | (inv_hit_way[i] & extern_inv_complete);
|
assign update_tag_way[i] = update_way[i] | (inv_hit_way[i] & extern_inv_complete);
|
||||||
|
|
||||||
tag_bank #(DCACHE_TAG_W+1, DCACHE_LINES) dtag_bank (.*,
|
tag_bank #($bits(dtag_entry_t), DCACHE_LINES) dtag_bank (.*,
|
||||||
.en_a(stage1_adv), .wen_a(stage1_inv),
|
.en_a(stage1_adv), .wen_a(stage1_inv),
|
||||||
.addr_a(getLineAddr(stage1_addr)),
|
.addr_a(getLineAddr(stage1_addr)),
|
||||||
.data_in_a('0), .data_out_a(tag_line[i]),
|
.data_in_a('0), .data_out_a(tag_line[i]),
|
||||||
|
|
||||||
.en_b(miss_or_extern_invalidate), .wen_b(update_tag_way[i]),
|
.en_b(miss_or_extern_invalidate), .wen_b(update_tag_way[i]),
|
||||||
.addr_b(update_port_addr),
|
.addr_b(update_port_addr),
|
||||||
.data_in_b(new_tag), .data_out_b(inv_tag_line[i])
|
.data_in_b(new_tagline), .data_out_b(inv_tag_line[i])
|
||||||
);
|
);
|
||||||
|
|
||||||
assign inv_hit_way[i] = ({1'b1, getTag(inv_addr)} == inv_tag_line[i]);
|
assign inv_hit_way[i] = (inv_hit_comparison_tagline == inv_tag_line[i]);
|
||||||
assign tag_hit_way[i] = (stage2_tag == tag_line[i]);
|
assign tag_hit_way[i] = (stage2_hit_comparison_tagline == tag_line[i]);
|
||||||
|
|
||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
assign tag_hit = |tag_hit_way;
|
assign tag_hit = |tag_hit_way;
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
//Assertions
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue