I am attempting to write and test a simple 16-bit width RAM8 chip in Verilog using Icarus Verilog. I'm finding it difficult to understand conceptually why the iverilog simulator is showing me 'x' (undefined) values on certain clock ticks and wondering if anybody can provide a conceptual understanding for this problem.
I've tried two different designs, one of which the output makes sense to me, but I can't parse the output of the second.
The first design makes out
a register, and assignment to the output is clocked:
module RAM8(out, address, in, load, clk);
output[15:0] out;
input [15:0] in;
input [2:0] address;
input load, clk;
reg out; // out is a register
reg [15:0] ram [7:0]; // 8-element array of 16-bit wide reg
always @(posedge clk) begin
if (load)
ram[address] <= in;
out <= ram[address]; // clocked assignment
end
endmodule // RAM8
Whereas the second design, out
is a continuously assigned wire:
module RAM8(out, address, in, load, clk);
output[15:0] out;
input [15:0] in;
input [2:0] address;
input load, clk;
reg [15:0] ram [7:0]; // 8-element array of 16-bit wide reg
always @(posedge clk) begin
if (load)
ram[address] <= in;
end
assign out = ram[address]; // continuous assignment
endmodule // RAM8
The test bench for both of these is the same:
module RAM8_tb();
wire [15:0] out;
reg [15:0] in;
reg [2:0] address;
reg load;
reg clk;
RAM8 DUT (
.out(out),
.in(in),
.address(address),
.load(load),
.clk(clk)
);
initial begin
clk = 0;
load = 0;
address = 0;
in = 0;
#10 load = 1; address = 0; in = 0;
#10 load = 0; address = 0;
#10 load = 1; address = 1; in = 1;
#10 load = 0; address = 1;
#10 load = 1; address = 2; in = 2;
#10 load = 0; address = 2;
#10 load = 1; address = 3; in = 3;
#10 load = 0; address = 3;
#10 load = 1; address = 4; in = 4;
#10 load = 0; address = 4;
#10 load = 1; address = 5; in = 5;
end // initial begin
always #5 clk = ~clk;
initial #150 $stop;
initial
$monitor("At time %t, clk = %0d, load = %0d, address = %0d, in = %0d, out = %0d",
$time, clk, load, address, in, out);
endmodule // RAM8_tb
My output running the test bench for the first design is this:
At time 0, clk = 0, load = 0, address = 0, in = 0, out = x
At time 5, clk = 1, load = 0, address = 0, in = 0, out = x
At time 10, clk = 0, load = 1, address = 0, in = 0, out = x
At time 15, clk = 1, load = 1, address = 0, in = 0, out = x
At time 20, clk = 0, load = 0, address = 0, in = 0, out = x
At time 25, clk = 1, load = 0, address = 0, in = 0, out = 0
At time 30, clk = 0, load = 1, address = 1, in = 1, out = 0
At time 35, clk = 1, load = 1, address = 1, in = 1, out = x
At time 40, clk = 0, load = 0, address = 1, in = 1, out = x
At time 45, clk = 1, load = 0, address = 1, in = 1, out = 1
At time 50, clk = 0, load = 1, address = 2, in = 2, out = 1
At time 55, clk = 1, load = 1, address = 2, in = 2, out = x
At time 60, clk = 0, load = 0, address = 2, in = 2, out = x
At time 65, clk = 1, load = 0, address = 2, in = 2, out = 2
At time 70, clk = 0, load = 1, address = 3, in = 3, out = 2
At time 75, clk = 1, load = 1, address = 3, in = 3, out = x
At time 80, clk = 0, load = 0, address = 3, in = 3, out = x
At time 85, clk = 1, load = 0, address = 3, in = 3, out = 3
At time 90, clk = 0, load = 1, address = 4, in = 4, out = 3
At time 95, clk = 1, load = 1, address = 4, in = 4, out = x
At time 100, clk = 0, load = 0, address = 4, in = 4, out = x
At time 105, clk = 1, load = 0, address = 4, in = 4, out = 4
At time 110, clk = 0, load = 1, address = 5, in = 5, out = 4
At time 115, clk = 1, load = 1, address = 5, in = 5, out = x
At time 120, clk = 0, load = 1, address = 5, in = 5, out = x
At time 125, clk = 1, load = 1, address = 5, in = 5, out = 5
At time 130, clk = 0, load = 1, address = 5, in = 5, out = 5
At time 135, clk = 1, load = 1, address = 5, in = 5, out = 5
At time 140, clk = 0, load = 1, address = 5, in = 5, out = 5
At time 145, clk = 1, load = 1, address = 5, in = 5, out = 5
This output makes sense to me. Each time I'm loading a new value, the output is undefined because the loading is happening concurrently to the value that's being loaded being clocked into the output register (hence, garbage values for that clock tick).
However the output for the test bench for the second design is confusing to me:
At time 0, clk = 0, load = 0, address = 0, in = 0, out = x
At time 5, clk = 1, load = 0, address = 0, in = 0, out = x
At time 10, clk = 0, load = 1, address = 0, in = 0, out = x
At time 15, clk = 1, load = 1, address = 0, in = 0, out = 0
At time 20, clk = 0, load = 0, address = 0, in = 0, out = 0
At time 25, clk = 1, load = 0, address = 0, in = 0, out = 0
At time 30, clk = 0, load = 1, address = 1, in = 1, out = x
At time 35, clk = 1, load = 1, address = 1, in = 1, out = 1
At time 40, clk = 0, load = 0, address = 1, in = 1, out = 1
At time 45, clk = 1, load = 0, address = 1, in = 1, out = 1
At time 50, clk = 0, load = 1, address = 2, in = 2, out = x
At time 55, clk = 1, load = 1, address = 2, in = 2, out = 2
At time 60, clk = 0, load = 0, address = 2, in = 2, out = 2
At time 65, clk = 1, load = 0, address = 2, in = 2, out = 2
At time 70, clk = 0, load = 1, address = 3, in = 3, out = x
At time 75, clk = 1, load = 1, address = 3, in = 3, out = 3
At time 80, clk = 0, load = 0, address = 3, in = 3, out = 3
At time 85, clk = 1, load = 0, address = 3, in = 3, out = 3
At time 90, clk = 0, load = 1, address = 4, in = 4, out = x
At time 95, clk = 1, load = 1, address = 4, in = 4, out = 4
At time 100, clk = 0, load = 0, address = 4, in = 4, out = 4
At time 105, clk = 1, load = 0, address = 4, in = 4, out = 4
At time 110, clk = 0, load = 1, address = 5, in = 5, out = x
At time 115, clk = 1, load = 1, address = 5, in = 5, out = 5
At time 120, clk = 0, load = 1, address = 5, in = 5, out = 5
At time 125, clk = 1, load = 1, address = 5, in = 5, out = 5
At time 130, clk = 0, load = 1, address = 5, in = 5, out = 5
At time 135, clk = 1, load = 1, address = 5, in = 5, out = 5
At time 140, clk = 0, load = 1, address = 5, in = 5, out = 5
At time 145, clk = 1, load = 1, address = 5, in = 5, out = 5
My question here is: what are the periodic undefined values at the output caused by? The commonality appears to be when the clk is 0 and the load is 1, but nothing I can recall from my understanding of registers explains why that would cause the output to be garbage. All the registers in my design are triggered on the positive clock edge, so why would a negative edge be changing any value?
I figure I may be confused generally about what's going on under the hood here, and would also appreciate somebody confirming or refuting my explanation for the behavior of the first design as well. Thanks in advance to anybody who takes the time to read and answer.