What if you could store important data once and have your circuit remember it perfectly forever?
Why ROM (Read-Only Memory) in Verilog? - Purpose & Use Cases
Imagine you need to store a fixed set of data, like a lookup table for colors or instructions, and you try to write each value manually every time your circuit runs.
Manually setting each data value every time is slow, prone to mistakes, and wastes precious hardware resources. It's like rewriting the same list over and over, risking typos and delays.
Using ROM in Verilog lets you store fixed data inside your hardware design efficiently. You write the data once, and the circuit can quickly read it anytime without errors or repeated effort.
always @(posedge clk) data <= (addr == 0) ? 8'hFF : (addr == 1) ? 8'hAA : 8'h00;
reg [7:0] rom [0:3]; initial begin rom[0] = 8'hFF; rom[1] = 8'hAA; rom[2] = 8'h55; rom[3] = 8'h00; end assign data = rom[addr];
It enables fast, reliable access to fixed data sets in hardware without rewriting or risking errors.
Think of a music player chip that stores fixed sound samples in ROM, so it can play tunes instantly without loading data each time.
Manual data setting is slow and error-prone.
ROM stores fixed data efficiently inside hardware.
ROM makes reading fixed data fast and reliable.
Practice
Solution
Step 1: Understand ROM functionality
ROM is designed to hold data that is fixed and cannot be modified during operation.Step 2: Compare with other memory types
Unlike RAM, ROM data is read-only and does not support writing during runtime.Final Answer:
To store fixed data that cannot be changed during simulation or operation -> Option AQuick Check:
ROM = fixed data storage [OK]
- Confusing ROM with RAM (read-write memory)
- Thinking ROM can perform operations
- Assuming ROM generates signals
Solution
Step 1: Identify correct ROM declaration
ROM is declared as a reg array with an initial block to assign fixed values.Step 2: Check each option
reg [7:0] rom_mem [0:3]; initial begin rom_mem[0] = 8'hAA; rom_mem[1] = 8'hBB; rom_mem[2] = 8'hCC; rom_mem[3] = 8'hDD; end uses reg array and initial block correctly. wire [7:0] rom_mem [0:3]; always @(posedge clk) rom_mem[0] <= 8'hAA; uses wire and always block incorrectly. Options C and D do not declare arrays properly.Final Answer:
reg [7:0] rom_mem [0:3]; initial begin rom_mem[0] = 8'hAA; rom_mem[1] = 8'hBB; rom_mem[2] = 8'hCC; rom_mem[3] = 8'hDD; end -> Option DQuick Check:
ROM array + initial block = reg [7:0] rom_mem [0:3]; initial begin rom_mem[0] = 8'hAA; rom_mem[1] = 8'hBB; rom_mem[2] = 8'hCC; rom_mem[3] = 8'hDD; end [OK]
- Using wire instead of reg for ROM array
- Assigning inside always block for ROM
- Not using an array for multiple ROM entries
data_out when addr = 2'b10?
module rom_example(input [1:0] addr, output reg [7:0] data_out);
always @(*) begin
case(addr)
2'b00: data_out = 8'h1A;
2'b01: data_out = 8'h2B;
2'b10: data_out = 8'h3C;
2'b11: data_out = 8'h4D;
default: data_out = 8'h00;
endcase
end
endmoduleSolution
Step 1: Locate the case for addr = 2'b10
The case statement assigns data_out = 8'h3C when addr is 2'b10.Step 2: Confirm output value
Since addr matches 2'b10, data_out will be 8'h3C.Final Answer:
8'h3C -> Option CQuick Check:
addr 2'b10 -> data_out 8'h3C [OK]
- Choosing wrong case label
- Confusing hex values
- Ignoring default case
module rom_bug(input [1:0] addr, output reg [7:0] data_out);
reg [7:0] rom_mem [0:3];
initial begin
rom_mem[0] = 8'hAA;
rom_mem[1] = 8'hBB;
rom_mem[2] = 8'hCC;
rom_mem[3] = 8'hDD;
end
always @(*) begin
data_out = rom_mem[addr];
end
endmoduleSolution
Step 1: Check ROM declaration and initialization
ROM is declared as reg array and initialized in initial block, which is correct for simulation.Step 2: Verify data output assignment
Using addr as index to read rom_mem is valid and data_out is assigned in combinational always block.Final Answer:
No error; code correctly implements ROM -> Option BQuick Check:
ROM reg array + initial + combinational read = correct [OK]
- Thinking initial block is illegal for ROM
- Confusing reg and wire for ROM arrays
- Assuming addr needs conversion
Solution
Step 1: Analyze each code snippet for ROM implementation
reg [7:0] rom [0:3]; initial begin rom[0]=8'd0; rom[1]=8'd1; rom[2]=8'd4; rom[3]=8'd9; end always @(*) data_out = rom[addr]; lacks module and always block structure; data_out assignment is incomplete. always @(addr) begin case(addr) 2'b00: data_out=8'd0; 2'b01: data_out=8'd1; 2'b10: data_out=8'd4; 2'b11: data_out=8'd9; default: data_out=8'd0; endcase end uses a case statement to output fixed squares based on addr, which is a valid ROM implementation. reg [7:0] rom [0:3]; assign rom[0]=0; assign rom[1]=1; assign rom[2]=4; assign rom[3]=9; assign data_out=rom[addr]; tries to assign values to wire array elements, which is illegal. reg [7:0] rom [0:3]; always @(posedge clk) begin rom[0]<=0; rom[1]<=1; rom[2]<=4; rom[3]<=9; end assign data_out=rom[addr]; tries to assign ROM values inside a clocked always block, which is not suitable for ROM initialization.Step 2: Confirm correct ROM behavior
always @(addr) begin case(addr) 2'b00: data_out=8'd0; 2'b01: data_out=8'd1; 2'b10: data_out=8'd4; 2'b11: data_out=8'd9; default: data_out=8'd0; endcase end correctly outputs squares for each address using a combinational case statement, matching ROM behavior.Final Answer:
always @(addr) begin case(addr) 2'b00: data_out=8'd0; 2'b01: data_out=8'd1; 2'b10: data_out=8'd4; 2'b11: data_out=8'd9; default: data_out=8'd0; endcase end -> Option AQuick Check:
ROM as combinational case statement = always @(addr) begin case(addr) 2'b00: data_out=8'd0; 2'b01: data_out=8'd1; 2'b10: data_out=8'd4; 2'b11: data_out=8'd9; default: data_out=8'd0; endcase end [OK]
- Assigning to wire arrays
- Initializing ROM inside clocked always block
- Not using combinational logic for ROM output
Ready to prove it?
Pass the test and this pattern moves unknown
