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
Related
I am using Quartus Prime Lite 19.1.0.
module memory_address_register1 #(
parameter ADDR_WIDTH = 4
)(
input clk, rst, load,
input [ADDR_WIDTH-1:0] add_in,
output reg [ADDR_WIDTH-1:0] add_out
);
always #(posedge clk) begin
if (rst) begin
add_out <= 4'b0000;
end else if (load) begin
add_out <= add_in;
end else begin
add_out <= add_out;
end
end
endmodule
module mmr_tb();
reg clk, rst, load;
reg [3:0] add_in;
wire [3:0] add_out;
initial begin
clk <= 1'b0;
rst <= 1'b0;
load <= 1'b0;
end
memory_address_register1 mmr (.clk(clk), .rst(rst), .load(load), .add_in(add_in), .add_out(add_out));
always #10 clk = ~clk;
initial begin
#20 add_in <= 4'd2;
#10 add_in <= 4'd3;
load <= 1'b1;
#30 add_in <= 4'd6;
#10 load <= 1'b1;
end
endmodule
It the output (add_out) accurate? Should the output (add_out) at t=70.0ns be "6" or "7"?
If the expected output is "6", can anyone explain why is that?
img2: posedge clk output value from previous clk cycle
I ran the testbench using modelsim, and I am able to get the expected output I wanted (output on the exact clock edge), but is it expected?
https://imgur.com/a/M85zPKT
You have potential race conditions in your testbench code. You should drive all your inputs in the testbench the same way you drive them in the design:
Use nonblocking assignments (<=) instead of blocking assignments (=)
Use #(posedge clk) instead of # delays
This will guarantee that your inputs will be synchronous to the clock. This also assures that pulsewidths of your inputs are a multiple of the clock period. Some of your signals are half a period wide or 1.5 periods wide.
module mmr_tb();
reg clk, rst, load;
reg [3:0] add_in;
wire [3:0] add_out;
initial begin
clk <= 0;
rst <= 1;
load <= 0;
add_in <= 0;
repeat (2) #(posedge clk);
rst <= 0;
forever #(posedge clk) begin
add_in <= add_in + 1;
end
end
memory_address_register1 mmr (.clk(clk), .rst(rst), .load(load), .add_in(add_in), .add_out(add_out));
always #10 clk = ~clk;
initial begin
repeat (4) #(posedge clk); load <= ~load;
repeat (1) #(posedge clk); load <= ~load;
repeat (4) #(posedge clk); load <= ~load;
repeat (1) #(posedge clk); load <= ~load;
repeat (3) #(posedge clk); $finish;
end
endmodule
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 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);
As I have known, D flipflop samples its input value at every positive edge
of the clock.
Thus, it will produce a 1 cycle delay. Right?
But why does my D flip flop does not produce a 1 cycle delay?
module flipflop(
input clk,
input rstn,
input [7:0] i_data,
output reg [7:0] o_data
);
always #(posedge clk) begin
if (~rstn) begin
o_data <= 0;
end
else begin
o_data <= i_data;
end
end
endmodule
module test;
reg clk;
reg [7:0] i_data;
reg rstn;
wire [7:0] o_data;
initial begin
clk = 0;
rstn = 1;
i_data = 0;
#20;
rstn = 0;
#30;
rstn = 1;
#20;
i_data = 8'hFA;
#20;
i_data = 8'hF0;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
always #10 clk = !clk;
flipflop flipflop(
.clk (clk),
.rstn(rstn),
.i_data(i_data),
.o_data(o_data)
);
initial begin
$dumpfile("flipflop.vcd");
$dumpvars();
end
endmodule
My D flip flop functions like a combinational circuit here.
You've run up against Verilog simulator event scheduling subtleties! Changing the data assignments to use nonblocking assignments is probably the easiest fix.
#20;
i_data <= 8'hFA;
#20;
i_data <= 8'hF0;
#20
i_data <= 8'hF1;
#20
What was happening in your original version is that the clock and the input data were scheduled to happen at the same time. Since the simulator can only do one thing at a time, it has to decide if it will change the clock or the data first. It changed the data first, so when the clock edge comes along, the input data has already changed to the next value so it looks like the data is slipping through the FF.
Nonblocking assignments (<=) are scheduled to happen after all the blocking assignments (=) have been done. So making the data assignments nonblocking ensures that they happen after the blocking-assigned clock edges.
Another way to rewrite things to work would be:
initial begin
#(posedge clk) i_data = 8'hFA;
#(posedge clk) i_data = 8'hF0;
#(posedge clk) i_data = 8'hF1;
end
The simulator is probably doing something like this:
initial begin
clk = 0;
rstn = 1;
i_data = 0;
#10;
clk = !clk;
#10;
rstn = 0;
clk = !clk;
#10;
clk = !clk;
#10;
clk = !clk;
#10;
rstn = 1;
clk = !clk;
#10;
clk = !clk;
#10
i_data = 8'hFA; //Input updated
clk = !clk; //Clock event
//o_data assigned here
#10;
clk = !clk;
#10;
i_data = 8'hF0;
clk = !clk;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
Since the clock event is occurring last in each time step from your testbench, it looks like the flop is being assigned immediately. You likely want your testbench to be entirely slaved off the clock so Marty's suggestion of using #(posedge...) will achieve this. You could also simply delay your assignments once at the very beginning:
initial begin
clk = 0;
#1;
rstn = 1;
i_data = 0;
#20;
rstn = 0;
#30;
rstn = 1;
#20;
i_data = 8'hFA;
#20;
i_data = 8'hF0;
#20
i_data = 8'hF1;
#20
#10 $finish;
end