Get it to kinda work
This commit is contained in:
@@ -5,35 +5,36 @@ module application_wrapper_cache_l1 #(
|
||||
parameter CACHELINE_COUNT = 64,
|
||||
localparam ADDR_WIDTH = 32
|
||||
)(
|
||||
input logic i_clk,
|
||||
input logic i_rst,
|
||||
input logic i_clk,
|
||||
input logic i_rst,
|
||||
|
||||
/* CPU Interface */
|
||||
input logic [ADDR_WIDTH-1:0] i_addr,
|
||||
input logic i_we,
|
||||
input logic [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input logic [ADDR_WIDTH-1:0] i_addr,
|
||||
input logic i_we,
|
||||
input logic i_sync,
|
||||
input logic [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
|
||||
input logic i_rdy,
|
||||
output logic o_rdy,
|
||||
input logic i_rdy,
|
||||
output logic o_rdy,
|
||||
|
||||
/* MMU Interface */
|
||||
input logic [ADDR_WIDTH-1:0] i_phys_address,
|
||||
output page_table_entry_t i_table_entry,
|
||||
input logic i_mmu_valid,
|
||||
input logic [ADDR_WIDTH-1:0] i_phys_address,
|
||||
output page_table_entry_t i_table_entry,
|
||||
input logic i_mmu_valid,
|
||||
|
||||
/* Higher level cache interface */
|
||||
output logic [ADDR_WIDTH-1:0] o_addr,
|
||||
output logic [1:0] o_cache_cmd,
|
||||
output logic o_cache_valid,
|
||||
output logic [ADDR_WIDTH-1:0] o_cache_addr,
|
||||
output cache_cmd_e o_cache_cmd,
|
||||
output logic o_cache_valid,
|
||||
|
||||
output logic [63:0] o_cache_data,
|
||||
input logic [31:0] i_cache_data,
|
||||
input logic i_cache_rdy
|
||||
output logic [CACHELINE_SIZE*8-1:0] o_cache_data,
|
||||
input logic [CACHELINE_SIZE*8-1:0] i_cache_data,
|
||||
input logic i_cache_rdy
|
||||
);
|
||||
|
||||
// we have 32 bit addresses, 64 byte cache lines, and 64 total lines.
|
||||
// Thats 6 bit for offset, 6 bit for index, and 20 bit for cache.
|
||||
// Thats 6 bit for offset, 6 bit for index, and 20 bit for tag.
|
||||
|
||||
// cache is virtually indexed, physically tagged
|
||||
|
||||
@@ -42,49 +43,292 @@ localparam INDEX_W = $clog2(CACHELINE_COUNT);
|
||||
localparam TAG_W = ADDR_WIDTH - INDEX_W - OFFSET_W;
|
||||
localparam META_W = 3; // valid, unique, clean
|
||||
|
||||
logic [OFFSET_W-1:0] offset;
|
||||
logic [INDEX_W-1:0] index;
|
||||
logic [TAG_W-1:0] tag;
|
||||
typedef struct {
|
||||
logic [TAG_W-1:0] tag;
|
||||
logic valid;
|
||||
logic shared;
|
||||
logic clean;
|
||||
} meta_tag_t;
|
||||
|
||||
assign offset = i_addr[OFFSET_W-1:0];
|
||||
assign index = i_addr[INDEX_W+OFFSET_W-1:OFFSET_W];
|
||||
assign tag = i_addr[INDEX_W+OFFSET_W+TAG_W-1:INDEX_W+OFFSET_W];
|
||||
logic [OFFSET_W-1:0] offset, offset_d1;
|
||||
logic [INDEX_W-1:0] index, index_d1, index_d2;
|
||||
logic [TAG_W-1:0] tag, tag_d1;
|
||||
|
||||
// cacheline size is in bytes, not bits
|
||||
// direct mapped cache, read one line so we have data ready if its a hit.
|
||||
logic [CACHELINE_SIZE*8-1:0] data_array [CACHELINE_COUNT];
|
||||
logic [META_W+TAG_W-1:0] meta_tag_array [CACHELINE_COUNT];
|
||||
meta_tag_t meta_tag_array [CACHELINE_COUNT];
|
||||
|
||||
enum logic [1:0] {IDLE, READY, EVICT, READ} state, state_next;
|
||||
logic [CACHELINE_SIZE*8-1:0] current_data, current_data_next, write_data_prev;
|
||||
meta_tag_t current_meta_tag, current_meta_tag_next;
|
||||
|
||||
logic [OFFSET_W-1:0] read_offset, read_offset_next;
|
||||
logic [INDEX_W-1:0] read_index, read_index_next;
|
||||
logic [ADDR_WIDTH-1:0] read_address, read_address_next;
|
||||
logic [ADDR_WIDTH-1:0] write_address, write_address_next;
|
||||
|
||||
logic [CACHELINE_SIZE*8-1:0] write_data;
|
||||
meta_tag_t write_meta_tag;
|
||||
|
||||
logic [INDEX_W-1:0] write_index;
|
||||
logic data_write_enable;
|
||||
logic meta_tag_write_enable;
|
||||
|
||||
logic we_d1;
|
||||
logic latched_we, latched_we_next;
|
||||
|
||||
logic [7:0] latched_data, latched_data_next;
|
||||
logic [7:0] data_d1;
|
||||
|
||||
|
||||
// performance counters
|
||||
logic [31:0] eviction_count, eviction_count_next;
|
||||
logic [31:0] cache_miss_count, cache_miss_count_next;
|
||||
|
||||
// reset counter
|
||||
logic [INDEX_W-1:0] clear_counter, clear_counter_next;
|
||||
|
||||
enum logic [2:0] {RESET, CLEAR, IDLE, READY, EVICT, READ} prev_state, state, state_next;
|
||||
|
||||
always_ff @(posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
state <= IDLE;
|
||||
state <= RESET;
|
||||
|
||||
current_data <= '0;
|
||||
|
||||
tag_d1 <= '0;
|
||||
index_d1 <= '0;
|
||||
offset_d1 <= '0;
|
||||
|
||||
read_address <= '0;
|
||||
write_address <= '0;
|
||||
|
||||
latched_we <= '0;
|
||||
|
||||
latched_data <= '0;
|
||||
|
||||
eviction_count <= '0;
|
||||
cache_miss_count <= '0;
|
||||
|
||||
clear_counter <= '0;
|
||||
|
||||
end else begin
|
||||
prev_state <= state;
|
||||
state <= state_next;
|
||||
|
||||
current_data <= current_data_next;
|
||||
write_data_prev <= write_data;
|
||||
current_meta_tag <= current_meta_tag_next;
|
||||
|
||||
read_offset <= read_offset_next;
|
||||
read_index <= read_index_next;
|
||||
|
||||
read_address <= read_address_next;
|
||||
write_address <= write_address_next;
|
||||
|
||||
if (data_write_enable) begin
|
||||
data_array[write_index] <= write_data;
|
||||
end
|
||||
|
||||
if (meta_tag_write_enable) begin
|
||||
meta_tag_array[write_index] <= write_meta_tag;
|
||||
end
|
||||
|
||||
tag_d1 <= tag;
|
||||
index_d1 <= index;
|
||||
index_d2 <= index_d1;
|
||||
offset_d1 <= offset;
|
||||
we_d1 <= i_we;
|
||||
data_d1 <= i_data;
|
||||
|
||||
latched_we <= latched_we_next;
|
||||
latched_data <= latched_data_next;
|
||||
|
||||
eviction_count <= eviction_count_next;
|
||||
cache_miss_count <= cache_miss_count_next;
|
||||
|
||||
clear_counter <= clear_counter_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
state_next = state;
|
||||
|
||||
current_data_next = current_data;
|
||||
current_meta_tag_next = current_meta_tag;
|
||||
|
||||
read_offset_next = read_offset;
|
||||
read_index_next = read_index;
|
||||
read_address_next = read_address;
|
||||
write_address_next = write_address;
|
||||
|
||||
latched_we_next = latched_we;
|
||||
latched_data_next = latched_data;
|
||||
|
||||
o_rdy = '0;
|
||||
|
||||
o_cache_valid = '0;
|
||||
o_cache_cmd = CACHE_NONE;
|
||||
o_cache_addr = '0;
|
||||
o_cache_data = '0;
|
||||
|
||||
// vipt
|
||||
offset = i_addr[OFFSET_W-1:0];
|
||||
index = i_addr[INDEX_W+OFFSET_W-1:OFFSET_W];
|
||||
tag = i_phys_address[INDEX_W+OFFSET_W+TAG_W-1:INDEX_W+OFFSET_W];
|
||||
|
||||
write_index = '0;
|
||||
write_data = '0;
|
||||
data_write_enable = '0;
|
||||
write_meta_tag.tag = '0;
|
||||
write_meta_tag.valid = '0;
|
||||
write_meta_tag.shared = '0;
|
||||
write_meta_tag.clean = '0;
|
||||
meta_tag_write_enable = '0;
|
||||
|
||||
o_data = '0;
|
||||
|
||||
eviction_count_next = eviction_count;
|
||||
cache_miss_count_next = cache_miss_count;
|
||||
|
||||
clear_counter_next = clear_counter;
|
||||
|
||||
case (state)
|
||||
IDLE: begin
|
||||
state_next = READY;
|
||||
RESET: begin
|
||||
state_next = CLEAR;
|
||||
end
|
||||
|
||||
READY: begin
|
||||
CLEAR: begin
|
||||
if (clear_counter == (INDEX_W)'(CACHELINE_COUNT-1)) begin
|
||||
state_next = IDLE;
|
||||
end
|
||||
|
||||
write_data = '0;
|
||||
data_write_enable = '1;
|
||||
|
||||
meta_tag_write_enable = '1;
|
||||
write_meta_tag.tag = '0;
|
||||
write_meta_tag.valid = '0;
|
||||
write_meta_tag.shared = '0;
|
||||
write_meta_tag.clean = '0;
|
||||
|
||||
write_index = clear_counter;
|
||||
|
||||
clear_counter_next = clear_counter + 1;
|
||||
end
|
||||
|
||||
IDLE: begin
|
||||
state_next = READY;
|
||||
current_data_next = data_array[index];
|
||||
current_meta_tag_next = meta_tag_array[index];
|
||||
o_rdy = '1;
|
||||
end
|
||||
|
||||
EVICT: begin
|
||||
READY: begin
|
||||
if (!current_meta_tag.valid || (current_meta_tag.valid && current_meta_tag.tag != tag_d1 && current_meta_tag.clean)) begin
|
||||
// current line is not valid, just read
|
||||
// OR current line is valid, but clean so we don't need to write it back.
|
||||
state_next = READ;
|
||||
|
||||
read_index_next = index_d1;
|
||||
read_offset_next = offset_d1;
|
||||
read_address_next = {i_phys_address[31:OFFSET_W], (OFFSET_W)'('0)};
|
||||
|
||||
latched_we_next = we_d1;
|
||||
latched_data_next = data_d1;
|
||||
|
||||
cache_miss_count_next = cache_miss_count + 1;
|
||||
end else if (current_meta_tag.valid && current_meta_tag.tag != tag_d1 && !current_meta_tag.clean) begin
|
||||
// current line was valid, but the wrong tag.
|
||||
state_next = EVICT;
|
||||
|
||||
read_index_next = index_d1;
|
||||
read_offset_next = offset_d1;
|
||||
read_address_next = {i_phys_address[31:OFFSET_W], (OFFSET_W)'('0)};
|
||||
write_address_next = {current_meta_tag.tag, index_d1, (OFFSET_W)'('0)};
|
||||
|
||||
latched_we_next = we_d1;
|
||||
latched_data_next = data_d1;
|
||||
|
||||
cache_miss_count_next = cache_miss_count + 1;
|
||||
eviction_count_next = eviction_count + 1;
|
||||
end else begin
|
||||
latched_we_next = i_we;
|
||||
latched_data_next = i_data;
|
||||
|
||||
// always be loading the next data array
|
||||
current_data_next = data_array[index];
|
||||
current_meta_tag_next = meta_tag_array[index];
|
||||
|
||||
// We are accessing something we just wrote to
|
||||
|
||||
if (latched_we) begin
|
||||
write_data = current_data;
|
||||
|
||||
write_data[offset_d1*8 +: 8] = latched_data;
|
||||
data_write_enable = '1;
|
||||
|
||||
meta_tag_write_enable = '1;
|
||||
write_meta_tag = current_meta_tag;
|
||||
write_meta_tag.clean = '0;
|
||||
|
||||
write_index = index_d1;
|
||||
|
||||
if (index == write_index) begin
|
||||
current_data_next = write_data;
|
||||
end
|
||||
end else begin
|
||||
// we have a possible RAW hazard, but not after READ state
|
||||
if (prev_state == READY && index_d1 == index_d2) begin
|
||||
o_data = current_data[offset_d1*8 +: 8];
|
||||
end else begin
|
||||
o_data = current_data[offset_d1*8 +: 8];
|
||||
end
|
||||
end
|
||||
|
||||
o_rdy = '1;
|
||||
end
|
||||
end
|
||||
|
||||
EVICT: begin
|
||||
o_cache_addr = write_address;
|
||||
o_cache_cmd = CACHE_WRITE;
|
||||
o_cache_valid = '1;
|
||||
o_cache_data = current_data;
|
||||
|
||||
if (i_cache_rdy) begin
|
||||
state_next = READ;
|
||||
end
|
||||
end
|
||||
|
||||
READ: begin
|
||||
o_cache_addr = read_address;
|
||||
o_cache_cmd = CACHE_READ;
|
||||
o_cache_valid = '1;
|
||||
|
||||
write_index = read_index;
|
||||
write_data = i_cache_data;
|
||||
write_meta_tag.tag = read_address[31:INDEX_W+OFFSET_W];
|
||||
write_meta_tag.valid = '1;
|
||||
write_meta_tag.shared = '0;
|
||||
write_meta_tag.clean = ~latched_we; // if we are about to write, then mark dirty
|
||||
|
||||
data_write_enable = i_cache_rdy;
|
||||
meta_tag_write_enable = i_cache_rdy;
|
||||
|
||||
if (i_cache_rdy) begin
|
||||
state_next = READY;
|
||||
current_data_next = i_cache_data;
|
||||
current_meta_tag_next = write_meta_tag;
|
||||
|
||||
index = write_index;
|
||||
tag = read_address[31:INDEX_W+OFFSET_W];
|
||||
offset = read_offset;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
state_next = READY;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
@@ -101,6 +345,20 @@ end
|
||||
|
||||
One thing that we also need is an MMU. The TLB can be 1 cycle, then if the TLB
|
||||
says that we are allowed to read from the cache, we can read from the cache.
|
||||
|
||||
how do we handle writes? Since we take 1 cycle to read from the cache, we cannot
|
||||
immediately write to the cache line in one cycle, we will have to wait a cycle
|
||||
in order to determine if the cacheline is valid or not. To do this, we will need
|
||||
to have it be pipelined, so that we store the data temporarily while we read the
|
||||
meta_tag array, then if its valid we write to the cache. To avoid RAW hazards, we
|
||||
also need to store the address and check if we are reading a value we just wrote.
|
||||
If so, then we return this stored value instead of reading from ram, since we would
|
||||
be reading at the same time as we are writing, and that could be undefined.
|
||||
|
||||
basically if the index matches the previous access, then we have a hazard and need to
|
||||
use the stored cacheline instead of the cacheline we read from memory, since that hasn't
|
||||
been updated yet. We don't need to cache metatag since if we just wrote to it, it will
|
||||
already be dirty anyway.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -10,4 +10,10 @@ package application_wrapper_cache_pkg;
|
||||
logic write_through;
|
||||
} page_table_entry_t;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
CACHE_NONE,
|
||||
CACHE_READ,
|
||||
CACHE_WRITE
|
||||
} cache_cmd_e;
|
||||
|
||||
endpackage
|
||||
Reference in New Issue
Block a user