0% found this document useful (0 votes)
56 views6 pages

Cache Controller

This document describes a cache controller module that interfaces between a CPU and main memory. It contains a cache with tag and data memories. The cache controller handles cache hits, reads and writes from the CPU, and interactions with main memory for cache misses, including handling dirty data on write-backs. The module uses finite state machines to control its operation in different states such as comparing tags, allocating new cache blocks, and writing back dirty data.

Uploaded by

balu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
56 views6 pages

Cache Controller

This document describes a cache controller module that interfaces between a CPU and main memory. It contains a cache with tag and data memories. The cache controller handles cache hits, reads and writes from the CPU, and interactions with main memory for cache misses, including handling dirty data on write-backs. The module uses finite state machines to control its operation in different states such as comparing tags, allocating new cache blocks, and writing back dirty data.

Uploaded by

balu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

module cache_controller2 (

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
);

parameter IDLE = 2'b00;


parameter COMPARE_TAG = 2'b01;
parameter ALLOCATE = 2'b10;
parameter WRITE_BACK = 2'b11;

input clk;
input rst_n;

//CPU request to cache controller


input [31:0] cpu_req_addr;
input [127:0] cpu_req_datain;
output [31:0] cpu_req_dataout;
input cpu_req_rw; //1=write, 0=read
input cpu_req_valid;

//Main memory request from cache controller


output [31:0] mem_req_addr;
input [127:0] mem_req_datain;
output [31:0] mem_req_dataout;
output mem_req_rw;
output mem_req_valid;
input mem_req_ready;

//Cache ready
output cache_ready;

//Cache consists of tag memory and data memory


//Tag memory = valid bit + dirty bit + tag
reg [23:0] tag_mem [1023:0];
//Data memory holds the actual data in cache
reg [127:0] data_mem [1023:0];

reg [1:0] present_state, next_state;


reg [31:0] cpu_req_dataout, next_cpu_req_dataout;
reg [31:0] cache_read_data;
reg cache_ready, next_cache_ready;
reg [31:0] mem_req_addr, next_mem_req_addr;
reg mem_req_rw, next_mem_req_rw;
reg mem_req_valid, next_mem_req_valid;
reg [127:0] mem_req_dataout, next_mem_req_dataout;
reg write_datamem_mem; //write operation from memory
reg write_datamem_cpu; //write operation from cpu
reg tagmem_enable;
reg valid_bit, dirty_bit;

reg [31:0] cpu_req_addr_reg, next_cpu_req_addr_reg;


reg [127:0] cpu_req_datain_reg, next_cpu_req_datain_reg;
reg cpu_req_rw_reg, next_cpu_req_rw_reg;

wire [17:0] cpu_addr_tag;


wire [9:0] cpu_addr_index;
wire [1:0] cpu_addr_blk_offset;
wire [1:0] cpu_addr_byte_offset;
wire [19:0] tag_mem_entry;
wire [127:0] data_mem_entry;
wire hit;

//CPU Address = tag + index + block offset + byte offset


assign cpu_addr_tag = cpu_req_addr_reg[31:14];
assign cpu_addr_index = cpu_req_addr_reg[13:4];
assign cpu_addr_blk_offset = cpu_req_addr_reg[3:2];
assign cpu_addr_byte_offset = cpu_req_addr_reg[1:0];

assign tag_mem_entry = tag_mem[cpu_addr_index];


assign data_mem_entry = data_mem[cpu_addr_index];
assign hit = tag_mem_entry[19] && (cpu_addr_tag == tag_mem_entry[17:0]);

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 @ (posedge clk or negedge rst_n)


begin
if(!rst_n)
begin
tag_mem[cpu_addr_index] <= tag_mem[cpu_addr_index];
data_mem[cpu_addr_index] <= data_mem[cpu_addr_index];
present_state <= IDLE;
cpu_req_dataout <= 32'd0;
cache_ready <= 1'b0;
mem_req_addr <= 32'd0;
mem_req_rw <= 1'b0;
mem_req_valid <= 1'b0;
mem_req_dataout <= 128'd0;
cpu_req_addr_reg <= 1'b0;
cpu_req_datain_reg <= 128'd0;
cpu_req_rw_reg <= 1'b0;
end
else
begin
tag_mem[cpu_addr_index] <= tagmem_enable ?
{4'd0,valid_bit,dirty_bit,cpu_addr_tag} : tag_mem[cpu_addr_index];
data_mem[cpu_addr_index] <= write_datamem_mem ? mem_req_datain :
write_datamem_cpu ? cpu_req_datain_reg : data_mem[cpu_addr_index];
present_state <= next_state;
cpu_req_dataout <= next_cpu_req_dataout;
cache_ready <= next_cache_ready;
mem_req_addr <= next_mem_req_addr;
mem_req_rw <= next_mem_req_rw;
mem_req_valid <= next_mem_req_valid;
mem_req_dataout <= next_mem_req_dataout;
cpu_req_addr_reg <= next_cpu_req_addr_reg;
cpu_req_datain_reg <= next_cpu_req_datain_reg;
cpu_req_rw_reg <= next_cpu_req_rw_reg;
end
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;

wire [31:0] mem_req_addr;


reg [127:0] mem_req_datain;
wire [127:0] mem_req_dataout;
wire mem_req_rw;
wire mem_req_valid;
reg mem_req_ready;

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)
);

always #5 clk = ~clk;

task reset_values ();


begin
clk = 1'b1; rst_n = 1'b0;
cpu_req_addr = 32'd0; cpu_req_datain = 128'd0; cpu_req_rw = 1'b0; cpu_req_valid =
1'b0;
mem_req_datain = 128'd0; mem_req_ready = 1'b1;
#20 rst_n = 1'b1;
end
endtask

task write_cpu (input [31:0]addr, input [127:0]data);


begin
#20 cpu_req_addr = addr; cpu_req_rw = 1'b1; cpu_req_valid = 1'b1; cpu_req_datain
= data; //write to cache (AB)
#10 cpu_req_addr = 32'd0; cpu_req_rw = 1'b0; cpu_req_valid = 1'b0; cpu_req_datain
= 128'd0;
end
endtask

task read_cpu (input [31:0]addr);


begin
#20 cpu_req_addr = addr; cpu_req_rw = 1'b0; cpu_req_valid = 1'b1;
#10 cpu_req_addr = 32'd0; cpu_req_rw = 1'b0; cpu_req_valid = 1'b0;
end
endtask

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;

read_cpu (32'hEB00); //read miss, dirty (diff tag, same index)


@(negedge mem_req_valid) mem_req_ready = 1'b0;
#20 mem_req_ready = 1'b1;
@(negedge mem_req_valid) mem_req_ready = 1'b0;
#30 mem_req_datain = 128'h5566; mem_req_ready = 1'b1;
end
endmodule

You might also like