Cache Controller
Cache Controller
clk,
rst_n,
cpu_req_addr, //CPU signals
cpu_req_datain,
cpu_req_dataout,
cpu_req_rw,
cpu_req_valid,
cache_ready, //Cache ready
mem_req_addr, //Main memory signals
mem_req_datain,
mem_req_dataout,
mem_req_rw,
mem_req_valid,
mem_req_ready
);
input clk;
input rst_n;
//Cache ready
output cache_ready;
initial begin
$readmemh("tag_memory.mem", tag_mem); //load initial values for tag memory
end
initial begin
$readmemh("data_memory.mem", data_mem); //load initial values for data memory
end
always @ (*)
begin
write_datamem_mem = 1'b0;
write_datamem_cpu = 1'b0;
valid_bit = 1'b0;
dirty_bit = 1'b0;
tagmem_enable = 1'b0;
next_state = present_state;
next_cpu_req_dataout = cpu_req_dataout;
next_cache_ready = 1'b1;
next_mem_req_addr = mem_req_addr;
next_mem_req_rw = mem_req_rw;
next_mem_req_valid = mem_req_valid;
next_mem_req_dataout = mem_req_dataout;
next_cpu_req_addr_reg = cpu_req_addr_reg;
next_cpu_req_datain_reg = cpu_req_datain_reg;
next_cpu_req_rw_reg = cpu_req_rw_reg;
case (cpu_addr_blk_offset)
2'b00: cache_read_data = data_mem_entry[31:0];
2'b01: cache_read_data = data_mem_entry[63:32];
2'b10: cache_read_data = data_mem_entry[95:64];
2'b11: cache_read_data = data_mem_entry[127:96];
default: cache_read_data = 32'd0;
endcase
case(present_state)
IDLE:
begin
if (cpu_req_valid)
begin
next_cpu_req_addr_reg = cpu_req_addr;
next_cpu_req_datain_reg = cpu_req_datain;
next_cpu_req_rw_reg = cpu_req_rw;
next_cache_ready = 1'b0;
next_state = COMPARE_TAG;
end
else
next_state = present_state;
end
COMPARE_TAG:
begin
if (hit & !cpu_req_rw_reg) //read hit
begin
next_cpu_req_dataout = cache_read_data;
next_state = IDLE;
end
else if (!cpu_req_rw_reg) //read miss
begin
next_cache_ready = 1'b0;
if (!tag_mem_entry[18]) //clean, read new block from memory
begin
next_mem_req_addr = cpu_req_addr_reg;
next_mem_req_rw = 1'b0;
next_mem_req_valid = 1'b1;
next_state = ALLOCATE;
end
else //dirty, write cache block to old
memory address, then read this block with curr addr
begin
next_mem_req_addr = {tag_mem_entry[17:0],cpu_addr_index,4'd0}; //old tag,
current index, offset 00
next_mem_req_dataout = data_mem_entry;
next_mem_req_rw = 1'b1;
next_mem_req_valid = 1'b1;
next_state = WRITE_BACK;
end
end
else //write operation
begin
valid_bit = 1'b1;
dirty_bit = 1'b1;
tagmem_enable = 1'b1;
write_datamem_cpu = 1'b1;
next_state = IDLE;
end
end
ALLOCATE:
begin
next_mem_req_valid = 1'b0;
next_cache_ready = 1'b0;
if(!mem_req_valid && mem_req_ready) //wait for memory to be ready with read
data
begin
write_datamem_mem = 1'b1; //write to data mem
valid_bit = 1'b1; //make the tag mem entry valid
dirty_bit = 1'b0;
tagmem_enable = 1'b1;
next_state = COMPARE_TAG;
end
else
begin
next_state = present_state;
end
end
WRITE_BACK:
begin
next_cache_ready = 1'b0;
next_mem_req_valid = 1'b0;
if(!mem_req_valid && mem_req_ready) //write is done, now read
begin
valid_bit = 1'b1;
dirty_bit = 1'b0;
tagmem_enable = 1'b1;
next_mem_req_addr = cpu_req_addr_reg;
next_mem_req_rw = 1'b0;
next_mem_req_valid = 1'b1;
next_state = ALLOCATE;
end
else
begin
next_state = present_state;
end
end
endcase
end
endmodule
module cache_controller2_tb;
reg clk;
reg rst_n;
reg [31:0] cpu_req_addr;
reg [127:0] cpu_req_datain;
wire [31:0] cpu_req_dataout;
reg cpu_req_rw; //1=write, 0=read
reg cpu_req_valid;
cache_controller2 dut (
.clk (clk),
.rst_n (rst_n),
.cpu_req_addr (cpu_req_addr),
.cpu_req_datain (cpu_req_datain),
.cpu_req_dataout (cpu_req_dataout),
.cpu_req_rw (cpu_req_rw),
.cpu_req_valid (cpu_req_valid),
.cache_ready (cache_ready),
.mem_req_addr (mem_req_addr),
.mem_req_datain (mem_req_datain),
.mem_req_dataout (mem_req_dataout),
.mem_req_rw (mem_req_rw),
.mem_req_valid (mem_req_valid),
.mem_req_ready (mem_req_ready)
);
initial begin
reset_values();
write_cpu (332'hAB00,128'h1122); //write
read_cpu (32'hAB00); //read hit (same tag, same index)
read_cpu (32'hBB00); //read miss, clean (same tag, diff index)
@(negedge mem_req_valid) mem_req_ready = 1'b0;
#20 mem_req_datain = 128'h3344; mem_req_ready = 1'b1;