Академический Документы
Профессиональный Документы
Культура Документы
endmodule
module try;
time delay_time = 7.721;
initial begin
$display("STATEMENT 2 :: delay for %0t",delay_time );
end
endmodule
RESULTS:
STATEMENT 1 :: time is 8
STATEMENT 2 :: delay for 80000
reg i toggled at 77.212 in waveform debugger
In the timescale statement, the first value is the time unit and the second is the
precision for the simulation. So with the time unit, when the simulator displays a
value, you just have to multiply the value by this time unit to get the real time. With
a 10ns time unit, when a delay of #7.7212, that means that it is 77.212ns delay.
Now the second one (time precision) specify with which precision time values are
rounded. Asking for a 77.212ns delay is possible only with a 1ps precision. That's
what you can see with reg i. It toggles at 77ns with a 1ns precision and 77.212 with
a 1ps precision.
For the STATEMENT 1, $stime returns an integer scaled to timesale unit, that's why
results are always 8 which is 7.7212 rounded up to 8.
Now for STATEMENT 2, the way %t is printed depends on $timeformat. It seems that
in this case, 7.7212 is first rounded to an integer => 8 and then printed according
to your time precision.
Each module can have separate time scale. The smallest time_precision argument
of all the timescale compiler directives in the design determines the precision of the
time unit of the simulation.
Lets take an example. There are two modules. Module_1 is instance od Module_2.
Module_1 has timescale of 1 ns/1ps. Module_2 has time scale of 1ns / 10ps. The
smallest resolution is 1ps. This is taken as simulator resolution but each module
evaluates according to its precision mentioned.
Lets take another example. There are two modules. Module_1 is instance of
Module_2. Module_1 does not have any time scale. Module_2 is having time scale of
1ns/100 ps. As there is no time scale for Module_1 ,the simulator takes precision
-1
-2
-3
-4
-5
-6
-7
100 ms
10 ms
1 ms
100 us
10 us
1 us
100 ns
-9
-10
-11
-12
-13
-14
-15
1 ns
100 ps
10 ps
1 ps
100 fs
10 fs
1 fs
Syntax : $timeformat(time unit, precision number, suffix string, and minimum field
width);
EXAMPLE:
`timescale 1 ms / 1 ns
module cntrl;
initial
$timeformat(-9, 5, " ns", 10);
endmodule
`timescale 1 fs / 1 fs
module a1_dat;
reg in1;
integer file;
buf #10000000 (o1,in1);
initial begin
file = $fopen("a1.dat");
#00000000 $fmonitor(file,"%m: %t in1=%d o1=%h", $realtime,in1,o1);
#10000000 in1 = 0;
#10000000 in1 = 1;
end
endmodule
RESULTS:
a1_dat: 0.00000 ns in1= x o1=x
a1_dat: 10.00000 ns in1= 0 o1=x
a1_dat: 20.00000 ns in1= 1 o1=0
a1_dat: 30.00000 ns in1= 1 o1=1
EXAMPLE:
`timescale 1 ms / 1 ns
module cntrl;
initial
$timeformat(-9, 5, " ns", 10);
endmodule
`timescale 1 ps / 1 ps
module a2_dat;
reg in2;
integer file2;
buf #10000 (o2,in2);
initial begin
file2=$fopen("a2.dat");
#00000 $fmonitor(file2,"%m: %t in2=%d o2=%h",$realtime,in2,o2);
#10000 in2 = 0;
#10000 in2 = 1;
end
endmodule
RESULTS:
a2_dat:
a2_dat:
a2_dat:
a2_dat:
RACE CONDITION
Verilog is easy to learn because its gives quick results. Although many users are
telling that their work is free from race condition. But the fact is race condition is
easy to create, to understand, to document but difficult to find. Here we will discuss
regarding events which creates the race condition & solution for that.
What Is Race Condition?
When two expressions are scheduled to execute at same time, and if the order of
the execution is not determined, then race condition occurs.
EXAMPLE
module race();
wire p;
reg q;
assign p = q;
initial begin
q = 1;
#1 q = 0;
$display(p);
end
endmodule
EXAMPLE
module race();
wire p;
reg q;
assign p = q;
initial begin
q = 1;
#1 q = 0;
$display(p);
end
endmodule
which causes the race condition. So it is impossible to avoid the race conditions
from the language but we can avoid from coding styles.
Look at following code. Is there any race condition?
EXAMPLE:
initial
begin
in = 1;
out <= in;
end
EXAMPLE
initial
begin
out <= in;
in = 1;
end
Sometimes unexpected output gives clue to search for race. Even if race condition
is existing in code, and if the output is correct, then one may not realize that there
exists race condition in their code. This type of hidden race conditions may come
out during the following situation.
When different simulators are used to run the same code.
Some times when the new release of the simulator is used.
Adding more code to previous code might pop out the previously hidden race.
If the order of the files is changed.
When using some tool specific options.
If the order of the concurrent blocks or concurrent statements is changed.(One
example is already discussed in the previous topics)
Some simulators have special options which reports where exactly the race
condition is exists. Linting tools can also catch race condition.
There are many details which is unspecified between simulators. The problem will
be realized when you are using different simulators. If you are limited to design
guidelines then there is less chance for race condition but if you are using Verilog
with all features for Testbench, then it is impossible to avoid. Moreover the language
which you are using is parallel but the processor is sequential. So you cant prevent
race condition.
Write-Write Race:
EXAMPLE:
always @(posedge clk)
a = 1;
always @(posedge clk)
a = 5;
Here you are seeing that one block is updating value of a while another also. Now
which always block should go first. This is nondeterministic in IEEE standard and left
that work to the simulator algorithm.
Read-Write Race:
it occurs when same register is read in one block and writes in another.
EXAMPLE:
always @(posedge clk)
a = 1;
always @(posedge clk)
b = a;
Here you are seeing that in one always block value is assign to a while
simultaneously its value is assign to b means a is writing and read parallel. This
type of race condition can easily solved by using nonblocking assignment.
EXAMPLE
always @(posedge clk)
a <= 1;
always @(posedge clk)
b <= a;
More Race Example:
1) Function calls
EXAMPLE:
function incri();
begin
pkt_num = pkt_num + 1;
end
endfunction
always @(...)
sent_pkt_num = incri();
always @(...)
sent_pkt_num_onemore = incri();
2) Fork join
EXAMPLE:
fork
a =0;
b = a;
join
3) $random
EXAMPLE:
always @(...)
$display("first Random number is %d",$random());
always @(...)
$display("second Random number is %d",$random());
4) Clock race
EXAMPLE
initial
clk = 0;
always
clk = #5 ~clk;
If your clock generator is always showing "X" then there is a race condition. There is
one more point to be noted in above example. Initial and always starts executes at
time zero.
5) Declaration and initial
EXAMPLE:
reg a = 0;
initial
a = 1;
EXAMPLE:
module DUT();
input d;
input clock;
output q;
always @(posedge clock)
q = d;
endmodule
module testbench();
DUT dut_i(d,clk,q);
initial
begin
@(posedge clk)
d = 1;
@(posedge clock)
d = 0;
end
endmodule
The above example has write read race condition.
Event Terminology:
Every change in value of a net or variable in the circuit being simulated, as well as
the named event, is considered an update event. Processes are sensitive to update
events. When an update event is executed, all the processes that are sensitive to
that event are evaluated in an arbitrary order. The evaluation of a process is also an
event, known as an evaluation event.
In addition to events, another key aspect of a simulator is time. The term simulation
time is used to refer to the time value maintained by the simulator to model the
actual time it would take for the circuit being simulated. The term time is used
interchangeably with simulation time in this section. Events can occur at different
times. In order to keep track of the events and to make sure they are processed in
the correct order, the events are kept on an event queue, ordered by simulation
time. Putting an event on the queue is called scheduling an event.
The Verilog event queue is logically segmented into five different regions. Events
are added to any of the five regions but are only removed from the active region.
1) Events that occur at the current simulation time and can be processed in any
order. These are the
active events.
1.1 evaluation of blocking assignment.
1.2 evaluation of RHS of nonblocking assignment.
1.3 evaluation of continuous assignment.
1.4 evaluation of primitives I/Os
1.5 evaluation of $display or $write
2) Events that occur at the current simulation time, but that shall be processed after
all the active events are processed. These are the inactive events.
#0 delay statement.
3) Events that have been evaluated during some previous simulation time, but that
shall be assigned at this simulation time after all the active and inactive events are
processed. These are the nonblocking assign update events.
4) Events that shall be processed after all the active, inactive, and non blocking
assign update events are processed. These are the monitor events.
$strobe and $monitor
5) Events that occur at some future simulation time. These are the future events.
Future events are divided into future inactive events, and future non blocking
assignment update events.
Example : PLI tasks
The processing of all the active events is called a simulation cycle.
Determinism
initial begin
a <= 0;
a <= 1;
end
When this block is executed, there will be two events added to the non blocking
assign update queue. The previous rule requires that they be entered on the queue
in source order; this rule requires that they be taken from the queue and performed
in source order as well. Hence, at the end of time step 1, the variable a will be
assigned 0 and then 1.
Nondeterminism
One source of nondeterminism is the fact that active events can be taken off the
queue and processed in any order. Another source of nondeterminism is that
statements without time-control constructs in behavioral blocks do not have to be
executed as one event. Time control statements are the # expression and @
expression constructs. At any time while evaluating a behavioral statement, the
simulator may suspend execution and place the partially completed event as a
pending active event on the event queue. The effect of this is to allow the
interleaving of process execution. Note that the order of interleaved execution is
nondeterministic and not under control of the user.
Race condition may occurs between DUT and testbench. Sometimes verification
engineers are not allowed to see the DUT, Sometimes they don't even have DUT to
verify. Consider the following example. Suppose a testbench is required to wait for a
specific response from its DUT. Once it receives the response, at the same
simulation time it needs to send a set of stimuli back to the DUT.
Most Synchronous DUT works on the posedge of clock. If the Testbench is also
taking the same reference, then we may unconditionally end in race condition. So
it~Rs better to choose some other event than exactly posedge of cock. Signals are
stable after the some delay of posedge of clock. Sampling race condition would be
proper if it is done after some delay of posedge of clock. Driving race condition can
be avoided if the signal is driven before the posedge of clock, so at posedge of clock
,the DUT samples the stable signal. So engineers prefer to sample and drive on
negedge of clock, this is simple and easy to debug in waveform debugger also.
TASK AND FUNCTION
Tasks and functions can bu used to in much the same manner but there are some
important differences that must be noted.
Functions
A function is unable to enable a task however functions can enable other functions.
A function will carry out its required duty in zero simulation time.
Within a function, no event, delay or timing control statements are permitted.
In the invocation of a function there must be at least one argument to be passed.
Functions will only return a single value and cannot use either output or inout
statements.
Functions are synthesysable.
Disable statements cannot be used.
Function cannot have nonblocking statements.
EXAMPLE:function
module function_calling(a, b,c);
input a, b ;
output c;
wire c;
function myfunction;
input a, b;
begin
myfunction = (a+b);
end
endfunction
assign c = myfunction (a,b);
endmodule
Task
Tasks are capable of enabling a function as well as enabling other versions of a Task
Tasks also run with a zero simulation however they can if required be executed in a
non zero simulation time.
Tasks are allowed to contain any of these statements.
A task is allowed to use zero or more arguments which are of type output, input or
inout.
A Task is unable to return a value but has the facility to pass multiple values via the
output and inout statements.
Tasks are not synthesisable.
Disable statements can be used.
EXAMPLE:task
module traffic_lights;
reg clock, red, amber, green;
parameter on = 1, off = 0, red_tics = 350,
amber_tics = 30, green_tics = 200;
initial red = off;
initial amber = off;
SystemVerilog.
Why a function should have at least one input?
There is no strong reason for this in verilog. I think this restriction is not removed fin
SystemVerilog. Some requirements where the inputs are taken from the global
signal, those functions don~Rt need any input. A work around is to use a dummy
input. If you have a better reason, just mail me at gopi@testbench.in
Why a task cannot return a value?
If tasks can return values, then Lets take a look at the following example.
A=f1(B)+f2(C);
and f1 and f2 had delays of say 5 and 10? When would B and C be sampled, or
global inside f1 and f2 be sampled? How long does then entire statement block?
This is going to put programmers in a bad situation. So languages gurus made that
tasks can't return .
Why a function cannot have delays?
The answer is same as above. But in Open Vera, delays are allowed in function. A
function returns a value and therefore can be used as a part of any expression. This
does not allow any delay in the function.
Constant Function:
Constant function calls are used to support the building of complex calculations of
values at elaboration time. A constant function call shall be a function invocation of
a constant function local to the calling module where the arguments to the function
are constant expressions.
EXAMPLE:constant function.
module ram_model (address, write, chip_select, data);
parameter data_width = 8;
parameter ram_depth = 256;
localparam adder_width = clogb2(ram_depth);
input [adder_width - 1:0] address;
Tasks and functions without the optional keyword automatic are static , with all
declared items being statically allocated. These items shall be shared across all
uses of the task and functions executing concurrently. Task and functions with the
optional keyword automatic are automatic tasks and functions. All items declared
inside automatic tasks and functions are allocated dynamically for each invocation.
Automatic task items and function items cannot be accessed by hierarchical
references.
EXAMPLE:
module auto_task();
task automatic disp;
input integer a;
input integer d;
begin
#(d) $display("%t d is %d a is %d", $time,d,a);
end
endtask
initial
#10 disp(10,14);
initial
#14 disp(23,18);
initial
#4 disp(11,14);
initial
#100 $finish;
endmodule
RESULTS:
18 d is 14 a is 11
24 d is 14 a is 10
32 d is 18 a is 23
EXAMPLE:
module tryfact;
// define the function
function automatic integer factorial;
input [31:0] operand;
integer i;
if (operand >= 2)
factorial = factorial (operand - 1) * operand;
else
factorial = 1;
endfunction
// test the function
integer result;
integer n;
initial begin
for (n = 0; n <= 7; n = n+1) begin
result = factorial(n);
$display("%0d factorial=%0d", n, result);
end
end
endmodule // tryfact
RESULTS:
0
1
2
3
4
factorial=1
factorial=1
factorial=2
factorial=6
factorial=24
5 factorial=120
6 factorial=720
7 factorial=5040
WATCHDOG
A watchdog timer is a piece of code, that can take appropriate action when it judges
that a system is no longer executing the correct sequence of code. In this topic ,I
will discuss exactly the sort of scenarios a watch dog can detect, and the decision
that must be made by watchdog. Generally speaking, a watchdog timer is based on
a counter that counts down from some initial value to zero. If the counter reaches,
then the appropriate action is take. If the required functionality is archived,
watchdog can be disabled.
In software world, in watchdog articles you will see various terms like strobing,
stroking etc. In this topic I will use more visual metaphor of man kicking the dog
periodically-with apologies to animal lovers. If the man stops kicking the dog, the
dog will take advantage of hesitation and bite the man. The man has to take a
proper decision for the dog bite. The process of restarting the watchdog timer's
counter is sometimes called "kicking the dog.".Bugs in DUT can cause the testbench
to hang, if they lead to an infinite loop and creating a deadlock condition. A properly
designed watchdog should catch events that hang the testbench.
Once your watchdog has bitten ,you have to decide what action to be taken. The
testbench will usually assert the error message, other actions are also possible like
directly stop simulation or just give a warning in performance tests.
In the following example, I have taken a DUT model so its easy to understand than a
RTL to demonstrate watchdog.
DUT PROTOCOL:
DUT has 3 signals.Clock a,b;
output b should be 1 within 4 clock cycles after output a became 1.
There are two scenarios I generated in DUT. one is following the above protocol and
the other violated the above rule. The testbench watchdog shows how it caught
`ifdef
`else
`elsif
`endif
`ifndef
The `ifdef compiler directive checks for the definition of a text_macro_name. If the
text_macro_name is defined, then the lines following the `ifdef directive are
included. If the text_macro_name is not defined and an `else directive exists, then
this source is
compiled. The `ifndef compiler directive checks for the definition of a
text_macro_name. If the text_macro_name is not defined, then the lines following
the `ifndef directive are included. If the text_macro_name is defined and an `else
directive exists, then this source is compiled. If the `elsif directive exists (instead of
the `else) the compiler checks for the definition of the text_macro_name. If the
name exists the lines following the `elsif directive are included. The `elsif directive
is equivalent to the compiler directive sequence `else `ifdef ... `endif. This directive
does not need a corresponding `endif directive. This directive must be preceded by
an `ifdef or `ifndef directive.
EXAMPLE:
module switches();
initial
begin
`ifdef TYPE_1
$display(" TYPE_1 message ");
`else
`ifdef TYPE_2
$display(" TYPE_2 message ");
`endif
`endif
end
endmodule
RESULT:
TYPE_1 message
RESULT:
TYPE_2 message
EXAMPLE:
module switches();
initial
begin
if($test$plusargs("TYPE_1"))
$display(" TYPE_1 message ");
else
if($test$plusargs("TYPE_2"))
$display(" TYPE_2 message ");
end
endmodule
RESULT:
TYPE_1 message
RESULT:
TYPE_2 message
This system function searches the list of plusargs (like the $test$plusargs system
function) for a user specified plusarg string. The string is specified in the first
argument to the system function as either a string or a register which is interpreted
as a string. If the string is found, the remainder of the string is converted to the type
specified in the user_string and the resulting value stored in the variable provided. If
a string is found, the function returns a non-zero integer. If no string is found
matching, the function returns the integer value zero and the variable provided is
not modified.
%d decimal conversion
%o octal conversion
%h hexadecimal conversion
%b binary conversion
%e real exponential conversion
%f real decimal conversion
%g real decimal or exponential conversion
Example
module valuetest();
integer i;
real r;
reg [11:0] v;
reg [128:0] s;
initial
begin
if($value$plusargs("STRING=%s",s))
$display(" GOT STRING ");
if($value$plusargs("INTG=%d",i))
$display(" GOT INTEGER ");
if($value$plusargs("REAL=%f",r))
$display(" GOT REAL ");
if($value$plusargs("VECTOR=%b",v))
$display(" GOT VECTOR ");
$display( " String is %s ",s);
$display(" Integer is %d ",i);
$display(" Realnum is %f ",r);
$display(" Vector is %b ",v);
end
endmodule
Compilation :
command filename.v
Simulation :