0
0
VerilogHow-ToBeginner · 4 min read

How to Model ROM in Verilog: Syntax and Example

To model ROM in Verilog, you can use a case statement inside a combinational always block or initialize a reg array with fixed values. The ROM outputs stored data based on the input address without writing capability.
📐

Syntax

There are two common ways to model ROM in Verilog:

  • Using a case statement: Define an always @(*) block that outputs data based on the input address.
  • Using a memory array: Declare a reg array initialized with fixed values and read from it using the address.

Both methods create read-only memory by not allowing writes.

verilog
module rom_case(
    input wire [3:0] addr,
    output reg [7:0] data
);

always @(*) begin
    case(addr)
        4'd0: data = 8'hA1;
        4'd1: data = 8'hB2;
        4'd2: data = 8'hC3;
        4'd3: data = 8'hD4;
        default: data = 8'h00;
    endcase
end

endmodule
💻

Example

This example shows a ROM modeled as a memory array initialized with fixed values. The output data changes based on the input addr. This simulates a 16x8 ROM.

verilog
module rom_memory(
    input wire [3:0] addr,
    output reg [7:0] data
);

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

    initial begin
        rom[0] = 8'h10;
        rom[1] = 8'h20;
        rom[2] = 8'h30;
        rom[3] = 8'h40;
        rom[4] = 8'h50;
        rom[5] = 8'h60;
        rom[6] = 8'h70;
        rom[7] = 8'h80;
        rom[8] = 8'h90;
        rom[9] = 8'hA0;
        rom[10] = 8'hB0;
        rom[11] = 8'hC0;
        rom[12] = 8'hD0;
        rom[13] = 8'hE0;
        rom[14] = 8'hF0;
        rom[15] = 8'hFF;
    end

    always @(*) begin
        data = rom[addr];
    end

endmodule
⚠️

Common Pitfalls

Common mistakes when modeling ROM in Verilog include:

  • Trying to write to ROM memory, which should be read-only.
  • Not initializing the memory array, causing undefined outputs.
  • Using blocking assignments (=) incorrectly in combinational blocks instead of non-blocking (<=) or vice versa.
  • Forgetting to cover all address cases in a case statement, which can cause latches.
verilog
/* Wrong: Missing default case causes latch */
always @(*) begin
    case(addr)
        4'd0: data = 8'hAA;
        4'd1: data = 8'hBB;
        // Missing default
    endcase
end

/* Right: Include default to avoid latch */
always @(*) begin
    case(addr)
        4'd0: data = 8'hAA;
        4'd1: data = 8'hBB;
        default: data = 8'h00;
    endcase
end
📊

Quick Reference

Tips for modeling ROM in Verilog:

  • Use reg arrays with initial blocks for fixed data.
  • Use always @(*) with case for small ROMs.
  • Never include write logic to keep ROM read-only.
  • Always cover all address cases to avoid unintended latches.

Key Takeaways

Model ROM in Verilog using a case statement or initialized memory array without write logic.
Always initialize ROM contents to avoid undefined outputs.
Cover all address cases in combinational logic to prevent latches.
ROM outputs data based solely on input address and does not change during simulation.
Use non-blocking assignments carefully in combinational blocks to ensure correct behavior.