0% found this document useful (0 votes)
10 views17 pages

Memory Controller Design Overview

The document outlines the design of a memory controller that manages a cache memory system with a Least Recently Used (LRU) page replacement policy. It includes a block diagram, detailed descriptions of components, Verilog code for the memory controller and its testbench, and simulation results demonstrating its functionality. The controller handles memory accesses, cache hits and misses, and updates the cache accordingly, with test results confirming correct operations.

Uploaded by

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

Memory Controller Design Overview

The document outlines the design of a memory controller that manages a cache memory system with a Least Recently Used (LRU) page replacement policy. It includes a block diagram, detailed descriptions of components, Verilog code for the memory controller and its testbench, and simulation results demonstrating its functionality. The controller handles memory accesses, cache hits and misses, and updates the cache accordingly, with test results confirming correct operations.

Uploaded by

Kunal Khare
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Memory Controller Design

Problem statement:
 Main memory has 64 pages, 1 KB each.
 Cache memory has 8 pages.
 Page replacement policy is Least Recently Used (LRU).

Block Diagram:
Description of blocks:
 CPU Address Bus: Sends 16-bit addresses to the memory controller.
 Address Decoder: Splits the address into a 6-bit page number and 10-bit
offset.
 Cache Tag Array: Stores the valid bits and page numbers for 8 cache slots.
 Tag Comparator: Checks if the requested page is in the cache (hit/miss).
 LRU Replacement Unit: Tracks usage to select the least recently used slot
for replacement on a miss.
 Cache Data RAM: Stores the actual page data (8 pages × 1 KB each).
 Main Memory Interface: Connects to main memory (64 pages × 1 KB),
handles page loading on cache miss.

Operation:
 On every memory access, the address decoder extracts the page number
and offset.
 The tag comparator checks the cache tag array for a valid match.
o If hit: Data is served directly from cache.
o If miss:
 The LRU unit chooses the least recently used slot.
 The required page is fetched from main memory.
 Cache is updated with the new page.
 LRU order is updated.
Address Breakdown:
 16-bit address:
o Page Number = upper 6 bits (address[15:10])
o Offset = lower 10 bits (address[9:0])
Verilog Module:
module MemoryController(
input clk,
input reset,
input [15:0] cpu_addr,
input cpu_rd,
input cpu_wr,
input [7:0] cpu_wdata,
output reg [7:0] cpu_rdata,
output reg cpu_stall,

output reg [15:0] mem_addr,


output reg mem_rd,
input [7:0] mem_rdata
);

localparam CACHE_LINES = 8;
localparam PAGE_SIZE = 1024;

// Address decoding
wire [5:0] page_num = cpu_addr[15:10];
wire [9:0] offset = cpu_addr[9:0];
// Cache tags and valid bits
reg [5:0] tags [0:CACHE_LINES-1];
reg valid [0:CACHE_LINES-1];

// LRU matrix
reg [CACHE_LINES-1:0] lru_matrix [0:CACHE_LINES-1];

// Cache RAM: 8 pages of 1K bytes each


reg [7:0] cache_data [0:CACHE_LINES*PAGE_SIZE-1];

// FSM states
typedef enum reg [1:0] {IDLE, MISS_READ} state_t;
state_t state;

// Internal control
reg [2:0] hit_index;
reg hit;
reg [2:0] victim_index;
reg [5:0] miss_page;
reg [9:0] fill_counter;
reg [2:0] fill_slot;
reg [9:0] next_fill_counter;

integer i, j;

// HIT detection
always @(*) begin
hit = 0;
hit_index = 0;
for (i = 0; i < CACHE_LINES; i = i + 1) begin
if (valid[i] && tags[i] == page_num) begin
hit = 1;
hit_index = i[2:0];
end
end
end

// LRU victim selection


always @(*) begin
victim_index = 0;
for (i = 0; i < CACHE_LINES; i = i + 1) begin
if (lru_matrix[i] == 8'b0) begin
victim_index = i[2:0];
end
end
end

// LRU update
task automatic update_lru(input [2:0] accessed);
begin
for (j = 0; j < CACHE_LINES; j = j + 1) begin
if (j != accessed) begin
lru_matrix[accessed][j] <= 1;
lru_matrix[j][accessed] <= 0;
end
end
end
endtask

// FSM
always @(posedge clk or posedge reset) begin
if (reset) begin
cpu_stall <= 0;
cpu_rdata <= 8'h00;
state <= IDLE;
mem_rd <= 0;
mem_addr <= 0;
for (i = 0; i < CACHE_LINES; i = i + 1) begin
valid[i] <= 0;
lru_matrix[i] <= 8'b0;
end
end
else begin
case (state)
IDLE: begin
cpu_stall <= 0;
mem_rd <= 0;
if (cpu_rd || cpu_wr) begin
if (hit) begin
// Cache HIT
if (cpu_rd) begin
cpu_rdata <= cache_data[{hit_index, offset}];
end
if (cpu_wr) begin
cache_data[{hit_index, offset}] <= cpu_wdata;
end
update_lru(hit_index);
end
else begin
// Cache MISS
cpu_stall <= 1;
miss_page <= page_num;
fill_slot <= victim_index;
fill_counter <= 0;

mem_rd <= 1;
mem_addr <= {page_num, 10'b0};
state <= MISS_READ;
end
end
end

MISS_READ: begin
// Load one byte from main memory into cache
cache_data[{fill_slot, fill_counter}] <= mem_rdata;
fill_counter <= fill_counter + 1;

if (fill_counter < PAGE_SIZE - 1) begin


mem_rd <= 1;
next_fill_counter = fill_counter + 1;
mem_addr <= {miss_page, next_fill_counter};
end
else begin
mem_rd <= 0;
valid[fill_slot] <= 1;
tags[fill_slot] <= miss_page;
update_lru(fill_slot);
cpu_stall <= 0;
state <= IDLE;
end
end

default: state <= IDLE;


endcase
end
end

endmodule
Testbench Code:

module MemoryController_tb;

// DUT signals
reg clk;
reg reset;
reg [15:0] cpu_addr;
reg cpu_rd;
reg cpu_wr;
reg [7:0] cpu_wdata;
wire [7:0] cpu_rdata;
wire cpu_stall;

wire [15:0] mem_addr;


wire mem_rd;
wire [7:0] mem_rdata;

// Main memory model (64K)


reg [7:0] main_memory [0:65535];

// Instantiate DUT
MemoryController uut (
.clk(clk),
.reset(reset),
.cpu_addr(cpu_addr),
.cpu_rd(cpu_rd),
.cpu_wr(cpu_wr),
.cpu_wdata(cpu_wdata),
.cpu_rdata(cpu_rdata),
.cpu_stall(cpu_stall),
.mem_addr(mem_addr),
.mem_rd(mem_rd),
.mem_rdata(mem_rdata)
);

// Clock generation
always #5 clk = ~clk;

// Connect main memory to controller


assign mem_rdata = (mem_rd) ? main_memory[mem_addr] : 8'hZZ;

initial begin
integer i; // Declare the loop variable here at start

$dumpfile("[Link]");
$dumpvars(0, MemoryController_tb);
$display("----- Starting MemoryController Testbench -----");

clk = 0;
reset = 1;
cpu_rd = 0;
cpu_wr = 0;
cpu_addr = 16'h0000;
cpu_wdata = 8'h00;

// Initialize main memory


for (i = 0; i < 65536; i = i + 1) begin
main_memory[i] = i[7:0];
end

// Reset sequence
#20;
reset = 0;

// -------------- TEST CASE 1: Read from 0x1000 (Page 16) --------------


@(negedge clk);
cpu_addr = 16'h1000;
cpu_rd = 1;
cpu_wr = 0;
@(negedge clk);
while (cpu_stall) @(negedge clk);
cpu_rd = 0;

$display("Read data at 0x1000 = %h", cpu_rdata);

// -------------- TEST CASE 2: Read from 0x2800 (Page 40) --------------


@(negedge clk);
cpu_addr = 16'h2800;
cpu_rd = 1;
cpu_wr = 0;

@(negedge clk);
while (cpu_stall) @(negedge clk);
cpu_rd = 0;

$display("Read data at 0x2800 = %h", cpu_rdata);

// -------------- TEST CASE 3: Write to 0x1004, then read back --------------


@(negedge clk);
cpu_addr = 16'h1004;
cpu_rd = 0;
cpu_wr = 1;
cpu_wdata = 8'hAA;
@(negedge clk);
while (cpu_stall) @(negedge clk);
cpu_wr = 0;

// Now read it back


@(negedge clk);
cpu_addr = 16'h1004;
cpu_rd = 1;
cpu_wr = 0;

@(negedge clk);
while (cpu_stall) @(negedge clk);
cpu_rd = 0;

$display("Read back after write at 0x1004 = %h", cpu_rdata);

// -------------- Finish --------------


#20;
$display("----- Testbench complete -----");
$finish;
end

endmodule
Simulation Results:
----- Starting MemoryController Testbench -----
Read data at 0x1000 = 00
Read data at 0x2800 = 00
Read back after write at 0x1004 = aa
----- Testbench complete -----
[Link]: $finish called at 20590 (1s)
Finding VCD file...
./[Link]
[2025-07-02 17:25:19 UTC] Opening EPWave...
Done

 Reading address 0x1000 returned 0x00 (as initialized in main


memory)
 Reading address 0x2800 returned 0x00 (same)
 Writing 0xAA to 0x1004 and reading back returned 0xAA,
confirming correct cache write handling.

You might also like