How is iverilog simulator interpreting my RAM code to determine 'x' values?
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.
verilog fpga ram iverilog
add a comment |
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.
verilog fpga ram iverilog
I'd suggest you don't rely on text output to understand what is happening in your design. Waveforms make more sense when debugging hardware. It will help you understand Justin's (correct) point.
– rascob
Dec 30 '18 at 22:16
@rascob I understood his point, however I'm curious if I can use any free or cheap waveform tools along with iverilog? I'm currently limited by RAM on my 2013 MacBook and can't run Vivado.
– Isaiah Becker-Mayer
Jan 3 at 2:53
If you have to use iverilog, you can try gtkwave. If not, you can try a free version of Mentor's Modelsim. Altera provides a "Web" edition for free: intel.com/content/www/us/en/programmable/downloads/…
– rascob
Jan 3 at 12:52
add a comment |
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.
verilog fpga ram iverilog
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.
verilog fpga ram iverilog
verilog fpga ram iverilog
asked Dec 28 '18 at 23:36
Isaiah Becker-MayerIsaiah Becker-Mayer
161
161
I'd suggest you don't rely on text output to understand what is happening in your design. Waveforms make more sense when debugging hardware. It will help you understand Justin's (correct) point.
– rascob
Dec 30 '18 at 22:16
@rascob I understood his point, however I'm curious if I can use any free or cheap waveform tools along with iverilog? I'm currently limited by RAM on my 2013 MacBook and can't run Vivado.
– Isaiah Becker-Mayer
Jan 3 at 2:53
If you have to use iverilog, you can try gtkwave. If not, you can try a free version of Mentor's Modelsim. Altera provides a "Web" edition for free: intel.com/content/www/us/en/programmable/downloads/…
– rascob
Jan 3 at 12:52
add a comment |
I'd suggest you don't rely on text output to understand what is happening in your design. Waveforms make more sense when debugging hardware. It will help you understand Justin's (correct) point.
– rascob
Dec 30 '18 at 22:16
@rascob I understood his point, however I'm curious if I can use any free or cheap waveform tools along with iverilog? I'm currently limited by RAM on my 2013 MacBook and can't run Vivado.
– Isaiah Becker-Mayer
Jan 3 at 2:53
If you have to use iverilog, you can try gtkwave. If not, you can try a free version of Mentor's Modelsim. Altera provides a "Web" edition for free: intel.com/content/www/us/en/programmable/downloads/…
– rascob
Jan 3 at 12:52
I'd suggest you don't rely on text output to understand what is happening in your design. Waveforms make more sense when debugging hardware. It will help you understand Justin's (correct) point.
– rascob
Dec 30 '18 at 22:16
I'd suggest you don't rely on text output to understand what is happening in your design. Waveforms make more sense when debugging hardware. It will help you understand Justin's (correct) point.
– rascob
Dec 30 '18 at 22:16
@rascob I understood his point, however I'm curious if I can use any free or cheap waveform tools along with iverilog? I'm currently limited by RAM on my 2013 MacBook and can't run Vivado.
– Isaiah Becker-Mayer
Jan 3 at 2:53
@rascob I understood his point, however I'm curious if I can use any free or cheap waveform tools along with iverilog? I'm currently limited by RAM on my 2013 MacBook and can't run Vivado.
– Isaiah Becker-Mayer
Jan 3 at 2:53
If you have to use iverilog, you can try gtkwave. If not, you can try a free version of Mentor's Modelsim. Altera provides a "Web" edition for free: intel.com/content/www/us/en/programmable/downloads/…
– rascob
Jan 3 at 12:52
If you have to use iverilog, you can try gtkwave. If not, you can try a free version of Mentor's Modelsim. Altera provides a "Web" edition for free: intel.com/content/www/us/en/programmable/downloads/…
– rascob
Jan 3 at 12:52
add a comment |
1 Answer
1
active
oldest
votes
In both cases, the X values coming out are are the initial values of ram
(which are X since you didn't assign any initial values). If you continued the test and cycled through the same addresses, the next time around you'd see the values you previously wrote.
In the first example, the concurrent read and write isn't an issue. The read is returning the value from before the clock edge, and ram
will contain the new value after the clock edge.
In the second example, the event triggering the X is address
incrementing, not the clk
and load
signals. Since out
isn't registered and isn't associated with clk
, as soon as address
changes you see the value at that address appear on out
. Then after the clock edge that writes a new value, you see out
change to that value at the same time.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53965441%2fhow-is-iverilog-simulator-interpreting-my-ram-code-to-determine-x-values%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
In both cases, the X values coming out are are the initial values of ram
(which are X since you didn't assign any initial values). If you continued the test and cycled through the same addresses, the next time around you'd see the values you previously wrote.
In the first example, the concurrent read and write isn't an issue. The read is returning the value from before the clock edge, and ram
will contain the new value after the clock edge.
In the second example, the event triggering the X is address
incrementing, not the clk
and load
signals. Since out
isn't registered and isn't associated with clk
, as soon as address
changes you see the value at that address appear on out
. Then after the clock edge that writes a new value, you see out
change to that value at the same time.
add a comment |
In both cases, the X values coming out are are the initial values of ram
(which are X since you didn't assign any initial values). If you continued the test and cycled through the same addresses, the next time around you'd see the values you previously wrote.
In the first example, the concurrent read and write isn't an issue. The read is returning the value from before the clock edge, and ram
will contain the new value after the clock edge.
In the second example, the event triggering the X is address
incrementing, not the clk
and load
signals. Since out
isn't registered and isn't associated with clk
, as soon as address
changes you see the value at that address appear on out
. Then after the clock edge that writes a new value, you see out
change to that value at the same time.
add a comment |
In both cases, the X values coming out are are the initial values of ram
(which are X since you didn't assign any initial values). If you continued the test and cycled through the same addresses, the next time around you'd see the values you previously wrote.
In the first example, the concurrent read and write isn't an issue. The read is returning the value from before the clock edge, and ram
will contain the new value after the clock edge.
In the second example, the event triggering the X is address
incrementing, not the clk
and load
signals. Since out
isn't registered and isn't associated with clk
, as soon as address
changes you see the value at that address appear on out
. Then after the clock edge that writes a new value, you see out
change to that value at the same time.
In both cases, the X values coming out are are the initial values of ram
(which are X since you didn't assign any initial values). If you continued the test and cycled through the same addresses, the next time around you'd see the values you previously wrote.
In the first example, the concurrent read and write isn't an issue. The read is returning the value from before the clock edge, and ram
will contain the new value after the clock edge.
In the second example, the event triggering the X is address
incrementing, not the clk
and load
signals. Since out
isn't registered and isn't associated with clk
, as soon as address
changes you see the value at that address appear on out
. Then after the clock edge that writes a new value, you see out
change to that value at the same time.
answered Dec 29 '18 at 2:15
Justin NJustin N
212
212
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53965441%2fhow-is-iverilog-simulator-interpreting-my-ram-code-to-determine-x-values%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I'd suggest you don't rely on text output to understand what is happening in your design. Waveforms make more sense when debugging hardware. It will help you understand Justin's (correct) point.
– rascob
Dec 30 '18 at 22:16
@rascob I understood his point, however I'm curious if I can use any free or cheap waveform tools along with iverilog? I'm currently limited by RAM on my 2013 MacBook and can't run Vivado.
– Isaiah Becker-Mayer
Jan 3 at 2:53
If you have to use iverilog, you can try gtkwave. If not, you can try a free version of Mentor's Modelsim. Altera provides a "Web" edition for free: intel.com/content/www/us/en/programmable/downloads/…
– rascob
Jan 3 at 12:52