How to Model RAM in Verilog: Syntax and Example
To model
RAM in Verilog, use a reg array to represent memory locations and implement read/write logic inside an always block triggered by clock edges. Use an address input to select memory locations and control signals like we (write enable) to manage data storage.Syntax
Modeling RAM in Verilog typically involves declaring a reg array to hold data, an address input to select memory cells, and control signals like write enable (we) and clock (clk). The always @(posedge clk) block is used to update memory on clock edges.
reg [DATA_WIDTH-1:0] mem_array [0:DEPTH-1];: Declares the memory array.input [ADDR_WIDTH-1:0] addr;: Address input to select memory location.input we;: Write enable signal.input clk;: Clock signal for synchronous operation.always @(posedge clk): Block to handle read/write on clock edge.
verilog
module ram_model (
input wire clk,
input wire we,
input wire [3:0] addr,
input wire [7:0] data_in,
output reg [7:0] data_out
);
reg [7:0] mem_array [0:15]; // 16 locations of 8-bit RAM
always @(posedge clk) begin
if (we) begin
mem_array[addr] <= data_in; // Write data
end
data_out <= mem_array[addr]; // Read data
end
endmoduleExample
This example shows a simple 16x8 RAM module with synchronous read and write. When we is high at the clock's rising edge, the input data is stored at the given address. The output always shows the data at the current address.
verilog
module testbench();
reg clk = 0;
reg we;
reg [3:0] addr;
reg [7:0] data_in;
wire [7:0] data_out;
ram_model ram (
.clk(clk),
.we(we),
.addr(addr),
.data_in(data_in),
.data_out(data_out)
);
always #5 clk = ~clk; // 10 time units clock period
initial begin
// Write 8'hAA to address 3
we = 1; addr = 4'd3; data_in = 8'hAA;
#10;
// Write 8'h55 to address 7
addr = 4'd7; data_in = 8'h55;
#10;
// Disable write, read address 3
we = 0; addr = 4'd3;
#10;
$display("Read from addr 3: %h", data_out);
// Read address 7
addr = 4'd7;
#10;
$display("Read from addr 7: %h", data_out);
$finish;
end
endmoduleOutput
Read from addr 3: aa
Read from addr 7: 55
Common Pitfalls
Common mistakes when modeling RAM in Verilog include:
- Using blocking assignments (
=) instead of non-blocking (<=) insidealways @(posedge clk)blocks, which can cause simulation mismatches. - Not synchronizing read and write operations to the clock, leading to glitches.
- Forgetting to declare the memory array size correctly, causing synthesis errors.
- Reading and writing the same address without proper timing, which can cause unexpected data.
verilog
/* Wrong way: blocking assignment in clocked block */ always @(posedge clk) begin if (we) begin mem_array[addr] = data_in; // Wrong: blocking assignment end data_out = mem_array[addr]; end /* Right way: non-blocking assignment */ always @(posedge clk) begin if (we) begin mem_array[addr] <= data_in; // Correct: non-blocking end data_out <= mem_array[addr]; end
Quick Reference
- Use
reg [width-1:0] mem_array [0:depth-1];to declare RAM. - Use
always @(posedge clk)for synchronous read/write. - Use non-blocking assignments (
<=) inside clocked blocks. - Control writes with a
we(write enable) signal. - Read data is usually registered on clock edge for stability.
Key Takeaways
Model RAM using a reg array with synchronous read/write inside an always @(posedge clk) block.
Use non-blocking assignments (<=) for memory updates to avoid simulation issues.
Control writes with a write enable (we) signal to prevent unintended data changes.
Declare memory size clearly with address and data widths matching your design.
Always test RAM behavior with a testbench to verify read and write operations.