Files
verilog6502/src/application_wrapper/cache/application_wrapper_cache_l1.sv

108 lines
2.9 KiB
Systemverilog

import application_wrapper_cache_pkg::*;
module application_wrapper_cache_l1 #(
parameter CACHELINE_SIZE = 64,
parameter CACHELINE_COUNT = 64,
localparam ADDR_WIDTH = 32
)(
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 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,
/* 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 [63:0] o_cache_data,
input logic [31: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.
// cache is virtually indexed, physically tagged
localparam OFFSET_W = $clog2(CACHELINE_SIZE);
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;
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];
// 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];
enum logic [1:0] {IDLE, READY, EVICT, READ} state, state_next;
always_ff @(posedge i_clk) begin
if (i_rst) begin
state <= IDLE;
end else begin
state <= state_next;
end
end
always_comb begin
state_next = state;
o_rdy = '0;
case (state)
IDLE: begin
state_next = READY;
end
READY: begin
o_rdy = '1;
end
EVICT: begin
end
READ: begin
end
endcase
end
/*
In the ready state, we read from the data array and if the line is valid
and the tag matches with the address, we present the data to the cpu.
Otherwise, we lower o_rdy and send the request to the higher level cache.
If what we read was valid but the tag didn't match, then we need to evict it.
If the line was not valid, then we don't need to evict it and can just request
the new data.
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.
*/
endmodule