RTL if statements not matching with simulation - verilog

I am struggling to understand why the output flickers between 0 and 1, when the output should constantly remain 0 since the reduction OR gate of 000 is 0 not 1.
When I tried a different bit width, the problem suddenly disappeared. However, I would like to know what is going on rather than relying on randomness for correctness.
project_test .sv
`timescale 1ns/1ns
module project_test
( input logic clk, rst,
input logic in,
output logic [2:0] c
);
logic [2:0] out;
always#(posedge clk or posedge rst) begin
if(rst)
out <= 'b0;
else if(in) begin
if(|out)
out <= 'b0;
end
else
out <= out + 1'b1;
end
assign c = out;
endmodule: project_test
testbench.sv
`timescale 1ns/1ns
module testbench;
logic clk, rst;
logic in;
logic [2:0] c;
project_test project_test(
.clk(clk),
.rst(rst),
.in(in),
.c(c)
);
initial begin
clk = 0;
rst = 1;
in = 0 ;
#30
rst = 0;
#20;
in = 1;
#500;
rst=1;
#100ns;
$stop();
end
always#(clk) begin
#10ns clk <= !clk;
end
endmodule
Simulation output:
RTL viewer:

That is an improper way to generate a clock signal in the testbench. You should not have the clk signal in the sensitivity list because it keeps re-triggerring the always block. Your clock generator potentially adds events to the Verilog event queue, which can cause odd behavior. In fact, when I ran your code on the Cadence simulator, I did not see the clock toggling at all.
This is a more standard way to generate a clock:
always begin
#10ns clk = !clk;
end

You are using a very verbose implementation. Why can't you do something like below.
always#(posedge clk or posedge rst)
begin
if(rst)
out <= 'd0;
else
out <= (in) ? 'd0 : (out + 1'b1);
end

Related

Why is the simulation stuck in Vivado

I tried to develop a spare memory code, but the simulation got stuck in vivado. I cannot exactly say whether it is stuck or not, but the simulation is not running. I've attached the image for the problem I'm unable to clearly express. The test bench of the code goes here. While trying to get a simulated waveform, vivado is not giving a simulation whereas it is fully working in Icarus Verilog, and the simulation waveforms are clear in GTK wave.
module trial_tb;
reg clk;
reg rst_n;
reg bist_enable;
reg we;
reg [5:0] wraddr;
reg data_in;
reg re;
reg [5:0] rdaddr;
wire data_out;
wire repair_fail;
wire repair_finish;
integer m;
integer idx;
SRAM_repair uut (clk, rst_n, bist_enable, we, wraddr, data_in, re, rdaddr, data_out, repair_fail, repair_finish);
initial
begin
clk = 0;
rst_n <= 0;
bist_enable <= 0;
rdaddr <= 'b0;
wraddr <= 'b0;
we <= 1'b0;
re <= 1'b0;
data_in <= 1'b0;
#5.0 rst_n <= 1;
#5.0 bist_enable <= 1;
#52.9 bist_enable <= 1'b0;
we <= 1'b1;
data_in <= 1'b0;
for ( m=0 ; m<=32; m=m+1) begin
wraddr <= m;
#0.2;
end
data_in <= 1'b1;
for ( m=33 ; m<=63; m=m+1) begin
wraddr <= m;
#0.2;
end
#0.2;
we <= 1'b0;
re <= 1'b1;
for ( m=0 ; m<64; m= m+1) begin
rdaddr <= m;
#0.2;
end
end
initial
begin
$dumpfile ("SRAM_repair.vcd");
$dumpvars( 0, trial_tb);
// $dumpvars( 0, trial_tb.uut.i_bisr_controller.fcr\[0\]);
// $dumpvars( 0, trial_tb.uut.i_bisr_controller.fcr\[1\]);
// $dumpvars( 0, trial_tb.uut.i_bisr_controller.fcr\[2\]);
// $dumpvars( 0, trial_tb.uut.i_bisr_controller.fcr\[3\]);
// $dumpvars( 0, trial_tb.uut.i_bisr_controller.fcr\[4\]);
// $dumpvars( 0, trial_tb.uut.i_bisr_controller.fcr\[5\]);
#90 $finish;
end
always #0.1 clk = ~clk;
endmodule
I suspect you did not use a proper timescale for the delays in your testbench. From IEEE Std 1800-2017, section 22.7 `timescale:
If there is no `timescale specified or it has been reset by a
`resetall directive, the default time unit and precision are
tool-specific.
When not specified, my simulator defaults to:
`timescale 1ns/1ns
I see the simulation hang at time 0, as I think you do. Since the time precision is the same as the time unit (both are 1ns for me), the 0.1 delay for clk is rounded down to 0, causing an infinite loop in the clk always block.
I fixed this by adding this explicit timescale before the module:
`timescale 1ns/100ps
This sets the precision less than the unit, allowing the clk to toggle properly.
The discrepancy you see between Vivado and Icarus is likely a result of different timescales being used. To see what timescale is in effect, add this code to your testbench:
initial $printtimescale;

Verilog: one clock cycle delay using register

I'm trying to delay two signals. I wrote a register to do that and instantiated it but a strange thing happens. Delaying "state" signal seems to work, but delaying "nb_bits" signal doesn't.
Here's my code for the register:
`timescale 1ns / 1ps
module register(
input CLK,
input clr,
input en,
input [7:0] in,
output [7:0] out
);
reg [7:0] temp;
always # (posedge CLK or posedge clr) begin
if (clr) begin
temp <= 8'b00010000;
end
else if (en) begin
temp <= in;
end
else begin
temp <= temp;
end
end
assign out = temp;
endmodule
And that's ma instantiation:
wire [3:0] nbb;
nb_bits_register nb_bits_reg(
.CLK(CLK),
.clr(clr),
.en(en),
.in(nb_bits),
.out(nbb)
);
wire [7:0] stt;
register state_reg(
.CLK(CLK),
.clr(clr),
.en(en),
.in(state),
.out(stt)
);
nb_bits_register module is analogical; I didn't want to parametrize before solving this problem.
`timescale 1ns / 1ps
module nb_bits_register(
input CLK,
input clr,
input en,
input [3:0] in,
output [3:0] out
);
reg [3:0] temp;
always # (posedge CLK or posedge clr) begin
if (clr) begin
temp <= 4'b0000;
end
else if (en) begin
temp <= in;
end
else begin
temp <= temp;
end
end
assign out = temp;
endmodule
And here's a simulation:
enter image description here
And testbench:
`timescale 1ns / 1ps
module state_machine_tb();
reg CLK, clr, en;
reg [7:0] symbol;
reg [3:0] nb_bits;
wire [7:0] state;
initial begin
CLK <= 1;
clr <= 0;
en <= 0;
symbol <= 8'b00110010;
nb_bits <= 1;
#10
clr <= 1;
en <= 1;
#10
clr <= 0;
symbol <= 8'b00110001;
nb_bits <= 1;
#10
symbol <= 8'b00110010;
nb_bits <= 2;
#10
symbol <= 8'b00110001;
nb_bits <= 1;
#10
symbol <= 8'b00110001;
nb_bits <= 1;
#10
symbol <= 8'b00110000;
nb_bits <= 3;
#10
$finish;
end
always begin
#5 CLK <= ~CLK;
end
state_machine state_machine_inst(
.CLK(CLK),
.clr(clr),
.en(en),
.symbol(symbol),
.nb_bits(nb_bits),
.state(state)
);
endmodule
It does seem like a rase condition in the scheduler. By definition from the Verilog LRM, the order of evaluating procedural blocks (always blocks and initial blocks) is indeterminate. You might notice a pattern with a particular simulator and version, but that patter can change when changing the simulator or changing the version of the same simulator.
Use blocking assignment with your clock (ex: always #5 CLK = ~CLK;). With will guarantee the CLK will be updated before other stimulus.
In the test bench, change all the #10 to #(posedge CLK). The timing will be the same, however it guarantees CLK was updated before evaluating the new values symbol and other stimulus.
FYI: If you change output [7:0] out to output reg [7:0] out you can assign out directly in your always block, removing the need for temp. This doesn't change anything functionally; just fewer variables and lines of code.
It seems like a race condition: your changes of nb_bits coincide with positive edges of CLK, so there's an ambiguity resolved by the simulator in this way:
change nb_bits (from 1 to 2, etc.)
change CLK from 0 to 1
execute in nb_bits_register: if (en) temp <= in; ... assign out = temp;
As the result, out = in in nb_bits_register.
A solution is to avoid this coincidence, e.g. by changing the first #10 in the testbench to #11.

Driving a internal wire in my module from my interface task

EDIT: I tried out the methods mentioned below: I set my interface to wires instead of logic, and I drive 'Z from the driver that wants to relinquish control of the signal so that the other driver can take over. Still doesn't work as I see u_slave_dut not being driven from my interface. Any clues on what is wrong? My working example: https://www.edaplayground.com/x/4SSP
I am writing a testbench for a top-level module that has a number of sub-modules. I want to instantiate an interface and hook it up to one of my sub-modules, say my_submodule. Easy enough, and I can see my interface pins toggling when my_submodule pins are toggled. This makes for great observation.
Next, I decided I wanted to be able to toggle the pins myself from my interface (using a task). I realize this leads to 2 drivers on the same bus. So, is there a way for me to do this?
I created a small example of edaplayground to experiment, and here I see that none of my writes from my task in the interface actually toggle the pins on u_slave_dut. Also, I get no warnings from the compiler which bothers me too.
My working example is here: https://www.edaplayground.com/x/5fcP
testbench.sv
`include "my_interface.sv"
module tb;
bit clk = 1'b1;
bit control = 1'b0;
initial begin
forever begin
#5 clk = ~clk;
end
end
my_interface my_vif(clk);
assign my_vif.addr = (control)? tb.u_top.u_slave_dut.i_addr : 'hz;
assign my_vif.wdata = (control)? tb.u_top.u_slave_dut.i_wdata : 'hz;
assign my_vif.write = (control)? tb.u_top.u_slave_dut.i_write : 'hz;
top u_top(.clk(clk));
initial begin
#80 my_vif.master_write_something;
#160 $finish;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
interface.sv
interface my_interface(input clk);
logic [3:0] addr;
logic write;
logic [3:0] wdata;
logic [3:0] rdata;
logic resp;
clocking master_cb #(posedge clk);
input resp, rdata;
output addr, write, wdata;
endclocking
clocking slave_cb #(posedge clk);
input addr, write, wdata;
output resp, rdata;
endclocking
task master_write_something;
#(master_cb);
master_cb.write <= 1'b1;
#(master_cb);
master_cb.wdata <= 3'b101;
master_cb.addr <= 3'b111;
#(master_cb);
master_cb.write <= 1'b0;
endtask
task slave_write_something;
#(slave_cb);
slave_cb.resp <= 1'b1;
#(slave_cb);
slave_cb.rdata <= 3'b101;
#(slave_cb);
slave_cb.resp <= 1'b0;
slave_cb.rdata <= 3'b000;
endtask
endinterface
design.sv
module slave_dut (
input clk,
input [3:0] i_addr,
input [3:0] i_wdata,
input i_write,
output o_resp,
output [3:0] o_rdata
);
reg o_resp_reg;
reg [3:0] o_rdata_reg;
initial begin
o_resp_reg <= 1'b0;
o_rdata_reg <= 'h0;
end
always #(posedge clk) begin
if (i_write == 1'b1) begin
o_resp_reg <= 1'b1;
o_rdata_reg <= i_wdata;
end
else begin
o_resp_reg <= 1'b0;
o_rdata_reg <= 'h0;
end
end
assign o_resp = o_resp_reg;
assign o_rdata = o_rdata_reg;
endmodule : slave_dut
module master_dut (
input clk,
output [3:0] o_addr,
output [3:0] o_wdata,
output o_write,
input i_resp,
input [3:0] i_rdata
);
reg [3:0] o_addr_reg;
reg [3:0] o_wdata_reg;
reg o_write_reg;
initial begin
o_addr_reg <= 'h0;
o_wdata_reg <= 'h0;
o_write_reg <= 'h0;
repeat (2) #(posedge clk);
o_addr_reg <= 'hF;
o_wdata_reg <= 'hB;
o_write_reg <= 1'b1;
#(posedge clk);
o_addr_reg <= 'h0;
o_wdata_reg <= 'h0;
o_write_reg <= 'h0;
repeat (2) #(posedge clk);
o_addr_reg <= 'h4;
o_wdata_reg <= 'hD;
o_write_reg <= 1'b1;
#(posedge clk);
o_addr_reg <= 'h0;
o_wdata_reg <= 'h0;
o_write_reg <= 'h0;
end
assign o_addr = o_addr_reg;
assign o_wdata = o_wdata_reg;
assign o_write = o_write_reg;
endmodule : master_dut
module top(input clk);
wire [3:0] addr;
wire [3:0] wdata;
wire write;
wire resp;
wire [3:0] rdata;
master_dut u_master_dut (
.clk(clk),
.o_addr(addr),
.o_wdata(wdata),
.o_write(write),
.i_resp(resp),
.i_rdata(rdata)
);
slave_dut u_slave_dut (
.clk(clk),
.i_addr(addr),
.i_wdata(wdata),
.i_write(write),
.o_resp(resp),
.o_rdata(rdata)
);
endmodule
Any idea where I am going wrong?
I believe the one simulator you chose to run the simulator on does not give any warnings or errors. Any other simulator will correctly give the errors about mixing continuous assignments with procedural assignments from the clocking block.
If you are going to have the same signal driven from two different places, you need to deal with that by using a wire instead of a variable. You also need to turn off one of the drivers by setting it to high-impedance ('z), so the other driver can control the signal. This needs to be done regardless of whether the two drivers are within your design or between the design and testbench. I wrote a DVCon paper a few years ago that explains this in more detail.
As Dave explained, it is the only way to control the multi driver nets by enabling only one driver to drive the net at a time. And from hardware point of view as well, only one driver should drive any wire at a time.
This can be achieved in your design by using additional reg.
Please refer the following code.
module tb;
bit clk = 1'b1;
reg control = 1'b1;
initial begin
forever begin
#5 clk = ~clk;
end
end
my_interface my_vif(clk);
assign my_vif.addr = (control)? tb.u_top.u_slave_dut.i_addr : 'hz;
assign my_vif.wdata = (control)? tb.u_top.u_slave_dut.i_wdata : 'hz;
assign my_vif.write = (control)? tb.u_top.u_slave_dut.i_write : 'hz;
top u_top(.clk(clk));
initial begin
#80 my_vif.master_write_something (control);
#160 $finish;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
// Interface Task
task master_write_something (ref reg x);
#(master_cb);
x = 1'b0;
master_cb.write <= 1'b1;
#(master_cb);
master_cb.wdata <= 3'b101;
master_cb.addr <= 3'b111;
#(master_cb);
master_cb.write <= 1'b0;
endtask
And the dump file is as follow.

Verilog code 2 errors i can't find: Would be grateful for an extra pair of eyes to spot a mistake i might've overlooked

I'm writing a verilog code where i'm reading two files and saving those numbers into registers. I'm then multiplying them and adding them. Pretty much a Multiplication Accumulator. However i'm having a hard frustrating time with the code that i have. It read the numbers from the files correctly and it multiples but here is the problem? When i first run it using ModelSim, I reset everything so i can clear out the accumulator. I then begin the program, but there is always this huge delay in my "macc_out" and i cannot seem to figure out why. This delay should not be there and instead it should be getting the result out A*B+MAC. Even after the delay, it's not getting the correct output. My second problem is that if i go from reset high, to low (start the program) and then back to reset high ( to reset all my values), they do not reset! This is frustrating since i've been working on this for a week and don't know/can't see a bug. Im asking for an extra set of eyes to see if you can spot my mistake. Attached is my code with the instantiations and also my ModelSim functional Wave Form. Any help is appreciated!
module FSM(clk,start,reset,done,clock_count);
input clk, start, reset;
output reg done;
output reg[10:0] clock_count;
reg [0:0] macc_clear;
reg[5:0] Aread, Bread, Cin;
wire signed [7:0] a, b;
wire signed [18:0] macc_out;
reg [3:0] i,j,m;
reg add;
reg [0:0] go;
reg[17:0] c;
parameter n = 8;
reg[1:0] state;
reg [1:0] S0 = 2'b00;
reg [1:0] S1 = 2'b01;
reg [1:0] S2 = 2'b10;
reg [1:0] S3 = 2'b11;
ram_A Aout(.clk(clk), .addr(Aread), .q(a));
ram_B Bout(.clk(clk), .addr(Bread), .q(b));
mac macout(.clk(clk), .macc_clear(macc_clear), .A(a), .B(b), .macc_out(macc_out), .add(add));
ram_C C_in(.clk(clk), .addr(Cin), .q(c));
always #(posedge clk) begin
if (reset == 1) begin
i <= 0;
add<=0;
j <= 0;
m <= 0;
clock_count <= 0;
go <= 0;
macc_clear<=1;
end
else
state<=S0;
case(state)
S0: begin
// if (reset) begin
// i <= 0;
// add<=0;
// j <= 0;
// m <= 0;
// clock_count <= 0;
// go <= 0;
// macc_clear<=1;
// state <= S0;
// end
macc_clear<=1;
done<=0;
state <= S1;
end
S1: begin
add<=1;
macc_clear<=0;
clock_count<=clock_count+1;
m<=m+1;
Aread <= 8*m + i;
Bread <= 8*j + m;
if (m==7) begin
state <= S2;
macc_clear<=1;
add<=0;
end
else
state <=S1;
end
S2: begin
add<=1;
macc_clear<=0;
m<=0;
i<=i+1;
if (i<7)
state<=S1;
else if (i==8) begin
state<=S3;
add<=0;
end
end
S3: begin
add<=1;
i<=0;
j<=j+1;
if(j<7)
state<=S1;
else begin
state<=S0;
done<=1;
add<=0;
end
end
endcase
end
always # (posedge macc_clear) begin
Cin <= 8*j + i;
c <= macc_out;
end
endmodule
module mac(clk, macc_clear, A, B, macc_out, add);
input clk, macc_clear;
input signed [7:0] A, B;
input add;
output reg signed [18:0] macc_out;
reg signed [18:0] MAC;
always #( posedge clk) begin
if (macc_clear) begin
macc_out <= MAC;
MAC<=0;
end
else if (add) begin
MAC<=(A*B)+ MAC;
macc_out<=MAC;
end
end
endmodule
module ram_A( clk, addr,q);
output reg[7:0] q;
input [5:0] addr;
input clk;
reg [7:0] mem [0:63];
initial begin
$readmemb("ram_a_init.txt", mem);
end
always #(posedge clk) begin
q <= mem[addr];
end
endmodule
module ram_C(clk,addr, q);
input [18:0] q;
input [5:0] addr;
input clk;
reg [18:0] mem [0:63];
always #(posedge clk) begin
mem[addr] <= q;
end
endmodule
ModelSim Functional Simulation Wave Form
1) Take a look at the schematic view for your MACC module - I think some of your "problems" will be obvious from that;
2) Consider using an always#(*) (Combinational) block for your FSM control signals (stuff like add or macc_clear) rather than a always#(posedge clk) (sequential) - it makes the logic to assert them easier. Right now they're registered, so you have a cycle delay. ;
3) In your MAC, you clear the MAC register on a reset, but you don't clear the macc_out register.
In short, I think you need to step back, and consider which signals are combinational logic, and which ones are sequential and need to be in registers.

Parse error when I try to use Verilog; testbenching an LFSR doesn't work

I am currently working on random number generation using Verilog. Sources have indicated that using Linear Feedback Shift Registers are one of the best ways to randomize MSBs. So I decided to code and testbench an LFSR. Snippet is below:
module lfsr_counter(clk, reset, ce, lfsr_done);
input clk, reset, ce;
output lfsr_done;
reg lfsr_done;
reg [10:0] lfsr;
initial lfsr_done = 0;
wire d0,lfsr_equal;
xnor(d0,lfsr[10],lfsr[8]);
assign lfsr_equal = (lfsr == 11'h359);
always #(posedge clk,posedge reset) begin
if(reset) begin
lfsr <= 0;
lfsr_done <= 0;
end
else begin
if(ce)
lfsr <= lfsr_equal ? 11'h0 : {lfsr[9:0],d0};
lfsr_done <= lfsr_equal;
end
end
endmodule
module testbench();
reg clk, reset, ce;
wire lfsr_done;
lfsr_counter dut(clk, reset, ce, lfsr_done); // Design Under Test
initial
begin
reset = 0;
clk = 1;
ce = 0;
#100
ce = 1;
#200 $finish;
end
//Generate Clock
always #10 clk = !clk;
endmodule
But I keep getting these parse errors:
I don't really get it. I'm using Verilogger Pro btw
I think always block terms are separated by or, not a comma.
always #(posedge clk or posedge reset) begin

Resources