Chapter start

Previous page

Next page

11.13   Other Verilog Features

This section covers some of the more advanced Verilog features. System tasks and functions are defined as part of the IEEE Verilog standard [Verilog LRM14].

11.13.1   Display Tasks

The following code illustrates the display system tasks [Verilog LRM 14.1]:

module test_display; // display system tasks:
initial begin $display ("string, variables, or expression");
/* format specifications work like printf in C:
        %d=decimal %b=binary %s=string %h=hex %o=octal
        %c=character %m=hierarchical name %v=strength %t=time format
        %e=scientific %f=decimal %g=shortest
examples: %d uses default width %0d uses minimum width
        %7.3g uses 7 spaces with 3 digits after decimal point */
// $displayb, $displayh, $displayo print in b, h, o formats
// $write, $strobe, $monitor also have b, h, o versions
$write("write"); // as $display, but without newline at end of line
$strobe("strobe"); // as $display, values at end of simulation cycle
$monitor(v); // disp. @change of v (except v= $time,$stime,$realtime)
$monitoron; $monitoroff; // toggle monitor mode on/off
end endmodule

11.13.2   File I/O Tasks

The following example illustrates the file I/O system tasks [Verilog LRM 14.2]:

module file_1; integer f1, ch; initial begin f1 = $fopen("f1.out");
if(f1==0) $stop(2); if(f1==2)$display("f1 open"); 
ch = f1|1; $fdisplay(ch,"Hello"); $fclose(f1); end endmodule
> vlog file_1.v
> vsim -c file_1
# Loading work.file_1
VSIM 1> run 10
# f1 open
# Hello
VSIM 2> q
> more f1.out
Hello
>

The $fopen system task returns a 32-bit unsigned integer called a multichannel descriptor ( f1 in this example) unique to each file. The multichannel descriptor contains 32 flags, one for each of 32 possible channels or files (subject to limitations of the operating system). Channel 0 is the standard output (normally the screen), which is always open. The first call to $fopen opens channel 1 and sets bit 1 of the multichannel descriptor. Subsequent calls set higher bits. The file I/O system tasks: $fdisplay , $fwrite , $fmonitor , and $fstrobe ; correspond to their display counterparts. The first parameter for the file system tasks is a multichannel descriptor that may have multiple bits set. Thus, the preceding example writes the string "Hello" to the screen and to file1.out . The task $fclose closes a file and allows the channel to be reused.

The file I/O tasks $readmemb and $readmemh read a text file into a memory. The file may contain only spaces, new lines, tabs, form feeds, comments, addresses, and binary (for $readmemb ) or hex (for $readmemh ) numbers, as in the following example:

mem.dat
@2 1010_1111 @4 0101_1111 1010_1111 // @address in hex
x1x1_zzzz 1111_0000 /* x or z is OK */
module load; reg [7:0] mem[0:7]; integer i; initial begin
$readmemb("mem.dat", mem, 1, 6); // start_address=1, end_address=6
for (i= 0; i<8; i=i+1) $display("mem[%0d] %b", i, mem[i]);
end endmodule
> vsim -c load
# Loading work.load
VSIM 1> run 10
# ** Warning: $readmem (memory mem) file mem.dat line 2:
#    More patterns than index range (hex 1:6)
#    Time: 0 ns  Iteration: 0  Instance:/
# mem[0] xxxxxxxx
# mem[1] xxxxxxxx
# mem[2] 10101111
# mem[3] xxxxxxxx
# mem[4] 01011111
# mem[5] 10101111
# mem[6] x1x1zzzz
# mem[7] xxxxxxxx
VSIM 2> q
>

11.13.3   Timescale, Simulation, and Timing-Check Tasks

There are two timescale tasks, $printtimescale and $timeformat [Verilog LRM 14.3]. The $timeformat specifies the %t format specification for the display and file I/O system tasks as well as the time unit for delays entered interactively and from files. Here are examples of the timescale tasks:

// timescale tasks:
module a; initial $printtimescale(b.c1); endmodule
module b; c c1 (); endmodule
`timescale 10 ns / 1 fs
module c_dat; endmodule
`timescale 1 ms / 1 ns
module Ttime; initial $timeformat(-9, 5, " ns", 10); endmodule
/* $timeformat [ ( n, p, suffix , min_field_width ) ] ;
units = 1 second ** (-n), n = 0->15, e.g. for n = 9, units = ns
p = digits after decimal point for %t e.g. p = 5 gives 0.00000
suffix for %t (despite timescale directive)
min_field_width is number of character positions for %t */

The simulation control tasks are $stop and $finis h [Verilog LRM 14.4]:

module test_simulation_control; // simulation control system tasks:
initial begin $stop; // enter interactive mode (default parameter 1)
$finish(2); // graceful exit with optional parameter as follows:
// 0 = nothing 1 = time and location 2 = time, location, and statistics 
end endmodule

The timing-check tasks [Verilog LRM 14.5] are used in specify blocks. The following code and comments illustrate the definitions and use of timing-check system tasks. The arguments to the tasks are defined and explained in Table 11.11.

TABLE 11.11    Timing-check system task parameters.

Timing task argument

  Description of argument

Type of argument

reference_event

to establish reference time

module input or inout

(scalar or vector net)

data_event

signal to check against reference_event

module input or inout

(scalar or vector net)

limit

time limit to detect timing violation on data_event

constant expression

or specparam

threshold

largest pulse width ignored by timing check $width

constant expression

or specparam

notifier

flags a timing violation (before -> after):

x->0, 0->1, 1->0, z->z

register

module timing_checks (data, clock, clock_1,clock_2); 
input data,clock,clock_1,clock_2; reg tSU,tH,tHIGH,tP,tSK,tR;
specify // timing check system tasks:
/* $setup (data_event, reference_event, limit [, notifier]);
violation = (T_reference_event)-(T_data_event) < limit */
$setup(data, posedge clock, tSU);
/* $hold (reference_event, data_event, limit [, notifier]);
violation = 
  (time_of_data_event)-(time_of_reference_event) < limit */
$hold(posedge clock, data, tH);
/* $setuphold (reference_event, data_event, setup_limit,
    hold_limit [, notifier]);
parameter_restriction = setup_limit + hold_limit > 0 */
$setuphold(posedge clock, data, tSU, tH);
/* $width (reference_event, limit, threshold [, notifier]);
violation = 
  threshold < (T_data_event) - (T_reference_event) < limit
reference_event = edge
data_event = opposite_edge_of_reference_event */
$width(posedge clock, tHIGH);
/* $period (reference_event, limit [, notifier]);
violation = (T_data_event) - (T_reference_event) < limit
reference_event = edge
data_event = same_edge_of_reference event */
$period(posedge clock, tP);
/* $skew (reference_event, data_event, limit [, notifier]);
violation = (T_data_event) - (T_reference_event) > limit */
$skew(posedge clock_1, posedge clock_2, tSK);
/* $recovery (reference_event, data_event, limit, [, notifier]);
violation = (T_data_event) - (T_reference_event) < limit */
$recovery(posedge clock, posedge clock_2, tR);
/* $nochange (reference_event, data_event, start_edge_offset,
  end_edge_offset [, notifier]);
reference_event = posedge | negedge
violation = change while reference high (posedge)/low (negedge)
+ve start_edge_offset moves start of window later
+ve end_edge_offset moves end of window later */
$nochange (posedge clock, data, 0, 0);
endspecify endmodule 

You can use edge specifiers as parameters for the timing-check events (except for the reference event in $nochange):

edge_control_specifier ::= edge [edge_descriptor {, edge_descriptor}]
edge_descriptor ::= 01 | 0x | 10 | 1x | x0 | x1

For example, 'edge [01, 0x, x1] clock' is equivalent to 'posedge clock' . Edge transitions with 'z' are treated the same as transitions with 'x' .

Here is a D flip-flop model that uses timing checks and a notifier register. The register, notifier, is changed when a timing-check task detects a violation and the last entry in the table then sets the flip-flop output to unknown.

primitive dff_udp(q, clock, data, notifier);
output q; reg q; input clock, data, notifier;
table //   clock data  notifier:state:  q
           r     0     ?      :  ?  :  0 ;
           r     1     ?      :  ?  :  1 ;
           n     ?     ?      :  ?  :  - ;
           ?     *     ?      :  ?  :  - ;
           ?     ?     *      :  ?  :  x ; endtable // notifier
endprimitive 
`timescale 100 fs / 1 fs
module dff(q, clock, data); output q; input clock, data; reg notifier;
dff_udp(q1, clock, data, notifier); buf(q, q1);
specify
  specparam tSU = 5, tH = 1, tPW = 20, tPLH = 4:5:6, tPHL = 4:5:6;
     (clock *> q) = (tPLH, tPHL);
  $setup(data, posedge clock, tSU, notifier); // setup: data to clock
  $hold(posedge clock, data, tH, notifier); // hold: clock to data
  $period(posedge clock, tPW, notifier); // clock: period
endspecify 
endmodule

11.13.4   PLA Tasks

The PLA modeling tasks model two-level logic [Verilog LRM 14.6]. As an example, the following eqntott logic equations can be implemented using a PLA:

b1 = a1 & a2; b2 = a3 & a4 & a5 ; b3 = a5 & a6 & a7;

The following module loads a PLA model for the equations above (in AND logic) using the array format (the array format allows only '1' or '0' in the PLA memory, or personality array). The file array.dat is similar to the espresso input plane format.

array.dat
1100000
0011100
0000111
module pla_1 (a1,a2,a3,a4,a5,a6,a7,b1,b2,b3);
input a1, a2, a3, a4, a5, a6, a7 ; output b1, b2, b3;
reg [1:7] mem[1:3]; reg b1, b2, b3;
initial begin
  $readmemb("array.dat", mem);
  #1; b1=1; b2=1; b3=1;
  $async$and$array(mem,{a1,a2,a3,a4,a5,a6,a7},{b1,b2,b3});
end
initial $monitor("%4g",$time,,b1,,b2,,b3);
endmodule

The next example illustrates the use of the plane format, which allows '1' , '0' , as well as '?' or 'z' (either may be used for don't care) in the personality array.

b1 = a1 & !a2; b2 = a3; b3 = !a1 & !a3; b4 = 1;
module pla_2; reg [1:3] a, mem[1:4]; reg [1:4] b;
initial begin
  $async$and$plane(mem,{a[1],a[2],a[3]},{b[1],b[2],b[3],b[4]});
  mem[1] = 3'b10?; mem[2] = 3'b??1; mem[3] = 3'b0?0; mem[4] = 3'b???;
  #10 a = 3'b111; #10 $displayb(a, " -> ", b);
  #10 a = 3'b000; #10 $displayb(a, " -> ", b);
  #10 a = 3'bxxx; #10 $displayb(a, " -> ", b);
  #10 a = 3'b101; #10 $displayb(a, " -> ", b);
end endmodule 
111 -> 0101
000 -> 0011
xxx -> xxx1
101 -> 1101

11.13.5   Stochastic Analysis Tasks

The stochastic analysis tasks model queues [Verilog LRM 14.7]. Each of the tasks return a status as shown in Table 11.12.

TABLE 11.12    Status values for the stochastic analysis tasks.

Status value

Meaning

0

OK

1

queue full, cannot add

2

undefined q_id

3

queue empty, cannot remove

4

unsupported q_type , cannot create queue

5

max_length <= 0, cannot create queue

6

duplicate q_id , cannot create queue

7

not enough memory, cannot create queue

The following module illustrates the interface and parameters for these tasks:

module stochastic; initial begin // stochastic analysis system tasks:
/* $q_initialize (q_id, q_type, max_length, status) ;
q_id is an integer that uniquely identifies the queue
q_type 1=FIFO 2=LIFO
max_length is an integer defining the maximum number of entries */
$q_initialize (q_id, q_type, max_length, status) ;
/* $q_add (q_id, job_id, inform_id, status) ;
job_id = integer input
inform_id = user-defined integer input for queue entry */
$q_add (q_id, job_id, inform_id, status) ;
/* $q_remove (q_id, job_id, inform_id, status) ; */
$q_remove (q_id, job_id, inform_id, status) ;
/* $q_full (q_id, status) ;
status = 0 = queue is not full, status = 1 = queue full */
$q_full (q_id, status) ;
/* $q_exam (q_id, q_stat_code, q_stat_value, status) ;
q_stat_code is input request as follows:
1=current queue length 2=mean inter-arrival time 3=max. queue length
4=shortest wait time ever
5=longest wait time for jobs still in queue 6=ave. wait time in queue
q_stat_value is output containing requested value */
$q_exam (q_id, q_stat_code, q_stat_value, status) ;
end endmodule

11.13.6   Simulation Time Functions

The simulation time functions return the time as follows [Verilog LRM 14.8]:

module test_time; initial begin // simulation time system functions:
$time ;
// returns 64-bit integer scaled to timescale unit of invoking module 
$stime ;
// returns 32-bit integer scaled to timescale unit of invoking module 
$realtime ;
// returns real scaled to timescale unit of invoking module 
end endmodule

11.13.7    Conversion Functions

The conversion functions for reals handle real numbers [Verilog LRM 14.9]:

module test_convert; // conversion functions for reals:
integer i; real r; reg [63:0] bits;
initial begin #1 r=256;#1 i = $rtoi(r);
#1; r = $itor(2 * i) ; #1 bits = $realtobits(2.0 * r) ;
#1; r = $bitstoreal(bits) ; end
initial $monitor("%3f",$time,,i,,r,,bits); /*
$rtoi converts reals to integers w/truncation e.g. 123.45 -> 123
$itor converts integers to reals e.g. 123 -> 123.0
$realtobits converts reals to 64-bit vector
$bitstoreal converts bit pattern to real
Real numbers in these functions conform to IEEE Std 754. Conversion rounds to the nearest valid number. */
endmodule
# 0.000000           x 0                    x
# 1.000000           x 256                    x
# 2.000000         256 256                    x
# 3.000000         256 512                    x
# 4.000000         256 512  4652218415073722368
# 5.000000         256 1024  4652218415073722368

Here is an example using the conversion functions in port connections:

module test_real;wire [63:0]a; driver d (a); receiver r (a);
initial $monitor("%3g",$time,,a,,d.r1,,r.r2); endmodule
module driver (real_net);
output real_net; real r1; wire [64:1] real_net = $realtobits(r1); 
initial #1 r1 = 123.456; endmodule
module receiver (real_net);
input real_net; wire [64:1] real_net; real r2;
initial assign r2 = $bitstoreal(real_net);
endmodule
# 0                    0 0 0
# 1  4638387860618067575 123.456 123.456

11.13.8   Probability Distribution Functions

The probability distribution functions are as follows [Verilog LRM 14.10]:

module probability; // probability distribution functions:
/* $random [ ( seed ) ] returns random 32-bit signed integer 
seed = register, integer, or time */
reg [23:0] r1,r2; integer r3,r4,r5,r6,r7,r8,r9;
integer seed, start, \end , mean, standard_deviation;
integer degree_of_freedom, k_stage;
initial begin seed=1; start=0; \end =6; mean=5; 
standard_deviation=2; degree_of_freedom=2; k_stage=1; #1;
r1 = $random % 60; // random -59 to 59
r2 = {$random} % 60; // positive value 0-59 
r3=$dist_uniform (seed, start, \end ) ; 
r4=$dist_normal (seed, mean, standard_deviation) ;
r5=$dist_exponential (seed, mean) ;
r6=$dist_poisson (seed, mean) ;
r7=$dist_chi_square (seed, degree_of_freedom) ;
r8=$dist_t (seed, degree_of_freedom) ;
r9=$dist_erlang (seed, k_stage, mean) ; end 
initial #2 $display ("%3f",$time,,r1,,r2,,r3,,r4,,r5); 
initial begin #3; $display ("%3f",$time,,r6,,r7,,r8,,r9); end
/* All parameters are integer values. 
Each function returns a pseudo-random number 
e.g. $dist_uniform returns uniformly distributed random numbers 
mean, degree_of_freedom, k_stage 
(exponential, poisson, chi-square, t, erlang) > 0.
seed = inout integer initialized by user, updated by function 
start, end ($dist_uniform) = integer bounding return values */
endmodule
2.000000        8       57           0           4           9
3.000000           7           3           0           2

11.13.9   Programming Language Interface

The C language Programming Language Interface ( PLI) allows you to access the internal Verilog data structure [Verilog LRM17-23, A-E]. For example, you can use the PLI to implement the following extensions to a Verilog simulator:

There are three generations of PLI routines (see Appendix B for an example):


Chapter start

Previous page

Next page