I have following codes with blocking (code 1) and nonblocking (code 2) assignment in always block.
But output is different in both cases. Why?
Event queue I know, but probably I am not able to understand where "always # (clk)" statement will be placed in event queue.
// Code 1
module osc2 (clk, d);
output clk;
reg clk;
input d;
initial
begin
#10 clk = 0;
$monitor ("%d %b", $time, clk);
end
initial #100 $finish;
always # (clk) #10 clk = ~clk;
endmodule
// Output of Code 1
10 0
20 1
// Code 2
module osc2 (clk, d);
output clk;
reg clk;
input d;
initial
begin
#10 clk = 0;
$monitor ("%d %b", $time, clk);
end
initial #100 $finish;
always # (clk) #10 clk <= ~clk;
endmodule
// Output of Code 2
10 0
20 1
30 0 (goes on upto 90)
90 0
For explanatory purposes, I unraveled the content of the first two loops and expanded components for break down. The below code will simulate.
always # (clk) #10 clk = ~clk;
initial while (1) // to see the loop, functionally equivalent to 'always'
begin // procedural block
begin : loop0_unraveled
#(clk); // suspend continuation of loop until change in clk
#10; // suspend continuation of loop 10 time units
clk = ~clk; /* eval '~clk' now
* update clk now
*/
end
begin : loop1_unraveled
begin // this block is functionally equivalent to '#(clk)'
reg smpl_clk; // local variable
smpl_clk = clk; // sample
$display("%t::Pre-Suspend : smpl_clk=%b clk=%b", $time, smpl_clk, clk);
wait(clk != smpl_clk); // suspend continuation of loop until
/* 1. no other blocking statements can execute, go to next region
* 2. All other regions are empty
* 3. Remaining events are block
* 4. Nothing left to do, exit simulation
*/
$display("%t::Post-Suspend : smpl_clk=%b clk=%b", $time, smpl_clk, clk);
end
#10; // unreachable
clk = ~clk;
end
end
always # (clk) #10 clk <= ~clk;
initial while (1) // to see the loop, functionally equivalent to 'always'
begin // procedural block
begin : loop0_unraveled
#(clk); // suspend continuation of loop until change in clk
#10; // suspend continuation of loop 10 time units
clk <= ~clk; /* eval '~clk' now,
* update clk after all blocking statements are suspended
*/
end
begin : loop1_unraveled
begin // this block is functionally equivalent to '#(clk)'
reg smpl_clk; // local variable
smpl_clk = clk; // sample
$display("%t::Pre-Suspend : smpl_clk=%b clk=%b",$time, smpl_clk, clk);
wait(clk != smpl_clk); // suspend continuation of loop until true
/* 1. no other blocking statements can execute, go to next region
* 2. In NBA region update clk
* 3. Go back to active region
* 4. Eval true, continue
*/
$display("%t::Post-Suspend : smpl_clk=%b clk=%b", $time, smpl_clk, clk);
end
#10; // reached
clk <= ~clk;
end
end // Go to top of the loop
As I already mentioned here, self triggering blocks are not very common in practice. Clock generator are usually implanted something similar to:
initial begin
#10 clk = 0;
forever #10 clk = ~clk;
end
Or
always #10 clk = (clk===1'b0);
Related
I am not getting any response from the uut in the testbench. The module exp2_up_down_counter works ok without testbench, but gives output as xxxx when instantiated in the testbench.
Here is the main module of the up-down counter:
`timescale 1ns/1ps
module exp2_up_down_counter (input clk, reset, mode, output reg [3:0] count);
always #(posedge clk)
if (reset == 1)
count <= 0; // reset the counter if reset is high
else if (mode == 1)
count <= count + 1; // works as up counter if mode pin is high
else
count <= count - 1; // works as down counter if mode pin is low
endmodule
Simulation without testbench:
Testbench for up-down counter
`timescale 1ns/1ps
module exp2_up_down_counter_tb;
reg clk, reset, mode;
wire [3:0] count;
exp2_up_down_counter uut(.clk(clk), .reset(reset), .mode(mode), .count(count));
initial begin
clk = 1'b0;
end
always #(*) #5 clk <= ~clk;
initial begin
// initializing the inputs
reset = 1;
mode = 0;
#5;
reset = 0;
#10
mode = 1;
#5000 $finish;
end
endmodule
Simulation with testbench:
In exp2_up_down_counter, count is declared as a reg. This means that its default value is X at time 0. Since the reset signal is synchronous to the clock, you need to wait for the 1st posedge of clock before you release the reset. Currently, the reset is released at the 1st posedge of clock in the testbench, which is a race condition. Therefore, count does not get assigned the value of 0, and it retains the value of X for the whole simulation.
You need to delay the reset release. For example, change:
#5;
reset = 0;
to:
#15;
reset = 0;
However, it is better to drive your synchronous inputs in the testbench the same way you drive your signals in the design: using #(posedge clk) and using nonblocking assignments (<=):
initial begin
reset = 1;
mode = 0;
repeat (2) #(posedge clk);
reset <= 0;
repeat (1) #(posedge clk);
mode <= 1;
#5000 $finish;
end
Also, this is a more standard way to drive the clock in the testbench:
always #5 clk = ~clk;
I have a problem in the test bench code, and I am not getting correct waveforms. Even the clock does not trigger.
CODE for D Flipflop:
module D_FF(o,D,clk);
output reg o;
input D,clk;
always # (posedge clk)
begin
if(D==1'b1)begin
o=1'b1;
end
else begin
o=1'b0;
end
end
endmodule
Code for TestBench:
module DD_flipflop_tb();
reg clk,D;
wire o;
D_FF i1(o,D,clk);
initial begin
clk=1'b0;
D=1'b0;
end
always begin
#20 clk=~clk;
#35 D=~D;
#5000 $finish;
end
endmodule
Here is what happens in the always block in your testbench.
At time 0, clk and D are 0.
At time 20, you invert clk, which becomes 1.
At time 55, you invert D, which becomes 1.
At time 5055, you call $finish which terminates the simulation. The statements in the block only execute once, which is why your inputs never change more than once.
In your testbench, initialize them as 0 in an initial block, then separate the clock generation from the data signal.
initial begin
clk = 0;
forever #20 clk=~clk;
end
initial begin
D=0;
forever #35 D=~D;
end
initial #5000 $finish;
You might want to assign separately the clock and the stimulus in the testbench:
initial begin
clk = 0;
D = 0;
#5000 $finish;
end
//..clock
always
#20 clk = ~clk;
//..stimulus
always
#35 D = ~D;
I've encountered a test bench which can essentially be boiled down to the below example: clock and signals are changed in the in the same timestep with blocking assignments. I believe this causes a race condition between the clock and the two ctrlX signals, but I was unable to prove in the EDA playground (I understand it's beyond my control). Am I correct that there is a race condition?
(EDA Playground link: https://www.edaplayground.com/x/5yDX#&togetherjs=gkG5xewfNN)
module tb_example;
reg clk = 1;
reg [3:0] dff1,dff2;
reg [3:0] ctrl1 = 'd0;
reg [3:0] ctrl2 = 'd0;
initial begin
#10 ctrl1 = 'd1;
#20 ctrl1 = 'd2;
#10 ctrl1 = 'd3;
#100 $finish;
end
always begin
#5 clk = !clk;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars(0,tb_example);
end
initial begin
#10 ctrl2 = 'd1;
#20 ctrl2 = 'd2;
#10 ctrl2 = 'd3;
#100 $finish;
end
always # (posedge(clk)) begin
dff1 <= ctrl1;
end
always # (posedge(clk)) begin
dff2 <= ctrl2;
end
endmodule
Yes, this is a race condition because you are using blocking assignments for ctrlx and they are changing at the same time as posedge clk. So, the values assigned to dffx are indeterminate and can vary from simulator to simulator.
One way to avoid this is to change ctrlx on the negedge of clk:
reg clk = 0;
i got a code like below with clk = #10 ~clk
always# (posedge clk)begin
for (g=0;g<8;g=g+1) begin
ws = 1;
#20
ws = 0;
#20;
end
so is there any other way to make the delay 20 synthesizaeble in the coding above?
A flip-flop is the only way of synthesising a delay:
always #(posedge clk)
q <= d;
With clk = #10 ~clk;, q will be #10 later than d.
The question appear not to be how to synthesis a #20 but how to control the timing for signals in to a RAM. Digital design are based around clock edges, with each positive or negative edge a set distance a part, this is the period of the clock or 1/frequency.
To sequence events as you describe you need a FSM (Finite state machine) to control or sequence it. I have included a small example below:
Available on EDA Playground
module tb;
//Tb component
reg clk;
reg rst_n;
initial begin :clk_and_reset
clk = 0;
rst_n = 0;
#40 rst_n = 1;
#40;
forever begin
#20 clk = ~clk;
end
end
//Design
reg [1:0] state;
reg [1:0] next_state;
reg [31:0] counter;
reg ws;
localparam S_IDLE = 'd0;
localparam S_WAIT = 'd1;
localparam S_OFF = 'd2;
always #(posedge clk, negedge rst_n) begin
if (~rst_n) begin
state <= S_IDLE;
end
else begin
case(state)
S_IDLE : begin
state <= S_WAIT;
counter <= 'b0;
S_WAIT :
if (counter < 32'd10) begin
state <= S_WAIT; //Wait for 10 clock cycles
counter <= counter + 1;
end
else begin
state <= S_OFF;
counter <= 'b0;
end
S_OFF : state <= S_IDLE;
default : state <= S_IDLE; //IDLE
end
end
//Output decode based on state
always #* begin
//ws goes high when in Wait state
ws = (state == S_WAIT);
end
//Test program
initial begin
repeat (10) begin
#(posedge clk);
$display("%4t : State %b: ws :%b", $realtime, state, ws);
end
$finish();
end
endmodule
This could be expanded by staying in idle until triggered then by having counter and staying in wait for x number of clocks, x number of clocks in OFF before going back to idle and waiting to be triggered again.
Update
I have updated the code example to stay in the WAIT state for 10 clock cycles to demonstrate how to control the delay between transitions.
I am using this section in my testbench to give inputs .How can i use #(posedge clk) instead of #10 in this code
initial
clk=1'b0;
always #5 clk = ~clk;
initial begin
rst=1'b1;
# 10 rst=1'b0;
for (i=0;i<20;i=i+1)
begin
a=$random;
Pn=a[3];
Pe=a[2];
Ps=a[1];
Pw=a[0];
#10;
if (Pn==1) begin
Pn=0;
#10;
end
if (Pe==1) begin
Pe=0;
#10;
end
if (Ps==1) begin
Ps=0;
#10;
end
if (Pw==1) begin
Pw=0;
#10;
end
end
end
endmodule
This is the testbench for traffic control.I have tried by using #(posedge clk ) everywhere instead of #10 but its not working properly
With a positive clock edge every #10 these block would be equivalent:
Pn=0;
#10;
Pe=0;
#10;
Pn=1;
With posedge:
Pn=0
#(posedge clk);
Pe=0;
#(posedge clk);
Pn=1;
The #(posedge clk); just waits for the condition to be met before moving on to the next line of code. If the sequencing of the stimulus looks to be a clock cycle ahead now you may need to switch to non-blocking (<=) assignments in the testbench ie:
Pn <= 0
#(posedge clk);
Pe <= 0;
#(posedge clk);
Pn <= 1;
Also note that your clock generation logic generated the first posedge at time 5, and you changed data at 10. So you always changed data in between clock cycles which is not how it would be typically be driven if it came from another synchronous system.
initial begin
clk = 1'b0;
end
always begin
#5 clk = ~clk;
end
I find it more reliable to control the clock from one process/block :
initial begin
clk = 1'b0;
forever begin
#5 clk = ~clk;
end
end
You could then realign your clock to steps of 10 via:
initial begin
clk = 1'b0;
#5;
forever begin
#5 clk = ~clk;
end
end