ROM stores fixed data that does not change during operation. It helps keep important information safe and always available.
ROM (Read-Only Memory) in Verilog
module rom_example( input wire [3:0] addr, output reg [7:0] data ); always @(*) begin case(addr) 4'h0: data = 8'hA1; 4'h1: data = 8'hB2; 4'h2: data = 8'hC3; 4'h3: data = 8'hD4; default: data = 8'h00; endcase end endmodule
ROM is often implemented using a case statement inside a combinational always block.
The addr input selects which fixed data to output on data.
case(addr) 4'h0: data = 8'hFF; 4'h1: data = 8'h00; 4'h2: data = 8'hAA; default: data = 8'h55; endcase
initial block to store ROM contents.reg [7:0] rom_mem [0:15]; initial begin rom_mem[0] = 8'h10; rom_mem[1] = 8'h20; rom_mem[2] = 8'h30; // ... initialize other addresses end always @(*) begin data = rom_mem[addr]; end
This program defines a small ROM with 4 fixed values. The testbench prints the data for each address.
module rom_demo( input wire [1:0] addr, output reg [7:0] data ); always @(*) begin case(addr) 2'b00: data = 8'h12; 2'b01: data = 8'h34; 2'b10: data = 8'h56; 2'b11: data = 8'h78; default: data = 8'h00; endcase end endmodule // Testbench to show ROM output module testbench; reg [1:0] addr; wire [7:0] data; rom_demo rom(.addr(addr), .data(data)); initial begin $display("Addr | Data"); for (addr = 0; addr < 4; addr = addr + 1) begin #1; // wait for data to update $display("%b | %h", addr, data); end $finish; end endmodule
ROM contents are fixed and cannot be changed during simulation or hardware operation.
Use initial blocks or case statements to define ROM data.
ROM is useful for storing constants, lookup tables, or program code in hardware.
ROM holds fixed data that your circuit reads but never changes.
Use case or arrays with initial to define ROM contents.
ROM is great for lookup tables, constants, and program instructions.
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
