Bird
Raised Fist0
Verilogprogramming~5 mins

Single-port RAM design in Verilog

Choose your learning style10 modes available
Introduction

Single-port RAM lets you store and read data using one address at a time. It helps save space and is simple to use in hardware designs.

When you need a small memory block to store data temporarily in a digital circuit.
When your design only needs to read or write one data item at a time.
When you want to save hardware resources by using one port for both reading and writing.
When building simple processors or controllers that use memory.
When you want to learn how memory works inside digital chips.
Syntax
Verilog
module single_port_ram #(
    parameter DATA_WIDTH = 8,
    parameter ADDR_WIDTH = 4
) (
    input wire clk,
    input wire we,          // write enable
    input wire [ADDR_WIDTH-1:0] addr,
    input wire [DATA_WIDTH-1:0] din,
    output reg [DATA_WIDTH-1:0] dout
);

    // Declare memory array
    reg [DATA_WIDTH-1:0] ram [0:(1<<ADDR_WIDTH)-1];

    always @(posedge clk) begin
        if (we) begin
            ram[addr] <= din;  // Write data
        end
        dout <= ram[addr];     // Read data
    end

endmodule

The clk input controls when data is read or written.

The we signal decides if the memory writes new data or just reads.

Examples
This example shows an 8-bit wide RAM with 16 addresses.
Verilog
module ram_example (
    input wire clk,
    input wire we,
    input wire [3:0] addr,
    input wire [7:0] din,
    output reg [7:0] dout
);

    reg [7:0] ram [0:15];

    always @(posedge clk) begin
        if (we) ram[addr] <= din;
        dout <= ram[addr];
    end

endmodule
This example uses 4-bit data width and 16 addresses.
Verilog
module ram_16x4 (
    input wire clk,
    input wire we,
    input wire [3:0] addr,
    input wire [3:0] din,
    output reg [3:0] dout
);

    reg [3:0] ram [0:15];

    always @(posedge clk) begin
        if (we) ram[addr] <= din;
        dout <= ram[addr];
    end

endmodule
Sample Program

This testbench writes values to addresses 3 and 7, then reads them back and prints the results. It also reads an address that was never written to show default zero.

Verilog
module testbench();
    reg clk = 0;
    reg we;
    reg [3:0] addr;
    reg [7:0] din;
    wire [7:0] dout;

    // Instantiate RAM
    single_port_ram ram (
        .clk(clk),
        .we(we),
        .addr(addr),
        .din(din),
        .dout(dout)
    );

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

    initial begin
        // Write 42 at address 3
        we = 1; addr = 4'd3; din = 8'd42;
        #10;

        // Write 100 at address 7
        addr = 4'd7; din = 8'd100;
        #10;

        // Stop writing, read address 3
        we = 0; addr = 4'd3;
        #10;
        $display("Read from addr 3: %d", dout);

        // Read address 7
        addr = 4'd7;
        #10;
        $display("Read from addr 7: %d", dout);

        // Read address 0 (not written, default 0)
        addr = 4'd0;
        #10;
        $display("Read from addr 0: %d", dout);

        $finish;
    end
endmodule

module single_port_ram (
    input wire clk,
    input wire we,
    input wire [3:0] addr,
    input wire [7:0] din,
    output reg [7:0] dout
);
    reg [7:0] ram [0:15];

    always @(posedge clk) begin
        if (we) ram[addr] <= din;
        dout <= ram[addr];
    end
endmodule
OutputSuccess
Important Notes

Reading and writing happen on the clock's rising edge.

If you read an address that was never written, it usually returns zero or unknown depending on your simulator.

Single-port RAM can only read or write one address per clock cycle.

Summary

Single-port RAM stores data with one address line for both reading and writing.

Use a clock and write enable signal to control memory operations.

This design is simple and saves hardware but can only do one operation at a time.

Practice

(1/5)
1. What is the main characteristic of a single-port RAM in Verilog?
easy
A. It stores data without any clock or control signals.
B. It can read and write data simultaneously on separate ports.
C. It uses one address line for both reading and writing operations.
D. It requires two clocks for read and write operations.

Solution

  1. Step 1: Understand single-port RAM basics

    Single-port RAM has only one address line used for both reading and writing data.
  2. Step 2: Compare with other RAM types

    Unlike dual-port RAM, it cannot perform read and write simultaneously on different ports.
  3. Final Answer:

    It uses one address line for both reading and writing operations. -> Option C
  4. Quick Check:

    Single-port RAM = one address line for read/write [OK]
Hint: Single-port RAM uses one address for both read and write [OK]
Common Mistakes:
  • Thinking it can read and write at the same time
  • Assuming it needs two clocks
  • Believing it works without a clock
2. Which of the following is the correct Verilog syntax to declare a 256x8 single-port RAM memory array?
easy
A. wire [7:0] mem [255:0];
B. memory [7:0] mem [0:255];
C. reg mem [7:0] [0:255];
D. reg [7:0] mem [0:255];

Solution

  1. Step 1: Understand Verilog memory declaration

    Memory arrays are declared as reg [width-1:0] name [address_range]; for RAM.
  2. Step 2: Check each option

    reg [7:0] mem [0:255]; correctly declares 256 locations (0 to 255) each 8 bits wide. wire [7:0] mem [255:0]; uses wire which is incorrect for RAM storage. reg mem [7:0] [0:255]; reverses dimensions. memory [7:0] mem [0:255]; uses invalid keyword.
  3. Final Answer:

    reg [7:0] mem [0:255]; -> Option D
  4. Quick Check:

    RAM declaration = reg [7:0] mem [0:255] [OK]
Hint: Use reg with [width-1:0] and address range [OK]
Common Mistakes:
  • Using wire instead of reg for RAM
  • Swapping width and address range
  • Using invalid keywords like memory
3. Given the following Verilog code snippet for a single-port RAM, what is the value of data_out after the clock edge if we = 1, addr = 3, and data_in = 8'hAA?
reg [7:0] mem [0:7];
always @(posedge clk) begin
  if (we) mem[addr] <= data_in;
  data_out <= mem[addr];
end
medium
A. 8'hAA
B. Previous value stored at mem[3]
C. 8'h00
D. Undefined (X)

Solution

  1. Step 1: Analyze write and read order in always block

    The write happens first: if we=1, mem[3] is updated with 8'hAA. Then data_out is assigned mem[3].
  2. Step 2: Understand non-blocking assignment timing

    Non-blocking assignments update after the always block finishes, so data_out reads the old value of mem[3] before write.
  3. Final Answer:

    Previous value stored at mem[3] -> Option B
  4. Quick Check:

    Non-blocking write then read = old value [OK]
Hint: Non-blocking writes update after reads in same clock [OK]
Common Mistakes:
  • Assuming data_out immediately shows new data_in
  • Confusing blocking and non-blocking assignments
  • Ignoring timing of memory update
4. Identify the error in this single-port RAM Verilog code snippet:
reg [7:0] mem [0:15];
always @(posedge clk) begin
  if (we)
    mem[addr] = data_in;
  else
    data_out = mem[addr];
end
medium
A. Using blocking assignments (=) instead of non-blocking (<=) inside always block.
B. Memory size declaration is incorrect.
C. Missing reset signal for memory initialization.
D. Address width is not declared.

Solution

  1. Step 1: Check assignment types in sequential always block

    Inside clocked always blocks, non-blocking assignments (<=) should be used to avoid race conditions.
  2. Step 2: Verify other code parts

    Memory size and address width are not shown but not necessarily errors here. Reset is optional.
  3. Final Answer:

    Using blocking assignments (=) instead of non-blocking (<=) inside always block. -> Option A
  4. Quick Check:

    Use <= in clocked always blocks [OK]
Hint: Use <= for sequential logic inside always @(posedge clk) [OK]
Common Mistakes:
  • Using = instead of <= in clocked blocks
  • Assuming reset is mandatory
  • Ignoring address width declaration
5. You want to design a single-port RAM in Verilog that supports synchronous write and asynchronous read. Which code snippet correctly implements this behavior?
hard
A.
reg [7:0] mem [0:15];
always @(posedge clk) begin
  if (we) mem[addr] <= data_in;
end
assign data_out = mem[addr];
B.
reg [7:0] mem [0:15];
always @(posedge clk) begin
  if (we) mem[addr] <= data_in;
  data_out <= mem[addr];
end
C.
reg [7:0] mem [0:15];
always @(addr or we or data_in) begin
  if (we) mem[addr] = data_in;
end
assign data_out = mem[addr];
D.
reg [7:0] mem [0:15];
always @(posedge clk) begin
  if (we) mem[addr] = data_in;
end
always @(addr) begin
  data_out = mem[addr];
end

Solution

  1. Step 1: Understand synchronous write and asynchronous read

    Write happens on clock edge with write enable; read happens anytime from memory asynchronously.
  2. Step 2: Analyze each code snippet

    reg [7:0] mem [0:15];
    always @(posedge clk) begin
      if (we) mem[addr] <= data_in;
    end
    assign data_out = mem[addr];
    uses clocked always block for write and continuous assignment for asynchronous read, which is correct.
    reg [7:0] mem [0:15];
    always @(posedge clk) begin
      if (we) mem[addr] <= data_in;
      data_out <= mem[addr];
    end
    reads synchronously.
    reg [7:0] mem [0:15];
    always @(addr or we or data_in) begin
      if (we) mem[addr] = data_in;
    end
    assign data_out = mem[addr];
    uses combinational always block for write, which is incorrect.
    reg [7:0] mem [0:15];
    always @(posedge clk) begin
      if (we) mem[addr] = data_in;
    end
    always @(addr) begin
      data_out = mem[addr];
    end
    uses blocking assignment in clocked block and asynchronous read in always block, which is not standard.
  3. Final Answer:

    Option A code snippet -> Option A
  4. Quick Check:

    Synchronous write + async read = clocked write + assign read [OK]
Hint: Use clocked block for write, continuous assign for async read [OK]
Common Mistakes:
  • Reading memory synchronously instead of asynchronously
  • Using blocking assignments in clocked blocks
  • Trying to write memory combinationally
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard