Verilog Language Reference Guide

Bit-select

Block Statements

Built-in Primitives

Case Statement

Continuous Assignments

Conversion Functions

Comments

Compiler Directives

Concatenations

Conditional Operator

Delays

Disable Statement

Display Tasks

Edge Sensitive Path

Expression Bit Length

File I/O Functions

Functions

Identifiers

If Statement

Integer Constants

Intra-assignment Timing Controls

Keywords

Loop Statements

Memories

min:typ:max Delays

Module Declaration

Module Instantiation

Module Path Declaration

Module Path Polarity

Net Data Types

Operators

Parameters

Part-select

PLA Modeling Tasks

Probabilistic Distribution Functions

Procedural Assignments

Procedural Continuous Assignments

Procedural Timing Control

Range Specification

Real Constants

Register Data Types

Simulation Control Tasks

Simulation Time Functions

Specify Block

State Dependent Path

Stochastic Analysis Tasks

Strengths

Strings

Structured Procedures

Tasks

Timescale System Tasks

Timing Check Tasks

UDP Declaration

UDP Instantiation

UDP State Table

Value Change Dump (VCD) File

Vectors


Bit-select

Formal Definition:

The bit-select provides an access to individual bits of vectors.

Complete description: Language Reference Manual section §4.2.1.

Simplified Syntax:

vector_identifier[expression];

Description:

The bit-select can be used to access individual bits of vector net or register data types. The bits can be addressed by using an expression. If the expression value is out of bounds or it returns z or x values, then the value returned by the reference is x. If one or more bits of the address returned by the expression have an x or z value, then the address expression is x.

The bit-select can be applied to any net vectors, regs, integers, and time register data types. The bit-selection of a register declared as real or realtime is illegal.

Examples:

Example 1

reg [3:0] vect;

vect = 4'b0001;

If the value of address expression is 0 then returned value is 1 (vect[0] = 1).

If the value of address expression is 3 then returned value is 0 (vect[3] = 0).

If the value of address expression is 4 then returned value is x (vect[4] = x).

If the value of address expression is x or z then returned value is x (vect[1’bx] = x).

Example 2

reg [0:3] vect;

vect = 4'b0001;

If the value of address expression is 3 then returned value is 1 (vect[3] = 1).

If the value of address expression is 0 then returned value is 0 (vect[0] = 0).

Example 3

reg [7:0] vect;

vect = 4;

Fills vect with the pattern 00000100 (MSB is bit 7, LSB is bit 0).

Important Notes:

  1. If the address expression is out of bounds or it returns an x or z value, then the returned value is x.

  2. The bit-select of real or realtime registers is illegal.


Block Statements

Formal Definition:

The block statements provide a means of grouping two or more statements in the block.

Complete description: Language Reference Manual section §9.8.

Simplified Syntax:

begin : name

statement;

...

end

fork : name

statement;

...

end

Description:

The Verilog HDL contains two types of blocks:

  • Sequential (begin-end blocks).

  • Parallel (fork-join blocks).

These blocks can be used if more than one statement should be executed.

All statements within sequential blocks (Example 1) are executed in the order in which they are given. If a timing control statement appears within a block, then the next statement will be executed after that delay.

All statements within parallel blocks (Example 2) are executed at the same time. This means that the execution of the next statement will not be delayed even if the previous statement contains a timing control statement.

Examples:

Example 1

begin

a = 1;

#10 a = 0;

#5 a = 4;

end

During the simulation, this block will be executed in 15 time units. At time 0, the ‘a’ variable will be 1, at time 10 the ‘a’ variable will be 0, and at time 15 (#10 + #5) the ‘a’ variable will be 4.

Example 2

fork

a = 1;

#10 a = 0;

#5 a = 4;

join

During the simulation this block will be executed in 10 time units. At time 0 the ‘a’ variable will be 1, at time 5 the ‘a’ variable will be 4, and at time 10 the ‘a’ variable will be 0.

Example 3

begin

a = 1;

@(b);

a = 0;

join

During the simulation when this block is executed ‘a’ becomes 1 and when a change occurs on ‘b’, then ‘a’ changes to 0. Flow of the procedural block is suspended when the @(b) statement is reached awaiting a change in value of ‘b’ before procedure block activities resume.

Important Notes:

  1. In parallel blocks all statements are executed at the same time, so there must not be any mutual dependent assignments.


Build-in Primitives

Formal Definition:

The build-in primitives provide a means of gate and switch modeling.

Complete description: Language Reference Manual section §7.1.

Simplified Syntax:

For and, nand, or, nor, xor, xnor, buf, not

gate (drive_strength) #(2delays) instance_name[range] (list_of_ports);

For bufif0, bufif1, notif0, notif1

gate (drive_strength) #(3delays) instance_name[range] (list_of_ports);

For nmos, pmos, rnmos, rpmos, cmos, rcmos, rtranif0, rtranif1, tranif0, tranif1

gate #(3delays) instance_name[range] (list_of_ports);

For tran, rtran

gate instance_name[range] (list_of_ports);

pullup (pullup_strength) instance_name[range] (list_of_ports);

pulldown (pulldown_strength) instance_name[range] (list_of_ports);

Description:

Gate or switch declaration begins with a keyword that determines the type of a gate or switch followed by a strength and delay declaration, name of the instance, range, and a list of connections to the gate or switch ports. The strength and the delay declarations are optional. The name of an instance and a range are also optional. Instantiations of individual gate types are not identical.

and, nand, or, nor, xor, xnor gates

The instantiation of these logic gates (Example 1) can contain zero, one, or two delays. The strength declaration should contain two specified strengths – strength1 and strength0 (see Strengths for more explanations).

These gates have one output and one or more inputs. The first port on the port list is output port.

and | 0 | 1 | x | z | or | 0 | 1 | x | z | xor | 0 | 1 | x | z
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | x | x | 0 | 0 | 1 | x | x
1 | 0 | 1 | x | x | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | x | x
x | 0 | x | x | x | x | x | 1 | x | x | x | x | x | x | x
z | 0 | x | x | x | z | x | 1 | x | x | z | x | x | x | x

nand | 0 | 1 | x | z | nor | 0 | 1 | x | z | xnor | 0 | 1 | x | z
0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | x | x | 0 | 1 | 0 | x | x
1 | 1 | 0 | x | x | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | x | x
x | 1 | x | x | x | x | x | 0 | x | x | x | x | x | x | x
z | 1 | x | x | x | z | x | 0 | x | x | z | x | x | x | x

Table 1 Truth tables for logic gates

buf and not gates

The instantiation of these logic gates (Example 2) can contain zero, one, or two delays. The strength declaration should contain two specified strengths – strength1 and strength0 (see Strengths for more explanations).

These gates have one input and one or more outputs. The last port on the port list is an input port.

buf |  | not
input | output | input | output
0 | 0 | 0 | 1
1 | 1 | 1 | 0
x | x | x | x
z | x | z | x

Table 2 Truth tables for logic gates

bufif1, bufif0, notif1, notif0 gates

The instantiation of these tri-state gates (Example 3) can contain zero, one, two, or three delays. The strength declaration should contain two specified strengths – strength1 and strength0 (see Strengths for more explanations).

These gates have three ports: the first is an output port, the second is a data port, and the third is a control port. The control port is used to set gates in high-impedance state.

bufif0 |  | control input |  |  |  | bufif1 |  | control input
 |  | 0 | 1 | x | z |  |  | 0 | 1 | x | z
data | 0 | 0 | z | L | L | data | 0 | z | 0 | L | L
input | 1 | 1 | z | H | H | input | 1 | z | 1 | H | H
 | x | x | z | x | x |  | x | z | x | x | x
 | z | x | z | x | x |  | z | z | x | x | x

notif0 |  | control input |  |  |  | notif1 |  | control input
 |  | 0 | 1 | x | z |  |  | 0 | 1 | x | z
data | 0 | 1 | z | H | H | data | 0 | z | 1 | H | H
input | 1 | 0 | z | L | L | input | 1 | z | 0 | L | L
 | x | x | z | x | x |  | x | z | x | x | x
 | z | x | z | x | x |  | z | z | x | x | x

Table 3 Truth table for tri-state logic gates

The L and H symbols have a special meaning. The L symbol means that the output has 0 or z value. The H symbol means that the output has 1 or z value. Any transition to H or L is treated as a transition to x.

nmos, pmos, rnmos, rpmos, cmos, and rcmos switches

The nmos switch is used to model N-type MOS (Metal-Oxide Semiconductor) transistor and the pmos switch is used to model P-type MOS (Metal-Oxide Semiconductor) transistor. The rnmos switch is used to model resistive nmos transistor and the rpmos switch is used to model resistive pmos transistor. The cmos switch should be treated as combination of a pmos switch and an nmos switch, which have common data input and data output. The rcmos switch should be treated as combination of an rpmos switch and an rnmos switch, which have common data input and data output.

The instantiation of these MOS switches (Example 4) can contain zero, one, two, or three delays.

The strength declaration is illegal. The nmos, pmos and cmos switches reduce supply strength of the signals to strong strength. Signals with others strengths are passed from input to output without a strength reduction. The rnmos, rpmos and rcmos switches reduce supply and strong strength of signals to pull strength. The pull strength of signals is reduced to weak. The large and weak strength of signals are reduced to medium. The medium strength of signals is reduced to small. Signals with other strengths are passed from input to output without strength reduction.

The nmos, pmos, rnmos, rpmos switches have three ports: the first is an output port, the second is a data port, and the third is a control port.

The cmos and rcmos switches have four ports: the first is an output port, the second is a data port, the third is a n-control port, and the fourth a is p-control port.

pmos |  | control input |  |  |  | nmos |  | control input
rpmos |  | 0 | 1 | x | z | rnmos |  | 0 | 1 | x | Z
data | 0 | 0 | z | L | L | data | 0 | z | 0 | L | L
input | 1 | 1 | z | H | H | input | 1 | z | 1 | H | H
 | x | x | z | x | x |  | x | z | x | x | x
 | z | z | z | z | z |  | z | z | z | z | z

cmos |  | N control
rcmos |  | 0 |  |  |  | 1 |  |  |  | x |  |  |  | z
 |  | P control
 |  | 0 | 1 | x | z | 0 | 1 | x | z | 0 | 1 | x | z | 0 | 1 | x | z
Data | 0 | 0 | z | L | L | 0 | 0 | 0 | 0 | 0 | L | L | L | 0 | L | L | L
 | 1 | 1 | z | H | H | 1 | 1 | 1 | 1 | 1 | H | H | H | 1 | H | H | H
 | x | x | z | x | x | x | x | x | x | x | x | x | x | x | x | x | x
 | z | z | z | z | z | z | z | z | z | z | z | z | z | z | z | z | z

Table 4 Truth tables for MOS switches

Symbols L and H have a special meaning. The symbol L means that the output has 0 or z value. The symbol H means that the output has 1 or z value. Any transition to H or L is treated as a transition to x.

rtranif0, rtranif1, tranif0 and tranif1 switches

The instantiation of these bi-directional pass switches (Example 5) can contain zero, one, two, or three delays.

The strength declaration is illegal. The tranif0 and tranif1 switches reduce supply strength of signals to strong. Signals with others strengths are passed from input to output without strength reduction. The rtranif0 and rtranif1 switches reduce supply and strong strength of signals to pull. The pull strength of signals is reduced to weak. The large and weak strength of signals are reduced to medium. The medium strength of signals is reduced to small. Signals with other strengths are passed from input to output without strength reduction.

The rtranif0, rtranif1, tranif0 and tranif1 switches have three ports: two bidirectional data ports and one control port (third position on port list).

tran and rtran switches

The instance of these bidirectional switches cannot contain delay and strength declaration.

The tran switches reduce supply strength of signals to strong strength. Signals with others strengths are passed from input to output without strength reduction. The rtran switches reduce supply and strong strength of signals to pull. The pull strength of signals is reduced to weak. The large and weak strength of signals are reduced to medium. The medium strength of signals is reduced to small. Signals with other strengths are passed from input to output without strength reduction.

The tran and rtran switches have two bidirectional data ports.

pullup and pulldown sources

The instantiation pullup and pulldown sources cannot contain delay declaration. The pullup can contain only strength1 specification (the strength0 declaration is optional). The pulldown can contain only strength0 specification (the strength1 declaration is optional).

The pullup source places a logic value 1 on connected signals. The pulldown source places a logic value 0 on connected signals.

Examples:

Example 1

and (strong1, weak0) (y, i1, i2, i3);

This is a three-input and gate instance with strengths specified. There is no instance name and no delays declaration.

nand #(1,2) gate1 (y, i1, i2);

This is a two-input nand gate instance with two delays specified. The instance name is gate1 and there is no strength specified.

or #1 b[1:0] (y, i1, i2, i3, i4);

This is two instances of two four-input or gates with one delay specified. Names for the instances are b[1] and b[0]. There are no strengths specified.

Example 2

buf (o1, o2, o3, o4, i);

This is the instance of buf gate, which has four outputs and one input.

Example 3

bufif0 (weak1, pull0) #(4,5,3) (data_out, data_in, ctrl);

The bufif0 gate instance with strength and delays is specified. There is no instance name, which is optional.

Example 4

pmos (data_out, data_in, ctrl);

cmos (data_out, data_in, n_ctrl, p_ctrl);

The pmos and cmos switches are instantiated with no delays, strength and instance name declarations.

Important Notes:

  1. Instantiations of gates and switches are different for individual types.


Case Statement

Formal Definition:

The case statement is a decision instruction that chooses one statement for execution. The statement chosen is one with a value that matches that of the case statement.

Complete description: Language Reference Manual section §9.5.

Simplified Syntax:

case (expression)

expression : statement

expression {, expression} : statement

default : statement

endcase

casez (expression)

expression : statement

expression {, expression} : statement

default : statement

endcase

casex (expression)

expression : statement

expression {, expression} : statement

default : statement

endcase

Description:

The case statement starts with a case or casex or casez keyword followed by the case expression (in parenthesis) and case items or default statement. It ends with the endcase keyword. The default statement is optional and should be used only once. A case item contains a list of one or more case item expressions, separated by comma, and the case item statement. The case item expression and the case item statement should be separated by a colon.

During the evaluation of the case statement, all case item expressions are evaluated and compared in the order in which they are given. If the first case item expression matches the case expression, then the statement which is associated with that expression is executed and the execution of the case statement is terminated. If comparison fails, then the next case item expression is evaluated and compared with the case expression. If all comparisons fail and the default section is given, then its statements are executed. Otherwise none of the case items will be executed.

Both case expression and case item expressions should have the same bit length. None of the expressions are required to be a constant expression.

The case expression comparison is effective when all compared bits are identical. Therefore, special types of case statement are provided, which can contain don’t-care values in the case expression and in the case item expression. These statements can be used in the same way as the case statement, but they begin with the keywords casex and casez.

The casez statement treats high-impedance (z) values as don’t-care values and the casex statement treats high-impedance and unknown (x) values as don’t care values. If any of the bits in the case expression or case item expression is a don’t-care value then that bit position will be ignored.

The don’t-care value can be also specified by the question mark (?), which is equal to z value.

Examples:

Example 1

reg [1:0] address;

case (address)

2'b00 : statement1;

2'b01, 2'b10 : statement2;

default : statement3;

endcase

If the address value is 2’b00 then statement1 will be executed. Statement2 is executed when address value equals 2’b01 or 2’b10. Otherwise statement3 is executed.

Example 2

reg a;

case (a)

1'b0 : statement1;

1'b1 : statement2;

1'bx : statement3;

1'bz : statement4;

endcase

In Example 2, the statements will be executed depending on the value of the ‘a’ variable (if a = 1’b0 then statement1 will be executed, etc). If we assign a question mark (?) to the ‘a’ variable, then statement4 will be executed because the syntax concerning numbers defines the question mark as equal to the z value.

Example 3

reg a;

casez (a)

1'b0 : statement1;

1'b1 : statement2;

1'bx : statement3;

1'bz : statement4;

endcase

If value of variable ‘a’ is 1’b0 or 1’b1 or 1’bx then statement1, statement2 or statement3 will be executed respectively. If ‘a’ equals 1’bz or 1’b? then statement1 will be executed because the casez statement treats z and ? as the don’t-care values. Statement4 will never be executed because only the first case item, which matches with the case expression, is executed.

Example 4

reg a;

casex (a)

1'b0 : statement1;

1'b1 : statement2;

1'bx : statement3;

1'bz : statement4;

endcase

If variable ‘a’ is 1’b0 or 1’b1 then statement1 and statement2 will be executed respectively. If ‘a’ equals 1’bx or 1’bz or 1’b? then statement1 will be executed (x, z and ? are don’t care values for the casex statement). Statement3 and statement4 will never be executed.

Example 5

reg a;

case (1'b1)

a : statement1;

endcase

The case expression can be a constant expression. In Example 5, statement1 will be executed only if ‘a’ is equal to 1’b1.

Important Notes:

  1. The default statement is optional and it can appear only once.

  2. The parenthesis (?) can appear in expressions and it is equal to high-impedance (z) value.

  3. If don’t care values are to be ignored, then the casex or casez statements should be used.

  4. The case statement can be a group of statements in the begin - end block.

  5. Both the case expression and case item expressions should have the same length.

  6. The case statement can appear only within structured procedures.


Continuous Assignments

Formal Definition:

Continuous assignments are the most basic assignment in dataflow modeling. Continuous assignments are used to model in combinational logic. It drives values into the nets.

Complete description: Language Reference Manual section §6.

Simplified Syntax:

net [strength] [range] [delay] identifier = net or register ;

assign [strength] [delay] net = net or register ;

Description:

Continuous assignments provide a way of modeling combinational logic at a higher level of abstraction than Gate-Level logic. It allows the use of Boolean logic rather than gate connections.

The left-hand side of an assignment is a variable to which the right-side value is to be assigned and must be a scalar or vector net or concatenation of both. The right-hand side of an assignment, separated from the left-hand side by the equal (=) character, can be a net, a reg or any expression that evaluates a value including function calls.

Continuous assignments drive values into the nets whenever the right-hand side value changes, this means continuous assignments are always active and assignments occur whenever the right-hand side operands changes. It drives both vector and scalar.

Continuous assignments can be used in two ways: as the net declaration statement and as the continuous assignment statement.

In a continuous assignment statement, after the assign keyword (Example 1) the net is declared as the left-hand side and after the equal (=) character, the right-hand side is declared as an expression. The value of out changes whenever the values of operands In_1 or In_2 change.

Example 2 shows how to use continuous assignments with vectors. The left-hand side of an assignment is a vector net, while the right-hand side operands are vector registers.

The left-hand side of an assignment can also be a concatenation of nets. Example 3 describes this use.

Instead of the continuous assignment statement, the net declaration assignment can be used. This means that in the net declaration statement we can assign expressions that occur whenever right-hand side operands change. In this case, assign keyword is not used. Example 1 can be described as shown in Example 4. In this case a net can be declared only once, therefore only one net declaration assignment can be made to a net.

An optional delay given to a continuous assignment specifies the time duration between the right-hand side operand value change and the assignment to the left-hand side. Delay specification can be used both in the continuous assignment statement and the net declaration statement (see Example 5 and Example 6).

Also optional is strength specification. Example 7 shows a way to specify strength in a continuous assignment. For more information about strength see the "Strength" chapter.

Examples:

Example 1

wire out;

assign out = In_A & In_B ;

Continuous assignment ‘out’ is a net. Both In_1 and In_2 are nets.

Example 2

assign address[7:0] = address_1[7:0] ^ address_2[7:0] ;

Continuous assignment with range specification. Address_1 and address_2 are 8-bit vector registers.

Example 3

assign {c_out, sum[7:0]} = Data_A[7:0]+Data_B[7:0]+c_in;

Continuous assignment with concatenation.

Example 4

wire out = In_A & In_B ;

The net declaration assignment. Equivalent to Example 1.

Example 5

assign #25 out = In_A & In_B ;

Delay specification in the continuous assignment statement.

Example 6

wire #25 out = In_A & In_B ;

Delay specification in the net declaration assignment.

Example 7

assign (strong1, pull0) out = Data_A | Data_B ;

Important Notes:

  • Continuous assignments cannot be used within initial or always blocks.

  • Continuous assignment statements can be used on a net that has been previously declared

  • Only one net declaration assignment can be used for a net.

  • More than one continuous assignment statement can be made to a net.


Conversion Functions

Formal Definition:

Conversion functions convert data formats between integer, real and bit representations.

Complete description: Language Reference Manual section §14.9.

Simplified Syntax:

$bitstoreal(bit_number) ;

$itor(integer_number) ;

$realtobits(real_number) ;

$rtoi(real_number) ;

Description:

The $bitstoreal function converts a bit pattern to a real number. The $itor function converts an integer to a real number. The $realtobits function converts a real number to its binary a equivalent. The $rtoi function converts a real number to an integer.

Examples:

Example 1

reg [31:0] a, result_b ;

integer b, result_I ;

real c, result_r ;

result_r = $bitstoreal(a) ;

result_r = $itor(b) ;

result_b = $realtobits(c) ;

result_I = $rtoi(c) ;

Important Notes:

  • Conversion functions are not synthesizable.


Comments

Formal Definition:

Comments provide a means of describing or documenting a model.

Complete description: Language Reference Manual section §2.3.

Simplified Syntax:

// a single line with comments

/* multiple lines

containing comments */

Description:

Comments can be used for describing models. There are two ways of using comments: in a single line or in multiple lines. It is illegal to use ‘/*’ characters without matching ‘*/’ characters. The multiple line comments cannot be nested.

Examples:

Example 1

// this is the first line of a single line comment

// this is the second line of a single line comment

Example of a single line comment.

Example 2

/* this is the first line of a multiple line comment

this is the second line of a multiple line comment

*/

Example of a multiple line comment.

Important Notes:

  1. Using the ‘/*’ characters without the matching ‘*/’ characters is not allowed

  2. The multiple line comments cannot be nested


Compiler Directives

Formal Definition:

Compiler directives are instructions affecting the compilation.

Complete description: Language Reference Manual section §16.

Simplified Syntax:

`celldefine

module_declaration

`endcelldefine

`default_nettype net_type_identifier

`define macro_name macro_text

`define macro_name(list_of_arguments) macro_text

`undef macro_name

`ifdef macro_name

group_of_lines

`else

group_of_lines

`endif

`include "filename"

`resetall

`timescale time_unit / time_precision

`unconnected_drive

module_declaration

`nounconnected_drive

Description:

All compiler directives are preceded by an accent grave (`) character. Compiler directives work from the point where they were used until the end of compilation or until a point where they are used again (even if the next usage occurs in another file).

`celldefine and `endcelldefine

These directives mark modules as cell modules (Example 1). They should be used in pairs outside the module definition.

`default_nettype

This directive sets net type used in implicit net declarations (Example 2). The default type is a wire. The `default_nettype directive should be used outside the module definition. The directive parameter can be one of following types:

wire, tri, tri0, tri1, wand, triand, wor, trior, trireg.

`define and `undef

These directives define and undefine text macros that can be used as a text substitution (Example 3). This is very useful in modeling because all changes can be applied in one place of the source code (in macro definition).

A macro can be defined with arguments, so every macro call can be followed by actual parameters.

The compiler recognizes a macro by its name preceded by accent grave (`) character.

`ifdef, `else, and `endif

These directives can be used to decide which lines of Verilog code should be included for the compilation (Example 4).

The `ifdef directive checks if a macro name that follows this directive is defined. If it is, then all lines between `ifdef and `else will be included. Otherwise, only lines between `else and `endif will be compiled.

`include

The `include directive (Example 4) inserts the contents of a specified file into a file in which it was called. The file name should be given in quotation marks (“) and it can be given using full or relative path.

`resetall

This compiler directive turns off all previously used compiler directives.

`timescale

This directive specifies time unit and time precision for simulation of modules that follow it (Example 5).

The time unit specifies the unit of measurement for times and delays.

The time precision specifies how delay values should be rounded during the simulation.

The time precision value should be equal or smaller than the time unit value.

Both time precision and time unit should be made up of an integer number and a character string that represent a unit of time. The valid numbers are: 1, 10, and 100. The valid characters are:
s, ms, us, ns, ps, and fs.

Actual time units and time precision values can be displayed by the $printtimescale system task.

`unconnected_drive and `nounconnected_drive

These compiler directives define how unconnected input ports of modules should be treated. They should be enclosed between pair of `unconnected_drive and `nounconnected_drive directives (Example 6).

The `unconnected_drive takes one parameter – pull0 or pull1. If pull0 is used then all unconnected ports will be pulled down. If pull1 is used then all unconnected ports will be pulled up.

These directives should be used outside any module definition.

Examples:

Example 1

`celldefine

module my_and(y, a, b);

output y;

input a, b;

assign y = a & b;

endmodule

`endcelldefine

Module my_and is marked as a cell module.

Example 2

`default_nettype tri

The default net type is set to tri.

Example 3

`define SIZE 8

`define xor_b(x,y) (x & !y)|(!x & y)

//These text macros can be used as follow:

reg [`SIZE – 1 : 0] data_out;

c = `xor_b(a, b);

`undef SIZE

Example 4

`ifdef behavioral

`include "groupA_beh.v ";

`include "groupB_beh.v ";

`include "ctrl_beh.v ";

`else

`include "groupA_synth.v ";

`include "groupB_ synth.v ";

`include "ctrl_ synth.v ";

`endif

If a ‘behavioral’ text macro is defined in a file then the behavioral models from the files: groupA_beh.v, groupB_beh.v, and ctrl_beh.v, will be included. Otherwise synthesizable models from groupA_synth.v, groupB_synth.v, and ctrl_synth.v, will be included.

Example 5

`timescale 10 ns / 100 ps

The time unit is set to 10 ns. During the simulation all delay values will be multiplied by 10 ns, and all delays will be rounded with 100 ps precision.

Example 6

`unconnected_drive pull1

module my_and(y, a, b);

output y;

input a, b;

assign y = a & b;

endmodule

module test;

reg b;

wire y;

my_and u1 (y, ,b);

endmodule

`nounconnected_drive

The a terminal of u1 will be pulled up (set to 1).

Important Notes:

  1. All compiler directives can be set to their default values by `resetall


Concatenations

Formal Definition:

The concatenation is the combination of two or more expressions.

Complete description: Language Reference Manual section §4.1.14.

Simplified Syntax:

{expression_1, expression_2}

{multiplier{expression}}

Description:

The concatenation is expressed by the brace characters {} bracketing two or more expressions separated by commas (Example 1). Concatenations can also be expressed using a repetition multiplier, which duplicates the expression it contains the number of times specified by the constant expression that precedes it (Example 2).

A concatenation expression can be either an identifier or a sized number. Unsized numbers are illegal because the size of all operands is required to calculate the size of an entire concatenation. A repetition multiplier should be a constant expression specified within the brace characters.

Examples:

Example 1

reg [7:0] a;

{a, 4'b1110, b[2:1]}

Result of this expression has 14-bits (‘a’ has 8 bits, 4’b1110 has 4 bits, b[2:1] has 2 bits).

Example 2

{a, {2{b, c, d}}, a}

The above concatenation is equivalent to the following concatenation:

{a, b, c, d, b, c, d, a}

Important Notes:

  1. Repetition multiplier should be a constant expression.

  2. Unsized numbers are illegal in concatenations (except as repetition multiplier).


Conditional Operator

Formal Definition:

The conditional operator selects an expression for evaluation depending on the value of condition.

Complete description: Language Reference Manual section §4.1.13.

Simplified Syntax:

condition ? expression1 : expression2;

Description:

If the condition is evaluated as false (or zero value) then expression2 is evaluated and used as a result of an entire expression. If condition is evaluated as true (or non-zero value) then expression1 is evaluated. In case condition is evaluated as x or z value, then both expresion1 and expression2 are evaluated, and the result is calculated bit by bit on the basis of the following table:

 | 0 | 1 | x | z
0 | 0 | x | x | x
1 | x | 1 | x | x
x | x | x | x | x
z | x | x | x | x

Table 5 Results of bit by bit calculation.

If one of the expressions is of real type then the result of the whole expression should be 0 (zero). If expressions have different lengths, then length of an entire expression will be extended to the length of the longer expression. Trailing 0s will be added to the shorter expression.

The conditional operator can be nested (Example 3) and its behavior is identical with the case statement behavior.

Examples:

Example 1

(a) ? 4'b110x : 4'b1000;

If ‘a’ has a non-zero value then the result of this expression is 4’b110x. If ‘a’ is 0, then the result of this expression is 4’b1000. If ‘a’ is x value then the result is 4’b1x0x (this is due to the fact that the result must be calculated bit by bit on the basis of the Table 1).

Example 2

assign data_out = (enable) ? data_reg : 8'bz;

The above example shows modeling tri-state buffers.

Example 3

reg [4:0] mux;

reg [1:0] addr;

mux = (addr == 2’b00) ? i0 :

((addr == 2’b01) ? i1 :

((addr == 2’b10) ? i2 :

((addr == 2’b11) ? i3 :

4’bz)));

case (addr)

2’b00: mux = i0;

2’b01: mux = i1;

2’b10: mux = i2;

2’b11: mux = i3;

default: mux = 4’bz;

endcase

Two different methods of modeling a multiplexer.

Important Notes:

  1. Conditional operator can be used for tri-state buffer modeling.

  2. Conditional operator can be nested (its behavior is identical with the case statement behavior).


Delays

Formal Definition:

Delays specify a time in which assigned values propagate through nets or from inputs to outputs of gates.

Complete description: Language Reference Manual section §7.15.

Simplified Syntax:

#value

#(value)

#(value, value)

#(value, value, value)

Description:

Delays specify how values propagate through nets or gates.

The net delay declaration specifies a time needed to propagate values from drivers through the net. It can be used in continuous assignments (Example 1) and net declarations (Example 2).

The gate delay declaration specifies a time needed to propagate a signal change from the input of a gate input to its output. The gate delay declaration can be used in gate instantiations (Example 3).

The delays can be also used for delay control in procedural statements (Example 4 - see Procedural timing control for more explanations).

The delays declaration can contain up to three values: rise, fall, and turn-off delays. The default delay is zero. If only one delay value is specified then it is used for all signal changes. If two delays are specified then the first delay specifies the rise delay and the second delay specifies the fall delay. If the signal changes to high-impedance (z) or to unknown (x) then the smaller value will be used. This means that if delays are specified as follows: #(4,3) then the second value (3) will be used for signal changes to z or x value.

If three values are given, then the first value specifies the rise delay, the second specifies the fall delay, and the third specifies turn-off delay. If the signal changes to unknown (x) value, then the smallest of these three values will be used.

Value changes |  | Delay used for propagation if:
From: | To: | 1 delay specified | 2 delays specified | 3 delays specified
0 | 1 | d1 | d1 | d1
0 | x | d1 | min(d1, d2) | min(d1, d2, d3)
0 | z | d1 | min(d1, d2) | d3
1 | 0 | d1 | d2 | d2
1 | x | d1 | min(d1, d2) | min(d1, d2, d3)
1 | z | d1 | min(d1, d2) | d3
x | 0 | d1 | d2 | d2
x | 1 | d1 | d1 | d1
x | z | d1 | min(d1, d2) | d3
z | 0 | d1 | d2 | d2
z | 1 | d1 | d1 | d1
z | x | D1 | min(d1, d2) | min(d1, d2, d3)

Table 6 Rules for delays depending on number of specified values

Examples:

Example 1

assign #5 out = in1 & in2;

All value changes on in1 or in2 signals will propagate to out port in 5 time units.

assign #(1,3) b = ~a;

All value changes on signal ‘a’ that cause signal ‘b’ to change its value to ‘1’, will propagate through net ‘b’ in 1 time unit. If ‘~a’ expression equals 0 then it will take 3 time units to propagate this value through net ‘b’. If the result of ‘~a’ expression is unknown (x) or high-impedance (z) value, then it will take 1 time unit (because 1 is less than 3 therefore this value will be used for propagating these value changes).

assign #(5,3,7) w_or = |bus;

If result of right-side expressions is 1 then 5 will be used as the delay.

If result of right-side expressions is 0 then 3 will be used as the delay.

If result of right-side expressions is high-impedance (z) then 7 will be used as the delay.

If result of right-side expressions is unknown (x) then 3 will be used as the delay (because this is the smallest of these three values).

Example 2

wire #(5) ready;

tri #(2,3) a;

wand #(3,2,1) signal_1;

Net ready has only one delay specified.

Net a has two delays specified.

Net signal_1 has three delays specified.

Example 3

and #1 and_gate (o, i1, i2);

or #(5,1) or_gate (o, i1, i2);

bufif1 #(3,4,5) buffer (o, i, c);

The and_gate has one delay specified.

The or_gate has two delays specified.

The buffer has three delays specified.

Example 4

reg r;

initial begin

#10 r = 1’b1;

r = #10 1’b0;

end

Important Notes:

  1. If less than 3 delays are specified then the smallest value is used for the missing delay(s).


Disable Statement

Formal Definition:

The disable statement provides means of terminating active procedures.

Complete description: Language Reference Manual section §11.

Simplified Syntax:

disable task_identifier;

disable block_identifier;

Description:

The disable statement can be used to terminate tasks (Example 1), named blocks (Example 2) and loop statements (Example 3) or for skipping statements in loop iteration statements (Example 4). Using the disable keyword followed by a task or block identifier will only disable tasks and named blocks. It cannot disable functions. If the task that is being disabled enables other tasks, all enabled tasks will be terminated.

If a task is enabled more than once, then disabling that task terminates all its instances.

Examples:

Example 1

task t;

output o;

integer o;

#100 o = 15;

endtask

disable t; // Disabling task t.

Example 2

begin : named_block

a = 1; // #1

disable named_block;

a = 2; // #2

end

Statement #2 will never be executed, therefore after execution of this block, variable ‘a’ will have 1 as its value.

Example 3

begin : break_block

i = 0;

forever begin

if (i==a)

disable break_block;

#1 i = i + 1;

end

end

The forever statement will be executed until ‘i’ is not equal to ‘a’.

Example 4

begin

i = 0;

forever begin : continue_block

if (i==a)

disable continue_block;

#1 i = i + 1;

end

end

If ‘i’ is equal to ‘a’ then statement (#1 i = i + 1) that appears after the disable statement will not be executed.

Important Notes:

  1. The disable statement cannot be used to disable functions.

  2. If a task or a named block contains other tasks or named blocks then disabling that task or a named block terminates all tasks and blocks within.

  3. The disable statement can appear only within the procedural blocks.


Display Tasks

Formal Definition:

System tasks display specific information from the simulator.

Complete description: Language Reference Manual section §14.1.

Simplified Syntax:

$display | $displayb | $displayh | $displayo (arguments) ;

$write | $writeb | $writeh | $writeo (arguments) ;

$strobe | $strobeb | $strobeh | $strobeo (arguments) ;

$monitor | $monitorb | $monitorh | $monitoro (arguments) ;

$monitoron ;

$monitoroff ;

Description:

Generally, display system tasks are grouped into three categories. The first one includes the display and write tasks such as the $display and the $write tasks. The second category is strobe monitoring, which consists of the $strobe group of tasks and the continuous monitoring tasks such as the $monitor task.

The first group of displaying tasks is very similar to print the function in the ANSI C language (the syntax is almost the same). The $write and the $display tasks work in the same way and the only difference is that the $display task adds a new line character at the end of the output, while the $write task does not.

When one of these tasks is invoked, it simply prints its arguments. The order of printed arguments is the same as the order that the x appear in the argument list. If no argument is specified, it can be declared a null argument (two adjacent commas) and when the display task is invoked, it simply prints a single space character (Example 1). An argument can be an expression that returns a value and a quoted string (see Example 2).

When an argument is given as a quoted string, there are several rules concerning format, the string argument is described in more detail in the String chapter. However there are some differences and extensions to format strings in display system tasks.

The display tasks have a special character (%) to indicate that the information about signal value is needed. When using a string, the compiler recognizes the % character and knows that the next character is a format specification. For a full description of all format specifications see the following table. If the format specification sign is used it should always be followed by a corresponding argument (exception is the %m argument).

If we need to display the % character we should use double %%.

%d or %D | Decimal format
%b or %B | Binary format
%h or %H | Hexadecimal format
%o or %O | Octal format
%c or %C | ASCII character format
%v or %V | Net signal strength
%m or %M | Hierarchical name
%s or %S | As a string
%t or %T | Current time format

Table 1 The format specification for display system tasks.

When the $display or $write system task is executed it displays the string, and all format specifications are replaced with corresponding expression values (see Example 3 and 4).

These system tasks can be invoked with "o", "h" and "b" extensions. For example $writeb, $writeo, and $displayh. When invoked, they inform the simulator that there are some arguments without corresponding format specifications and the default display format should be changed. By default, $display and $write system tasks use the decimal format to change display formats (see Example 5).

For information on how the %t format specification works see the Timescale chapter. This format specification is similar to $timeformat system task.

The size of the displayed data is very important. Generally it depends on the format specification. If you are using a hexadecimal format, the data will be displayed as four characters, each of them representing four bits of value (a single hexadecimal value can be represented as four bits). Similarly, octal values will be displayed as group of characters representing three bits. See Examples 4 and 5 for further information. The result of an expression is automatically sized, however you can change default settings by adding 0 (zero) after the % character. Example 6 shows how it is applied and displays the results. In the decimal format, values with leading zeros will be replaced by a space character. The number of spaces added corresponds to the number of truncated zeros.

Another very useful display tasks feature is rules applying to the result of an expression that has an unknown or high impedance value.

If you are using decimal format (%d) the following rules apply:

  • Single lowercase "x" character will be displayed when all bits are of an unknown value

  • Single uppercase "X" character will be displayed when some bits are of an unknown value

  • Single lowercase "z" character will be displayed when all bits are of a high impedance value

  • Single uppercase "Z" character will be displayed when some bits are of a high impedance

If you are using hexadecimal (%h) and octal (%o) formats the following rules apply:

  • Single lowercase "x" will be displayed when all bits in group are of an unknown value

  • Single uppercase "X" will be displayed when some bits in group are of an unknown value

  • Single lowercase "z" will be displayed when all bits in group are of a high impedance value

  • Single uppercase "Z" will be displayed when some bits in group are of a high impedance

NOTE: In the octal format, a group represents a group of three bits that can be represented as one digit within the range is 0 to 7. In the hexadecimal format, a group of four bits can be represented as one character within the range 0 to 9 and characters in range a to f. (See Examples 7 and 8)

The strength information may be needed when dealing with nets. For this purpose there is a special %v format specification in Verilog HDL to retrieve such information. It reports strength of a net but only in a scalar type. Three characters represent the strength, which is displayed in the console. The first two characters inform us about strength and the third character is the actual value of the net. In Verilog there are only four values: 0, 1, x, z, but the value returned by %v can also be L or H. See the table below for a full description of the strength identifier:

The first two characters:

Mnemonic | Strength name | Strength level
Su | Supply drive | 7
St | Strong drive | 6
Pu | Pull drive | 5
La | Large capacitor | 4
We | Weak drive | 3
Me | Medium capacitor | 2
Sm | Small capacitor | 1
Hi | High impedance | 0

The third character:

0 | Logic 0 value
1 | Logic 1 value
X | An unknown value
Z | A high impedance value
L | Logic 0 or high impedance value
H | Logic 1 or high impedance value

For further rules on displaying strengths, refer to the chapter regarding Strength.

The second category of display tasks is the strobe monitoring tasks. The $strobe task also has extensions such as o, b and h. They work in the same way as the $display task, however when the $display or $write task is encountered, it is executed immediately. The $strobe task is suspended until all events that occur in a particular time are processed. This means that this task returns values that are used in the next time unit. See example 10.

The last category of display tasks consists of continuous monitoring tasks. This category includes $monitor, $monitoron and $monitoroff. The difference between this group of tasks and other tasks is that these tasks provide a means of displaying a value when an event occurs. The $strobe returns value when all events in the time unit occurs, while $monitor is sensitive to an event on a variable in its argument list.

Examples:

Example 1

$display(, ,) ;

$write(, ,) ;

These tasks produce single space characters; however $display adds a new line character at the end of a line.

Example 2

reg a,b ;

$display("Simple string");

$write(a*b) ;

$display produces a Simple string text and $write evaluates a value of an expression and prints the result in the console window.

Example 3

// reg a, b ;

// a = 0 ;

// b = 1 ;

$display("The value of a is: %b", a) ;

$write ("The value of b is: %b", b) ;

The console window displays the following:

The value of a is: 0

The value of b is: 1.

Notice that the $write task prints the results below the $display tasks. ($display adds a new line character). If you change the order of these tasks to make the $write task first, then the console window will display the following:

The value of b is: 1 The value of a is: 0

This is because the $write task does not add a new line character at the end of the line.

Example 4

reg [8:0] a ; // a = 492 ;

reg [7:0] b ; // b = 205 ;

$display("The decimal value of a is: %d", a) ;

$display("The octal value of a is: %o", a) ;

$display("The binary value of a is: %b", a) ;

$display("The hexadecimal value of a is: %h", a) ;

$display("The decimal value of b is: %d", b) ;

$display("The hexadecimal value of b is: %h", b) ;

$display("The binary value of b is: %b", b) ;

$display("The octal value of b is: %o", b) ;

The results are:

The decimal value of a is: 492

The octal value of a is: 754

The binary value of a is: 111101100

The hexadecimal value of a is: 1ec

The decimal value of b is: 205

The hexadecimal value of b is: cd

The binary value of b is: 11001101

The octal value of b is: 315

In the hexadecimal format, a single character represents a group of four bits and in the octal format , a single character represents a group of three bits.

Example 5

reg [8:0] a ; // a = 492 ;

$display(a, ";") ;

$displayb(a, ";") ;

$displayo(a, ";") ;

$displayh(a, ";") ;

The results are:

492;

111101100;

754;

1ec;

Example 6

reg [31:0] a ; // a = 40 ;

$display("Decimal value a is: '%d'", a) ;

$display("Decimal value a is: '%0d'", a) ;

$display("Octal value a is: '%o'", a) ;

$display("Octal value a is: '%0o'", a) ;

The results are:

Value a is: ' 40'

Value a is: '40'

Octal value a is: '00000000050'

Octal value a is: '50'

Notice that in the first case, the value is preceded by eight space characters. The register can store a maximum value of 4294967295. To print this number, 10 characters are needed. If only 2 characters are displayed (40), the remaining eight characters are replaced by space characters. By using the %0d format specification, you cause the value to be printed without any space characters and automatically resized. Space characters only in the case of decimal format replace the leading zeros. In other cases, zeros are always displayed.

Example 7

reg [4:0] a ;

$display("Value a: %d", a) ; // a = 5'bxxxxx ;

$display("Value a: %d", a) ; // a = 5'b1x1x0 ;

$display("Value a: %d", a) ; // a = 5'bzzzzz ;

$display("Value a: %d", a) ; // a = 5'b10zz1 ;

$display("Value a: %d", a) ; // a = 5'b1x0zz ;

This example shows how the rules apply to %d format specification.

Results are:

Value a: x

Value a: X

Value a: z

Value a: Z

Value a: X

Notice that in the last case, the unknown bit and high impedance bits result in a single uppercase X. This is because an unknown value has higher priority than a high impedance value.

Example 8

reg [4:0] a ;

$display("Value a: %o", a) ; // a = 5'bxxxxx ;

$display("Value a: %o", a) ; // a = 5'b1x1x0 ;

$display("Value a: %o", a) ; // a = 5'bzzzzz ;

$display("Value a: %o", a) ; // a = 5'b10zz1 ;

$display("Value a: %o", a) ; // a = 5'b1x0zz ;

For the %o format specification the results are:

Value a: xx

Value a: XX

Value a: zz

Value a: 2Z

Value a: XZ

See the expression bit length chapter for more details on zz and xx .

Example 9

reg [4:0] a ;

$display("Value a: %h", a) ; // a = 5'bxxxxx ;

$display("Value a: %h", a) ; // a = 5'b1x1x0 ;

$display("Value a: %h", a) ; // a = 5'bzzzzz ;

$display("Value a: %h", a) ; // a = 5'b10zz1 ;

$display("Value a: %h", a) ; // a = 5'b1x0zz ;

The results are:

Value a: xx

Value a: 1X

Value a: zz

Value a: 1Z

Value a: 1X

Example 10

reg [4:0] a ;

$strobe("Value a: %h", a) ;

Important Notes:

  • To display the % character use double %%.


Edge Sensitive Path

Formal Definition:

The edge sensitive path is a module path described with an edge transition at the source.

Complete description: Language Reference Manual section §13.3.3.

Simplified Syntax:

Paralel_path:

([edge_identifier] input_terminal =>

output_terminal [polarity]:data_source) = delays;

Full_path :

([edge_identifier] input_terminal *>

output_terminal [polarity]:data_source) = delays;

Edge identifier:

posedge

negedge

Polarity:

+ -

Description:

The edge sensitive path is the same as simple module path. The difference is that in the edge sensitive path, the source edge transition is used. The edge identifier can be either a posedge or a negedge. If an input is declared as a vector port then the least significant bit is used to detect the edge transition. If no transition is specified, then the edge sensitive path works as a simple module path (i.e. at any transition that occurs on an input terminal).

The polarity operator describes if data passing from the source to the output is inverted (-) or not inverted (+).

The keywords posedge and negedge can be used both in parallel and in full paths.

Examples:

Example 1

(posedge clk => (q +: d)) = (3,1);

At a positive edge on a ‘clk’ signal the value of ‘q’ will change, using the rising delay of 3 and the falling delay of 1 time unit. The data path travels from ‘d’ to ‘q’ and data is not inverted.

Important Notes:

  • The polarity operator is used by timing analysis tools and is ignored by the simulator.


Expression Bit Length

Formal Definition:

This chapter explains values for evaluation of size of expressions.

Complete description: Language Reference Manual section §4.4.

Description:

Every expression has a result with a specified bit length. Therefore operand lengths should be checked before the expression is calculated to prevent the loss of important bits. This problem occurs when the result of an expression is assigned to a variable that cannot store all the result bits.

Expression | Bit length
Unsized constant number | Same as integer
Sized constant number | As given
i op j, op: + - / % & | ^ ^~ ~^ | Max(length of i, length of j)
i * j | Length of i + length of j
op i, op: + - ~ | Length of i
i op j, op: == != === !== && || > >= < <= | 1 bit
op i, op: & ~& | ~| ^ ~^ ^~ | 1 bit
i op j, op: >> << | Length of i
i ? j : k | Max(length of j, length of k)
{i,j} | Length of i + length of j
{i{j,k}} | i * (length of j + length of k)

Table 2 Expression bit length rules

Examples:

Example 1

reg [3:0] a;

reg [7:0] b;

reg [15:0] c;

a + b -> 8 bits

a * b -> 12 bits

a || b -> 1 bit

a >> 2 -> 4 bits

(c) ? a : b -> 8 bits

{i,j} -> 12 bits

{2(a,b}} -> 24 bits

Important Notes:

  • The expression result bit-length should be known before the assignment to prevent unintended data loss.


File I/O Functions

Formal Definition:

File I/O functions perform operations on files.

Complete description: Language Reference Manual section §14.2.

Simplified Syntax:

$fopen (file_name) ;

$fclose (file_name) ;

$fdisplay (arguments) ;

$fwrite (arguments) ;

$fstrobe (arguments) ;

$fmonitor (arguments) ;

$readmemb ("file", memory_identifier [,begin_address[,end_address]]) ;

$readmemh ("file", memory_identifier [,begin_address[,end_address]]) ;

Description:

The $fopen function opens a file and returns a multi-channel descriptor in the format of an unsized integer. This is unique for each file. All communications between the simulator and the file take place through the file descriptor. Users can specify only the name of a file as an argument, this will create a file in the default folder or a folder given in the full path description.

To close an opened file use the $fclose function. This function is called without any arguments, it simply closes all opened files. If an argument is specified it will close only a file in which the descriptor is given. By default, before the simulator terminates, all open files are closed. This means that the user does not have to close any files, and closing is done automatically by the simulator.

All file output tasks work in the same way as their corresponding display tasks. (see the Display Tasks chapter for further information) The only difference is a file descriptor that appears as the first argument in the function argument list. These functions only can append data to a file and cannot read data from files.

To read data from a file and store it in memory, use the functions: $readmemb and $readmemh. The $readmemb task reads binary data and $readmemh reads hexadecimal data. Data has to exist in a text file. White space is allowed to improve readability, as well as comments in both single line and block. The numbers have to be stored as binary or hexadecimal values. The basic form of a memory file contains numbers separated by new line characters that will be loaded into the memory.

When a function is invoked without starting and finishing addresses, it loads data into memory starting from the first cell. To load data only into a specific part of memory, start and finish addresses have to be used. The address can be explicit, given in the file with the @ (at) character and is followed by a hexadecimal address with data separated by a space. It is very important to remember the range (start and finish addresses) given in the file, the argument in function calls have to match each other, otherwise an error message will be displayed and the loading process will be terminated.

Examples:

Example 1

integer file ;

reg a, b, c;

initial begin

file = $fopen("results.dat") ;

a = b & c ;

$fdisplay(file, "Result is: %b", a) ;

$fclose(file) ;

end

Result of operation a = b & c will be put into the file result.dat.

Example 2

reg [3:0] memory [15:0] ;

initial begin

$readmemb("data.bin", memory) ;

end

Loading data in binary format from file data.bin into memory.

Example 3

reg [3:0] memory [15:0] ;

initial $readmemh("data.hex", memory, 4, 2) ;

Loading data in hexadecimal format from file data.hex into memory starting at address 2 and ending at address 4.

Important Notes:

  • If the file that is being opened in one block and accessed in another parallel block, then an error can occur if accessing takes place before the file is opened.

  • Care must be taken when accessing files in independent procedural blocks.


Functions

Formal Definition:

Functions provide a means of splitting code into small parts that are frequently used in a model.

Complete description: Language Reference Manual section §10.3.

Simplified Syntax:

function type_or_range identifier;

parameter_declaration;

input_declaration;

register_declaration;

event_declaration;

statement;

endfunction

Description:

Functions can only be declared inside a module declaration.

Function definition begins with the function keyword and ends with the endfunction keyword. The returned type or range declaration followed by a function identifier and semicolon should appear after the function keyword. Function can contain declarations of range, returned type, parameters, input arguments, registers and events (these declarations are similar to module items declaration). Net declarations are illegal. Declaration of parameters, registers, events and returned type or range are not required. A function without a range or return type declaration, returns a one-bit value. Functions should have at least one input declaration and a statement that assigns a value to the register with the same name as the function.

Any expression can be used as a function call argument. Functions cannot contain any time-controlled statements, and they cannot enable tasks. Functions can return only one value.

Examples:

Example 1

function [15:0] negation;

input [15:0] a;

negation = ~a;

endfunction

A function returning 16-bit value.

Example 2

function real multiply;

input a, b;

real a, b;

multiply = ((1.2 * a) * (b * 0.17)) * 5.1;

endfunction

A function returning real value.

Example 3

real a;

wire [15:0] b;

wire c, d, e, f;

assign b = negation ({4{c, d, e, f}}); // (#1)

initial begin

a = multiply(1.5, a); // (#2)

$display(“ b=%b ~b=%b”, b, negation(b)); // (#3)

end

Examples of function calls declared in example 1 and 2 (#1 - continuous assignment, #2 and #3 - procedural statements).

Important Notes:

  1. Functions cannot contain time-control statements.

  2. A function returns value when invoked by its name.

  3. Functions should have at least one input argument.

  4. Functions cannot have output or inout arguments.

  5. Functions can only be declared inside a module declaration.

  6. Can use ‘include to insert function code


Identifiers

Formal Definition:

The identifier is a unique name, which identifies an object.

Complete description: Language Reference Manual section §2.7.

Simplified Syntax:

identifier

\escaped_identifier

Description:

An identifier is used as an object reference. An identifier can contain a sequence of letters, digits, underscores (_) and dollar signs ($). The first character of an identifier can only be a letter or an underscore (Example 1). Identifiers are case sensitive.

Escaped identifiers (Example 2) start with backslash character (\) and end with white space (i.e. space, tab, new line). Escaped identifiers can contain any printable characters. Leading backslash character and white space at the end are not considered as part of an identifier, thus identifiers \enable and enable are identical.

Examples:

Example 1

reg enable;

wire _ready;

integer group_a;

reg and5;

tri clk$1;

Legal identifiers.

Example 2

wire \+^_^+*+*<-> ;

reg \!clk ;

White spaces between an escaped identifier and the semicolon that follows it are required, because otherwise, the semicolon will be taken as a part of an identifier.

reg \clk ;

defines \clk identifier, but

reg \clk;

defines \clk; identifier (and there will be also an error message because a variable declaration should be ended by semicolon).

Important Notes:

  1. Identifiers are case sensitive

  2. \clk and clk are the same identifiers

  3. Escaped identifiers should be followed by at least a white space character


If Statement

Formal Definition:

The if statement is used to choose which statement should be executed depending on the conditional expression.

Complete description: Language Reference Manual section §9.4.

Simplified Syntax:

if (conditional expression)

statement1;

else

statement2;

if (conditional expression)

statement1;

else if (conditional expression)

statement2;

else

statement3;

Description:

The ‘if’ statement can be used in two ways: as a single ‘if-else’ statement (Example 1) or as a multiple ‘if-else-if’ statement (nested if statement – Example 2).

In the first case when the conditional expression is evaluated to true (or non-zero), then statement1 is executed and if condition is false (or zero), then statement2 is executed.

In the second case, if the first conditional expression is evaluated to be true, then statement1 is executed. Otherwise, the second conditional expression is evaluated and depending on its values, statement2 or statement3 is executed.

Every statement can be a group of statements (enclosed in a begin-end block – Example 3) or a null statement (; - Example 4). The conditional expression can be any valid expression.

Examples:

Example 1

if (a == 5)

b = 15;

else

b = 25;

If ‘a’ is 5 then ‘b’ will be 15. Otherwise ‘b’ will be 25.

Example 2

if (a)

b = 4;

else if (d)

b = 5;

else

b = 1;

If ‘a’ has non-zero value then ‘b’ will be 4.

If ‘a’ is 0 and ‘d’ has non-zero value then ‘b’ will be 5.

If ‘a’ is 0 and ‘d’ is 0 then ‘b’ will be 1.

Example 3

if (a)

begin

counter = counter + 1;

data_out = counter;

end

else

data_out = 8'bz;

If ‘a’ has non-zero value then the counter variable will be incremented and a new counter value will be assigned to data_out variable. Otherwise, data_out bits will be assigned a high-impedance value.

Example 4

if ( counter > 10)

;

else

counter = counter + 1;

If counter value is bigger than 10, then it will stop (execute a null statement - ;). If the counter value is less than 10 then it will be incremented by 1.

Important Notes:

  1. The if statement can be nested.


Integer Constants

Formal Definition:

The integer constants are used to specify numbers.

Complete description: Language Reference Manual section §2.5.

Simplified Syntax:

sign size 'base number

Description:

Integer constants can be specified as unsized numbers (Example 1) or as sized numbers (Example 2). Sign, size and base are optional and they can be separated by white spaces. If none are used, then a number is positive and a decimal. Size should be a positive constant value (decimal number) and it specifies number of bits used for the integer. The base format should contain two characters: apostrophe (‘) and a base identifier. The base identifier and apostrophe cannot be separated by any white space. Legal base specifications are d and D for decimal numbers, h and H for hexadecimal numbers, o and O for octal numbers, b and B for binary numbers.

Decimal numbers can contain only digits and underscores (_). Binary numbers can contain only 0, 1, unknown values (x and X), high-impedance values (z and Z) and underscores. Each character in a binary number has 1 bit. Octal numbers can be specified using 0, 1, 2, 3, 4, 5, 6, 7, unknown values (x and X), high-impedance values (z and Z) and underscores. Each character in an octal number has a 3 bit equivalent. Legal characters for hexadecimal numbers are unknown values (x and X), high-impedance values (z and Z), digits (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), letters (a, A, b, B, c, C, d, D, e, E, f, F) and underscores. Each character in a hexadecimal number has a 4 bit equivalent.

Decimal numbers without the base format and size specified are treated as signed integers, but decimal numbers with base format are treated as unsigned integers (see Arithmetic expressions with registers and integers for more details).

If a specified number is bigger than a specified size constant, then the most significant bits of numbers will be truncated. If number is smaller than the size constant, then it will be padded to the left with zeros. If the most significant bit of a specified number has an unknown (x) or high-impedance (z) value, then that value will be used to pad to the left (Example 3).

Underscore character (_) is ignored and can be used to enhance readability. It cannot be the first character in number.

The question mark (?) can be used in specifying numbers with high-impedance value (z) and is very useful in case statements.

Examples:

Example 1

15

'h f

'o 17

'd 15

'b 1111

'b 1_1_1_1

All the above numbers are equal. The first number is a decimal number without the base specified, the second one is a hexadecimal number, the third is an octal number, the fourth is a decimal number with base specified, and the fifth and sixth are binary numbers.

Example 2

-5'b1_1011

10 'd 20

8'h z

6'o 71

Examples of sized integers.

Example 3

8'b0 is equal to 8'b00000000

8'b1 is equal to 8'b00000001

8'bz is equal to 8'bzzzzzzzz

8'bx is equal to 8'bxxxxxxxx

Examples of padding to the left.

Important Notes:

  1. Decimal numbers without specified size and base format are treated as signed integers.

  2. Decimal numbers with the base format specified are treated as unsigned integers.


Intra-assignment Timing Controls

Formal Definition:

The intra-assignment timing controls are procedural timing controls, which can be used inside procedural assignments.

Complete description: Language Reference Manual section §9.7.6.

Simplified Syntax:

register = delay_control expression;

register <= delay_control expression;

register = event_control expression;

register <= event_control expression;

register = repeat (expression) @(event) expression;

register <= repeat (expression) @(event) expression;

Description:

All intra-assignment timing controls should be used with procedural assignments. They can be used with blocking and non-blocking assignments. If a statement with intra-assignment timing controls is encountered during simulation, an expression will be evaluated and its value will be stored. Then, the execution of the statement will be suspended until the time specified by the delay control expires or an event specified by the event control occurs. Changes in the expression value up to the time of the event will be ignored. Next, the stored value will be assigned to the register.

Type | Assignment | Equivalent
Delay with assignment | #5 a = b; | #5; a = b;
Intra-assignment | a = #5 b; | temp = b; #5; a = temp;

Table 7 Differences beetwen delays and intra-assignment timing control

A delay with an assignment works differently. An assignment will be delayed and then the current value of expression will be assigned.

The repeat expression specifies how many occurrences of an event should appear before the assignment takes place (Example 3).

Examples:

Example 1

r_out = #10 inputA;

This is the same as:

temp = inputA;

#10;

r_out = temp;

Example 2

q = @(posedge clk) d;

This is the same as:

temp = d;

@(posedge clk);

q = temp;

Example 3

a = repeat (5) @(ready) b & c;

This is the same as:

Temp = b & c;

@(ready);

@(ready);

@(ready);

@(ready);

@(ready);

a = temp;

Important Notes:

  1. If a statement contains intra-assignment timing controls, its right hand side expression is evaluated and its value is assigned after the time specified by the delay control or after an event specified by event control.


Keywords

Formal Definition:

Keywords are reserved identifiers, which are used to define language constructs.

Complete description: Language Reference Manual section §2.7.2.

List of keywords:

always

and

assign

begin

buf

bufif0

bufif1

case

casex

casez

cmos

deassign

default

defparam

disable

edge

else

end

endcase

endfunction

endmodule

endprimitive

endspecify

endtable

endtask

event

for

force

forever

fork

function

highz0

highz1

if

initial

inout

input

integer

join

large

macromodule

medium

module

nand

negedge

nmos

nor

not

notif0

notif1

or

output

pmos

posedge

primitive

pull0

pull1

pulldown

pullup

rcmos

reg

release

repeat

rnmos

rpmos

rtran

rtranif0

rtranif1

scalared

small

specify

specparam

strong0

strong1

supply0

supply1

table

task

time

tran

tranif0

tranif1

tri

tri0

tri1

triand

trior

vectored

wait

wand

weak0

weak1

while

wire

wor

xnor

xor

Description:

  1. The keywords are reserved identifiers, which contain only lowercase letters. The user cannot redefine any of them.


Loop Statements

Formal Definition:

Loop statements provide a means of modeling blocks of procedural statements.

Complete description: Language Reference Manual section §9.6.

Simplified Syntax:

forever statement;

repeat (expression) statement;

while (expression) statement;

for (assignment; expression; assignment) statement;

Description:

There are four types of loop statements: forever, repeat, while, and for statements.

The forever instruction (Example 1) continuously repeats the statement that follows it. Therefore, it should be used with procedural timing controls (otherwise it hangs the simulation).

The repeat instruction (Example 2) executes a given statement a fixed number of times. The number of executions is set by the expression, which follows the repeat keyword. If the expression evaluates to unknown, high-impedance, or a zero value, then no statement will be executed.

The while instruction (Example 3) executes a given statement until the expression is true. If a while statement starts with a false value, then no statement will be executed.

The for instruction (Example 4) executes a given statement until the expression is true. At the initial step, the first assignment will be executed. At the second step, the expression will be evaluated. If the expression evaluates to an unknown, high-impedance, or zero value, then the for statement will be terminated. Otherwise, the statement and second assignment will be executed. After that, the second step is repeated.

Examples:

Example 1

always begin

counter = 0;

forever #10 counter = counter + 1;

end

Example 2

initial begin

repeat (10) a = a + ~b;

end

Example 3

module test

parameter MSB = 8;

reg [MSB-1:0] Vector;

integer t

initial

begin

t = 0;

while (t < MSB);

begin

//Initializes vector elelments

Vector[t] = 1'b0;

t = t + 1;

end

end

Example 4

initial begin

for (index=0; index < 10; index = index + 2)

mem[index] = index;

end

Important Notes:

  1. The forever statement should contain at least one procedural timing control.


Memories

Formal Definition:

Memories are arrays of registers.

Complete description: Language Reference Manual section §3.8.

Simplified Syntax:

reg memory_width memory_identifier memory_depth;

integer memory_identifier memory_length;

time memory_identifier memory_length;

Description:

Memories can be declared only for reg, integer and time data types. Depth of memory should be declared by specifying a range following the memory identifier (Example 1). Registers and memories can be declared in the same line (Example 2). Elements of memory type can be accessed by memory index (Example 3). An assignment to a memory identifier without specified memory index is illegal. Bit-selects and part-selects on memory elements are not allowed. If access to individual bits of memory is needed, then a word containing that bit should be assigned to a register with the same width. All operations should then be done on this register and the result should be assigned back to the memory word (Example 5). Memory words can be accessed individually, but bit-select and part-select operations cannot be done on memories or memory words directly.

Vector declaration and memory declaration are not the same. If a variable is declared as a vector, all bits can be assigned a value in one statement. If a variable is declared as memory then a value to each element should be assigned separately (Example 4).

Examples:

Example 1

reg [7:0] mem[1023:0];

integer i_mem[8:1];

The ‘mem’ variable is a memory that contains 1024 8-bit words.

The ‘i_mem’ variable has 8 words (each word is an integer register).

Example 2

reg [3:0] mem[255:0], r;

This line a declares 4-bit register ‘r’ and memory ‘mem’, which contains 256 4-bit words.

Example 3

reg [7:0] mem [3:0], r;

mem[0] = 7;

r = mem[3];

mem[1] = r;

Example 4

reg [7:0] vect;

reg array[7:0];

vect = 8'b11001010;

array[7] = 1'b1;

array[6] = 1'b1;

array[5] = 1'b0;

array[4] = 1'b0;

array[3] = 1'b1;

array[2] = 1'b0;

array[1] = 1'b1;

array[0] = 1'b0;

If the variable is declared as a vector (variable vect), then the new value can be assigned to all bits at the same time. If a variable is declared as a memory (variable array) type, then the new value should be assigned to each element of memory separately.

Example 5

reg [7:0] mem[255:0], r;

r = mem[135];

r[3:1] = 3’b100;

mem[135] = r;

This example shows how to access particular bits of memory.

Important Notes:

  1. Memories can be declared only for reg, integer and time registers types.

  2. Bit-selects and part-selects on memory elements are prohibited.


min:typ:max Delays

Formal Definition:

Delays can be specified for minimum, typical, and maximum propagation times.

Complete description: Language Reference Manual section §7.15.

Simplified Syntax:

#(min:typ:max)

#(min:typ:max, min:typ:max)

#(min:typ:max, min:typ:max, min:typ:max)

Description:

Delays can be specified with three values for each delay. These values describe minimum, typical and maximum propagation times (Example 1).

The min:typ:max values can be any constant value.

The min:typ:max values can be specified for delay control in procedural statements (Example 2).

Examples:

Example 1

assign #(1:2:3) out = in1 & in2;

assign #(1:2:3,2:3:4) b = ~a;

assign #(1:5:7,2:3:4,3:5:7) w_or = |bus;

The min:typ:max values specified for one, two and three delay values.

Example 2

initial #(1:2:3) a = 5;

Important Notes:

  1. There is no relation between min, typ, and max value.

  2. A simulation switch selects which of the three values is to be used. The default is typ.


Module Declaration

Formal Definition:

A module is comprised of the interface and the design behavior.

Complete description: Language Reference Manual section §12.1.

Simplified Syntax:

module identifier (ports_list) ;

ports_declaration ;

module_body ;

endmodule

Description:

All module declarations must begin with the module keyword and end with the endmodule keyword. After the module declaration, an identifier is required. Ports list is an option. After that, ports declaration is given with declarations of the direction of ports and the optionally type. The body of module can be any of the following:

  1. Any declaration including parameter, function, task, event or any variable declaration.

  2. Continuous assignment.

  3. Gate, UDP or module instantiation.

  4. Specify block.

  5. Initial block

  6. Always block.

If there is no instantiation inside the module, it will be treated as a top-level module

Examples:

Example 1

module module_1(a, b, c) ;

parameter size = 3 ;

input [size : 0] a, b ;

output [size : 0] c;

assign c = a & b;

endmodule

Module declaration with a parameter declaration.

Important Notes:

  • If there are two or more modules without instantiation inside the modules, then they are treated as the top-level. This means that you can have several of top-level modules.


Module Instantiation

Formal Definition:

Module instantiation provides a means of nesting modules descriptions.

Complete description: Language Reference Manual section §12.1.2.

Simplified Syntax:

module_name [parameter_value_assignment] module_instance ;

Description:

Modules can be instantiated from within other modules. When a module is instantiated, connections to the ports of the module must be specified. There are two ways to make port connections. One is connection by name, in which variables connected to each of module inputs or outputs are specified in a set of parenthesis following the name of the ports. In this method order of connections is not significant. See Example 1.

The second method is called ordered connection. In this method the order of the ports must match the order appearing in the instantiated module. See Example 2. When ports are connected by name it is illegal to leave any ports unconnected. This may occur when ports are connected by order. See Example 3.

What happens if you leave a port unconnected depends on the type of the port. If you are connecting net type ports, unconnected bits are driven with high impedance. In other cases, bits are driven with unknown values.

Module instantiations can create an array of instances. To create theses instances, range specifications have to be declared after the module name. The array of instances can save you time in writing code and provide a way to enrich your readability, see Example 4

Examples:

Example 1

module dff (clk, d, q);

input clk, d;

output q;

reg q;

always @(posedge clk) q = d;

endmodule

module top;

reg data, clock;

wire q_out, net_1;

dff inst_1 (.d(data), .q(net_1), .clk(clock));

dff inst_2 (.clk(clock), .d(net_1), .q(q_out));

endmodule

In the top module there are two instantiations of the ‘dff’ module. In both cases port connections are done by name, so the port order is insignificant. The first port is input port ‘d’, the second is output ‘q’ and the last is the clock in the ‘inst_1’. In the dff module the order of ports is different than either of the two instantiations.

Example 2

module dff (clk, d, q);

input clk, d;

output q;

reg q;

always @(posedge clk) q = d;

endmodule

module top;

reg data, clock;

wire q_out, net_1;

dff inst_1 (clock, data, net_1);

dff inst_2 (clock, net_1, q_out);

endmodule

Example 3

dff inst_1 (clock, , net_1);

Second port is unconnected and has the value Z because it is of the net type.

Example 4

module my_module (a, b, c);

input a, b;

output c;

assign c = a & b ;

endmodule

module top (a, b, c) ;

input [3:0] a, b;

output [3:0] c;

my_module inst [3:0] (a, b, c);

endmodule

Important Notes:

  • If ports are connected by name it is illegal to leave any ports unconnected.


Module Path Declaration

Formal Definition:

Module path declaration is used to describe how data can propagate through a module.

Complete description: Language Reference Manual section §13.3.

Simplified Syntax:

Simple module path ;

Edge sensitive path ;

State dependent path ;

Description:

Let’s take a look at this model:

The problem is to define delays between input and output (Y and A for example). The solution is to declare a path and specify a delay. There are three ways to do this:

  • Declare a simple module path

  • Edge a sensitive path

  • State a dependent path.

The idea is to define the delay from the source to the destination. In this method each path can have a specific delay difference. For example, the path between Y and A can be different than Y and B. Generally, if a delay is specified, we know when the response occurs on the output if the input changes.

Examples of module path declarations are also described in chapters: Edge sensitive path, and State dependent path.

Examples:

Simple module path example:

(A => Q) = 10;

(B => Q) = (12);

(C, D *> Q) = 18;

The symbols *> and => each represent a different kind of connection between the module path source and the module path destination. The operator *> establishes a full connection between source and destination. The operator => establishes a parallel connection between source and destination. Refer to the Language Reference Manual for a description of full connection and parallel connection paths.

Important Notes:

  • Module paths cannot be declared outside of a module.

  • Only the net type of a port can be used as a source. Input and inout directions are allowed.

  • Both registers and net types can be used as path destinations. Input and inout directions are allowed.

  • A destination cannot have more than one driver.


Module Path Polarity

Formal Definition:

Module path polarity describes when a signal is inverted or not driving propagation between the source and the destination .

Complete description: Language Reference Manual section §13.3.7.

Simplified Syntax:

+=> positive simple module path polarity

-=> negative simple module path polarity

+*> positive multiple module path polarity

-*> negative multiple module path polarity

Description:

The polarity of the module is a description of what happens when a signal is propagated from the source to the destination. There are three possible polarities of the module.

  • Unknown polarity

  • Positive polarity

  • Negative polarity

Positive polarity is specified by the + prefix. When positive polarity is specified, simple rules apply: a rise at the source causes a rise transition at the destination and a fall transition at the source causes the fall transition at the destination. (Example 1)

Negative polarity is specified by the - prefix. When negative polarity is specified, the rules applied are similar to those from positive polarity. However, a rise transition at the source causes fall transition at the destination, and a fall transition at the source causes a rise transition at the destination. (Example 2)

When no prefix is specified with => or *> operators, it means that unknown polarity is to be used by default. In this case a rise transition at the source may cause a rise, a fall, or no transition at the destination. The same rule applies for the fall transition. (Example 3)

Examples:

Example 1

(DataIn +=> DataOut) = DataIn_to_DataOut ;

(DataIn +*> DataOut) = DataIn_to_DataOut ;

Positive polarity.

Example 2

(DataIn -=> DataOut) = DataIn_to_DataOut ;

(DataIn -*> DataOut) = DataIn_to_DataOut ;

Negative polarity.

Example 3

(DataIn => DataOut) = DataIn_to_DataOut ;

(DataIn *> DataOut) = DataIn_to_DataOut ;

Default unknown polarity.

Important Notes:

  • By default, unknown polarity is specified.

  • Module path polarity is used by a timing analysis tool and is ignored by the simulator.


Net Data Types

Formal Definition:

Nets are data types that can be used to model physical connections.

Complete description: Language Reference Manual section §3.2.

Simplified Syntax:

Net declaration:

wire range delays list_of_identifiers;

wand range delays list_of_identifiers;

wor range delays list_of_identifiers;

tri range delays list_of_identifiers;

triand range delays list_of_identifiers;

trior range delays list_of_identifiers;

tri0 range delays list_of_identifiers;

tri1 range delays list_of_identifiers;

supply0 range delays list_of_identifiers;

supply1 range delays list_of_identifiers;

trireg strength range delays list_of_identifiers;

Net declaration assignment:

wire strength range delays list_of_identifiers = expression;

wand strength range delays list_of_identifiers = expression;

wor strength range delays list_of_identifiers = expression;

tri strength range delays list_of_identifiers = expression;

triand strength range delays list_of_identifiers = expression;

trior strength range delays list_of_identifiers = expression;

tri0 strength range delays list_of_identifiers = expression;

tri1 strength range delays list_of_identifiers = expression;

supply0 strength range delays list_of_identifiers = expression;

supply1 strength range delays list_of_identifiers = expression;

trireg strength range delays list_of_identifiers = expression;

Description:

Net data types are used to model physical connections. They do not store values (there is only one exception – trireg, which stores a previously assigned value). The net data types have the value of their drivers. If a net variable has no driver, then it has a high-impedance value (z).

Nets can be declared in a net declaration statement (Example 1) or in a net declaration assignment (Example 2).

Net declarations can contain strength declarations, which specifies the strength of the logic values driven by the net (see Strengths for more details). The range declaration is used to specify multi-bit nets (vectors). The delays are used to specify propagation delays through the nets. The strength, delay and range declarations are optional.

Wire and tri nets.

Both wire net and tri net are identical. Two different names are used for more readability. Preferably wire nets may be used if a net has only one driver. If a net has more than one driver, then tri net may be used instead.

 | 0 | 1 | x | z
0 | 0 | x | x | 0
1 | x | 1 | x | 1
x | x | x | x | x
z | 0 | 1 | x | z

Table 8: Truth table for wire and tri nets

This table applies only to wire and tri nets driven by multiple drivers that have no strength declaration or their strengths are equal.

Wand and triand nets.

These net types are wired and nets. It means that if one of their drivers is 0 then the result value will also be 0.

 | 0 | 1 | x | z
0 | 0 | 0 | 0 | 0
1 | 0 | 1 | x | 1
x | 0 | x | x | x
z | 0 | 1 | x | z

Table 9: Truth table for wand and triand nets

This table applies only to wand and triand nets driven by multiple drivers that have no strength declaration, or their strengths are equal.

Wor and trior nets.

These net types are wired or nets. It means that if one of their drivers has a value of 1, then the result value will also be 1.

 | 0 | 1 | x | z
0 | 0 | 1 | x | 0
1 | 1 | 1 | 1 | 1
x | x | 1 | x | x
z | 0 | 1 | x | z

Table 10: Truth table for wor and trior nets

This table applies only to wor and trior nets driven by multiple drivers that have no strength declaration, or their strengths are equal.

Tri0 and tri1 nets.

These nets are used to model resistive pulldown and pullup devices. If a tri0 net has no driver its value is 0. If a tri1 net has no driver, then its value is 1. These values have pull strength.

 | 0 | 1 | x | z
0 | 0 | x | x | 0
1 | x | 1 | x | 1
x | x | x | x | x
z | 0 | 1 | x | 0

Table 11: Truth table for tri0 net

 | 0 | 1 | x | z
0 | 0 | x | x | 0
1 | x | 1 | x | 1
x | x | x | x | x
z | 0 | 1 | x | 1

Table 12: Truth table for tri1 nets

Supply0 and supply1 nets.

These nets are used to model power supplies in the circuit. They should have supply strength.

Trireg nets.

The trireg nets are used to model net capacity. If the trireg net driver has 0, 1, or x value, then it becomes a trireg net value and its strength can be one of the drive strengths, depending on the driver strength. If the driver has a z value, then the trireg net keeps the previously driven value and the strength can be one of the charge strengths, depending on the strength specified during net declaration.

Examples:

Example 1

wire [7:0] a;

tri tristate_buffer;

wand #5 sig_1;

trireg (small) t;

The ‘a’ variable is a 8-bit wire net.

The ‘tristate_buffer’ is 1-bit tri net type variable.

The ‘sig_1’ variable is 1-bit wand net type variable, which propagates driven value to its output in 5 time units.

The ‘t’ variable is trireg net variable with small charge strength.

Example 2

reg a;

wire [3:0] b;

wor (strong1, weak0) wired_or = a;

trior (pull1, weak0) [3:0] #(5:3:4) vect = b;

The ‘wired_or’ variable is a 1-bit wor net type variable that has specified strengths (strong1 when its value is 1 and weak0 when its value is 0).

The ‘vect’ variable is a 4-bit trior net type variable that has pull and weak strengths and 3 delay parameters.

Important Notes:

  1. Nets cannot be used as left-hand value of procedural assignments.

  2. If the trireg net is not driven, then it has charge strength. Otherwise it has the strength of its driver.


Operators

Formal Definition:

Operators provide a means to construct expressions.

Complete description: Language Reference Manual section §4.1.

Simplified Syntax:

Arithmetic: + - * /

Modulus: %

Relational: < <= > >=

Logical: ! && ||

Logical equality: == !=

Case equality: === !==

Bit-wise: ~ & | ^ ~^ ^~

Reduction: & ~& | ~| ^ ~^ ^~

Shift: << >>

Conditional: ?:

Event or: or

Concatenations: {} {{}}

Description:

Verilog HDL operators can be divided into several groups.

Operator | Description
+ - ! ~ | Unary
* / % | Arithmetic
+ - (binary) | Binary
<< >> | Shift
< <= > => | Relational
== != === !== | Equality
& ~& | and nand
^ ~^ ^~ | xor xnor
| ~| | or nor
&& | Logical and
|| | Logical or
?: | Conditional operator

Table 13: Operator's priority

Arithmetic operators

The arithmetic operators can be used with all data types.

Operator | Description
a + b | a plus b
a - b | a minus b
a * b | a multiply by b
a / b | a divide by b
a % b | a modulo b

Table 14: Arithmetic operators

The modulus operator is not allowed for real data type variables. For the modulus operator, the result takes the sign of the first operand. Examples of using these operators are shown in Example 1.

Relational operators

The relational operators are used to compare expressions. The value returned by the relational operators is 0 if the expression evaluates to false and 1 if expression evaluates to true.

Operator | Description
a < b | a less than b
a > b | a greater than b
a <= b | a less than or equal to b
a => b | a greater than or equal to b

Table 15: Relational operators

Examples of using the relational operators are shown in Example 2.

Equality operators

The equality operators are used to compare expressions. If a comparison fails, then the result will be 0, otherwise it will be 1.

If both operands of logical equality (==) or logical inequality (!=) contain unknown (x) or a high-impedance (z) value, then the result of comparison will be unknown (x). Otherwise it will be true or false.

If operands of case equality (===) or case inequality (!==) contain unknown (x) or a high-impedance (z) value, then the result will be calculated bit by bit.

Examples of using the equality operators are shown in Example 3.

Logical operators

The logical operators are used to connect expressions.

Operator | Description
a && b | a and b
a || b | a or b
!a | not a

Table 16: Logical operators

The result for these operators is 0 (when false), 1 (when true), and unknown (x - when ambiguous). The negation operator (!) turns a nonzero or true value of the operand into 0, zero or false value into 1, and ambiguous value of operator results in x (unknown value).

Examples of using the logical operators are shown in Example 4.

Bit-wise operators

The bit-wise operators calculate each bit of results by evaluating the logical expression on a pair of corresponding operand bits.

& | 0 | 1 | x | z
0 | 0 | 0 | 0 | 0
1 | 0 | 1 | x | x
x | 0 | x | x | x
z | 0 | x | x | x

Table 17: Bit-wise and operator

| | 0 | 1 | x | z
0 | 0 | 1 | x | x
1 | 1 | 1 | 1 | 1
x | x | 1 | x | x
z | x | 1 | x | x

Table 18: Bit-wise or operator

^ | 0 | 1 | x | z
0 | 0 | 1 | x | x
1 | 1 | 0 | x | x
x | x | x | x | x
z | x | x | x | x

Table 19: Bit-wise exclusive or operator

~^ ^~ | 0 | 1 | x | z
0 | 1 | 0 | x | x
1 | 0 | 1 | x | x
x | x | x | x | x
z | x | x | x | x

Table 20: Bit-wise exclusive nor operator

~ | Result
0 | 1
1 | 0
x | X
z | X

Table 21: Bit-wise negation operator

Examples of using the bit-wise operators are shown in Example 5.

Reduction operators

The reduction operator produces a 1-bit result. This result is calculated by recursively applying bit-wise operation on all bits of the operand. At each step of this recursive calculation the logical bit-wise operation is performed on the result of a previous operation and on the next bit of the operand. The operation is repeated for all bits of the operand.

Examples of using the reduction operators are in shown Example 6.

Shift operators

The shift operators perform left and right shifts on their left operand by the number of positions specified by their right operand. All vacated bits are filled with zeroes. If the expression that specifies the number of bits to shift (right operand) has unknown (x) or high-impedance (z) value, then result will be unknown.

Examples of using the shift operators are in shown Example 7.

Conditional operator

The conditional operator is described in the Conditional operator section.

Concatenations

Concatenations are described in the Concatenations section.

Event or operator

The event or operator is described in the section on Procedural timing controls.

Examples:

Example 1

reg [3:0] a, b;

a = 4;

b = 3;

a + b = 7

a – b = 1

a * b = 12

a / b = 1

a % b = 1

5 % 2 = 1

5 % -2 = 1

-5 % 2 = -1

-5 % -2 = -1

Example 2

reg [3:0] a, b;

a = 4’b1100;

b = 4’b0110;

a < b // false - 0

a > 8 // true - 1

a <= b // false - 0

a >= 10 // true - 1

a < 4’b1zzz // unknown - x

a < 4’b1x01 // unknown - x

Example 3

reg [3:0] a, b;

a = 4’b1100;

b = 4’b101x;

a == 4’b1100 // true - 1

a != 4’b1100 // false - 0

a == 4’b1z10 // false - 0

a != 4’b100x // true – 1

b == 4’b101x // unknown - x

b != 4’b101x // unknown - x

b === 4’b101x // true - 1

b !== 4’b101x // false - 0

Example 4

reg [3:0] a, b;

a = 4’b1100;

b = 4’b0000;

!a // 0 - false

!b // 1 - true

a && b // 0 - false

a || b // 1 – true

Example 5

reg [7:0] a, b;

a = 8’b1010xzxz;

b = 8’b10010011;

a & b = 8’b100000xx;

a | b = 8’b1011xx11;

a ^ b = 8’b0011xxxx;

a ~^ b = 8’b1100xxxx;

~ a = 8’b0101xxxx;

Example 6

value | & | ~& | | | ~| | ^ | ~^ | ^~
4’b0000 | 0 | 1 | 0 | 1 | 0 | 1 | 1
4’b0001 | 0 | 1 | 1 | 0 | 1 | 0 | 0
4’b0011 | 0 | 1 | 1 | 0 | 0 | 1 | 1
4’b0111 | 0 | 1 | 1 | 0 | 1 | 0 | 0
4’b1111 | 1 | 0 | 1 | 0 | 0 | 1 | 1
4’b01xx | 0 | 1 | 1 | 0 | x | x | x
4’b01z0 | 0 | 1 | 1 | 0 | x | x | x

Table 22: Reduction operators

Example 7

reg [3:0] a;

a = 4’b1111;

a << 3 = 4’b1000

a >> 3 = 4’b0001

a << 1’bz = 4’bxxxx

a >> 1’bx = 4’bxxxx

Important Notes:

  1. Some of the operators cannot be used with reals.


Parameters

Formal Definition:

Parameters are constants typically used to specify the width of variables and time delays.

Complete description: Language Reference Manual section §3.10, §12.2.

Simplified Syntax:

parameter identifier = constant_expression ,

identifier = constant_expression ;

defparam hierarchical_path = constant_expression ;

Description:

In Verilog HDL, parameters are constants and do not belong to any other data type such as net or register data types.

A constant expression refers to a constant number or a previously defined parameter (see Example 1). You are not allowed to modify parameter values at runtime, but you can modify a parameter value using the defparam statement. The defparam statement can modify parameters only at the time of compilation. Parameter values can also be modified using #delay specification with module instantiation.

In Verilog there are two ways to override a module parameter value during a module instantiation. The first method is by using the defparam keyword and the second method is called module instance parameter value assignment.

After the defparam keyword, the hierarchical path to the parameter is specified along with the new value of the parameter. In this case, the new value should be a constant expression (see Example 2). If the right-hand side expression references any parameters it should be declared within the module where defparam is invoked (see Example 3).

The module instance parameter value assignment method looks like an assignment of delay to gate instance (see Example 4). This method overrides parameters inside instantiated modules, in the order, that they appear in the module. Using this format, parameters cannot be skipped.

Constant expressions can contain previously declared parameters. When changes are detected on the previously declared parameters, all parameters that depend on this value are automatically updated (see Example 5).

Examples:

Example 1

parameter lsb = 7 ;

parameter size = 8 ,

word = 32 ;

parameter number = 3.92,

frequency = 100 ;

parameter clk_cycle = frequency / 2 ;

Example 2

module my_module (Clk, D, Q) ;

parameter width = 2,

delay = 10 ;

input [width - 1 : 0] D ;

input Clk ;

output [width : 0] Q ;

assign #delay Q = D;

endmodule

Example 3

module top;

reg Clk ;

reg [7:0] D ;

wire [7:0] Q ;

my_module inst_1(Clk, D, Q) ;

endmodule

module override ;

defparam top.inst_1.width = 7 ;

endmodule

Example 4

module top;

reg Clk ;

reg [7:0] D ;

wire [7:0] Q ;

my_module #(7, 25) inst_1(Clk, D, Q) ;

endmodule

Example 5

parameter foo = 4;

parameter data = foo / 10 ;

When ‘foo’ changes, ‘data’ is automatically updated.

Important Notes:

  • Parameters are constants.

  • If you are using the defparam statement, remember that you have to specify a hierarchical path to your parameter.

  • You cannot skip over a parameter in a module instance parameter value assignment. If you need do this, use the initial value for parameter that is not to be overwritten.

  • When one parameter depends on the other, remember that if you change the first one, the second will automatically be updated.


Part-select

Formal Definition:

Part-select gives an access to contiguous bits of vectors.

Complete description: Language Reference Manual section §4.2.1.

Simplified Syntax:

vector_identifier[msb:lsb];

Description:

Part-select returns a part of a vector. The range is specified by two, separated by colon, constant expressions: the most significant bit (msb) in an expression and the least significant bit (lsb) in an expression. Both the msb expression and the lsb expression should be constant expressions.

The part-select operation can be applied to any net vector type, as well as reg, integers and time registers. The part-select of a register declared as real or realtime is illegal.

Part-select of a vector should be done in the same direction as the range of the declared vector.

Examples:

Example 1

reg [3:0] vect;

vect = 4'b0001;

If the address expression is [3:1] then returned value is 000 (vect[3:1] = 3’b000).

If the address expression is [1:0] then returned value is 01 (vect[1:0] = 2’b01).

Important Notes:

  1. Part-select on memories, real registers, or realtime registers is illegal.


PLA Modeling Tasks

Formal Definition:

The PLA system tasks are used to model PLA devices.

Complete description: Language Reference Manual section §14.6.

Simplified Syntax:

$array_type$logic$format (memory_name, input_terms, output_terms) ;

array_type ::= sync | async

logic ::= and | or | nand | nor

format ::= array | plane

memory_name ::= identifier

input_terms ::= {scalar_variable}

output_terms ::= {scalar_variable}

Description:

These system tasks are used to model content addressed memories i.e., memories that are read at locations that an input address matches a stored address. The PLA devices can be synchronous or asynchronous (type is defined by array_type: sync and async).

All patterns should be loaded into memory using the $readmemb and $readmemh system tasks or assigned by procedural assignments.

Both the input_terms and the output_terms should be concatenations of scalar variables, but all variables from the output_terms should be declared as a reg data type. The input_terms should have the length equal to the memory word size. The output_terms should have the length equal to the number of memory words (Example 1).

The input data is taken from the input_terms and then compared with all patterns from memory. If any pattern from the memory matches the input data then the corresponding bit of the output_terms becomes ‘1’.

The format specifies the logic type of an array. If an array is used, then only the bits with ‘1’ value from the pattern are compared with the input data. If plane is used, then both ‘0’ and ‘1’ values are significant. The don’t care values can also be specified by ‘z’ and ‘?’ characters. (Example 3).

The logic identifier specifies how the input data should be compared with patterns (it also depends on the logic type of an array). If there is an and identifier then all bits with ‘1’ value (array type) or all bits with ‘0’ and ‘1’ value (plane type) from the pattern should match the corresponding bits from the input data (Example 2). If a or identifier is used then at least one bit with ‘1’ value (array type) or at least one bit with ‘0’ or ‘1’ value (plane type) from the pattern should match the corresponding bit from the input data.

The contents of a memory can be changed during the simulation.

Examples:

Example 1

module pla(a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2);

input a0, a1, a2, a3, a4, a5, a6, a7;

output b0, b1, b2;

reg b0, b1, b2;

reg [7:0] mem[0:2];

initial begin

mem[0] = 8'b11001100;

mem[1] = 8'b00110011;

mem[2] = 8'b00001111;

$async$and$array(mem, {a0,a1,a2,a3,a4,a5,a6,a7}, {b0,b1,b2});

end

endmodule

The PLA device has an 8-bit input ([7:0]) bus and a 3-bit output ([0:2]) bus declared as reg (b0, b1, b2). This PLA device is an asynchronous array declared with logic and.

The simulation results for the PLA device from Example 1 are as follows:

A = {a0, a1, a2, a3, a4, a5, a6, a7}

B = {b0, b1, b2}

mem[0] = 8'b11001100;

mem[1] = 8'b00110011;

mem[2] = 8'b00001111;

A = 11001100 -> B = 100

A = 00110011 -> B = 010

A = 00001111 -> B = 001

A = 10101010 -> B = 000

A = 01010101 -> B = 000

A = 11000000 -> B = 000

A = 00111111 -> B = 011

All ‘1’s from the pattern should match the ‘1’s from the input data (the input data can also have other ‘1’s)

The simulation results for the PLA device from Example 1 declared with $async$and$plane are as follows:

A = {a0, a1, a2, a3, a4, a5, a6, a7}

B = {b0, b1, b2}

mem[0] = 8'b11001100;

mem[1] = 8'b00110011;

mem[2] = 8'b00001111;

A = 11001100 -> B = 100

A = 00110011 -> B = 010

A = 00001111 -> B = 001

A = 10101010 -> B = 000

A = 01010101 -> B = 000

A = 11000000 -> B = 000

A = 00111111 -> B = 000

All ‘0’s and ‘1’s from the pattern should match the ‘0’s and ‘1’s from the input data.

If a PLA is declared with $async$and$plane then the pattern can be specified as 8’b0011????.

8’b0011???? -> ~a[0] & ~a[1] & a[2] & a[3]

The value of a[4], a[5], a[6], and a[7] bits are not important (the don’t care values specified by ‘?’ character).

Important Notes:

  • If more than one pattern matches the input data then more than one output bit will go to ‘1’.


Probabilistic Distribution Functions

Formal Definition:

Probabilistic Distribution Functions provide the functionality of random number generators.

Complete description: Language Reference Manual section §14.10.

Simplified Syntax:

$dist_uniform (seed, start, end) ;

$dist_normal (seed, mean, standard_deviation) ;

$dist_exponential (seed, mean) ;

$dist_poisson (seed, mean) ;

$dist_chi_square (seed, degree_of_freedom) ;

$dist_t (seed, degree_of_freedom) ;

$dist_erlang (seed, k_stage, mean) ;

Description:

Probabilistic distribution functions present a way to test your design using a randomly generated data. Testbenches often do not reveal irregularities in working models because designers tend to write testbenches in a schematic fashion. Usually, test vectors applied to the inputs of a module do not cover all possible states. When used, these functions may find a specific input combination for which the model does not work correctly. To enable repetitive design debugging, the probabilistic distribution functions must return recurrent data. This means that each time they are called they should return the same values in the last call order.

Probabilistic distribution functions use several arguments for generating data. A first function argument is a seed. Each time a function is called, the seed argument determines an order of values that are returned from the function. This argument must be a register type value of an inout direction. Users can initialize this value and let the system override it. This will make these functions repetitive.

The $dist_uniform function returns an integer value that is a random generated number in a range depending on the start and end arguments. Returned values are uniformly distributed. Both start and end arguments can be any integer, positive or negative, however the start value should be smaller than the end value.

The $dist_normal function returns a number that is an average approach to the mean argument. The mean argument is also used in $dist_expotential, $dist_poisson and $dist_erlang. The standard_deviation argument is used to determine the shape of density. In $dist_chi_square and $dist_t the shape of density depends on the degree_of_freedom.

Examples:

Example 1

reg [15:0] a ;

initial begin

a = $dist_exponential(60, 24);

end

Example 2

reg [15:0] a ;

initial begin

a = $dist_erlang(60, 24, 7) ;

end

Important Notes:

  • To enable repetitive design debugging, the probabilistic distribution functions return recurrent data.


Procedural Assignments

Formal Definition:

The procedural assignments enable updating registers.

Complete description: Language Reference Manual section §9.2.

Simplified Syntax:

register_identifier = expression;

register_identifier <= expression;

Description:

The procedural assignments can be used only within the structured procedures (always, initial, task, function).

The left-hand side of assignment should be one of the following:

  • Register.

  • Bit-select of register.

  • Part-select of reg, integer, or time data type.

  • Memory word.

  • Concatenation of any of the above.

The Verilog HDL contains two types of procedural assignments statements: blocking (Example 1) and non-blocking (Example 2) procedural assignments.

If a current statement contains a blocking procedural assignment then the next statement will be executed after the execution of the current statement (in the next step of the simulation).

If a current statement contains a non-blocking procedural assignment then the next statement will be executed at the same time (in the same step of the simulation).

A block of statements with non-blocking procedural assignments has similar functionality as a group of statements within a fork-join block (Example 3).

Examples:

Example 1

begin

a = 1;

#10 a = 0;

#5 a = 4;

end

During the simulation, this block will be executed in 15 time units. At time 0 the ‘a’ variable will be 1, at time 10 the ‘a’ variable will be 0, and at time 15 (#10 + #5) the ‘a’ variable will be 4.

Example 2

begin

a <= 1;

#10 a <= 0;

#5 a <= 4;

end

During the simulation this block will be executed in 10 time units. At time 0 the ‘a’ variable will be 1, at time 5 the ‘a’ variable will be 4, and at time 10 the ‘a’ variable will be 0.

Example 3

fork

a = 1;

#10 a = 0;

#5 a = 4;

join

This fork-join block has the same functionality as the block with non-blocking assignments from example 2.

Important Notes:

  1. Statements that contain the non-blocking procedural assignments are executed in the same simulation cycle.


Procedural Continuous Assignments

Formal Definition:

Procedural continuous assignments provide a means to continuously drive a value into a register or a net.

Complete description: Language Reference Manual section §9.3.

Simplified Syntax:

assign register_assignment ;

deassign register_left_value ;

force register_assignment | net_assignment ;

release register_left_value | net_left_value ;

register_left_value - left hand-side operand ;

net_left_value - left hand-side operand ;

Description:

In the assign statement, the left hand-side operand can be a register or a concatenation of registers in contrast to continuous assignments where the left hand-side operands are nets. However, the memory word, bit-select or part-select cannot be used on the left hand-side. The priority of procedural continuous assignment is higher than that of the procedural assignments. The deassign keyword informs the end of the driving of the corresponding register. After a deassign, register values remain the same until driven by another procedural or procedural continuous assignment. If the assign keyword is used a second time for the same register, the first register will be deassigned and a new procedural continuous assignment statement takes place.

The keywords force and release have the same effect as assign and deassign; however the left hand-side operand should be a net or a bit-select or a part-select of vector net or concatenation of both. It cannot be part-select or bit-select of a vector register or a memory word.

An assign declared as a force overrides all procedural assignments to the register until the release statement is executed. In the same way, if a net is driven by a procedural continuous assignment all previous assignments are overridden until the release statement is executed. In the register case, the value will be maintained to the next procedural continuous assignment.

Examples:

Example 1

module example1(clk, d, reset, set, q) ;

input clk, d, reset, set;

output q;

reg q;

always @(posedge clk) q = d;

always @(reset or set) begin

if (reset) assign q = 1'b0;

else if (set) assign q= 1'b1;

else deassign q;

end

endmodule

Important Notes:

  • The left-hand operand of the force and release statements can be a net data type variable.

  • Assign and deassign can only be applied to reg type variables.


Procedural Timing Control

Formal Definition:

The procedural timing control is used to determine when statements should be executed.

Complete description: Language Reference Manual section §9.7.

Simplified Syntax:

Delay control:

#delay

#(min:typ:max delay)

Event type declaration:

event identifier;

Event trigger:

-> event_identifier;

Event control:

@(event_identifier)

@(posedge identifier)

@(negedge identifier)

@(event_expression or event_expression)

Wait statement:

wait (expression) statement

Description:

The Verilog HDL has two types of timing controls: delay control (Example 1) and event control (Example 2).

The delay control specifies the time between encountering and executing the statement. The delay control can be specified as a simple delay and as min:typ:max delay.

The named event (Example 3) is a special data type that does not hold any value. The event can be triggered using special characters -> followed by an event identifier. Any occurrence of an event trigger can be noticed using an event control statement.

An event control specifies the event that is required to resume execution of a statement. Event can be one of the following:

  1. Named event

  2. Change of a signal value

  3. Positive or negative edge occurred on signal (posedge, negedge)

  4. List of above-mentioned events (separated by or – event or operator)

A posedge is any transition from 0, x, and z to 1, and from 0 to z or x.

A negedge is any transition from 1, x, and z to 0, and from 1 to z or x.

The wait statement (Example 4) will suspend execution of all statements until the expression becomes true.

Examples:

Example 1

#10;

The next statement will be executed after 10 time units.

#10 a = 5;

Assignment to a variable will be delayed by 10 time units.

#(1:2:3);

Delay control with min:typ:max delay value.

#(5:3:7) a = 5;

Assignment to a variable delayed by min:typ:max delay value.

Example 2

@ready a = a + 1;

The ‘a’ variable will be incremented by 1 when a change occurs on the ‘ready’ variable.

@(posedge clk) q = d;

The ‘d’ variable will be assigned to ‘q’ on the positive edge of clk.

@(a or b or c or d)

y = (a | b) & (~c ^ d);

A new value will be assigned to the ‘y’ variable when a change occurs on any of the variables a, b, c, or d.

Example 3

event e;

Event declaration.

initial begin

#10;

-> e;

end

Example of event triggering.

always @e d = 0;

Example of waiting for an event.

Example 4

wait (a);

i = i + 1;

wait (!a);

This sequence of statements will wait until ‘a’ becomes 1, and then the next statement will be executed. Next, execution will be suspended until ‘a’ becomes 0.

Important Notes:

  1. The delay controls are useful in specifying patterns for testbenches.


Range Specification

Formal Definition:

The range specification can be used to specify an array of gate or module instances.

Complete description: Language Reference Manual section §7.1.

Simplified Syntax:

instance_name[l_index:r_index] (list of terminals);

Description:

The range should be specified using two constant expressions separated by a colon and bracketed by square brackets. The expressions constitutes: the left-hand index (l_index) and right-hand index (r_index). The left-hand index can be less than, equal, or greater than the right-hand index (Example 1). If these indexes are equal then only one instance will be generated (Example 2). Identical instance names cannot appear twice with other range specifications (even if ranges do not overlap each other).

Examples:

Example 1

reg [3:0] a, b;

wire [3:0] y;

and g[3:0](y,a,b);

This declaration is equivalent to:

and g3 (y[3], a[3], b[3]);

and g2 (y[2], a[2], b[2]);

and g1 (y[1], a[1], b[1]);

and g0 (y[0], a[0], b[0]);

Example 2

reg a, b;

wire y;

or g[0:0](y,a,b);

This declaration is equivalent to:

or g (y, a, b);

Important Notes:

  1. If the range is used in module or gate instantiations, then terminals of all output ports should not be scalars or there may be a bus conflict.


Real Constants

Formal Definition:

The real constants are used to specify floating-point numbers.

Complete description: Language Reference Manual section §2.5.

Simplified Syntax:

sign unsigned_number.unsigned_number

sign unsigned_number.unsigned_number e sign unsigned_number

sign unsigned_number.unsigned_number E sign unsigned_number

Description:

A real constant can be specified using only digits, underscores, decimal points and exponential symbols (e or E). It cannot be specified with size or base format. If a decimal point is provided then the real number should have at least one digit on both sides of a decimal point. Real numbers can be specified in the decimal notation (Example 1) or in the scientific notation (Example 2).

Examples:

Example 1

17.5

0.5

1_000_000.0

Example 2

10e5

0.5694_e-5

Important Notes:

  1. The real constants cannot be specified with size or base format.


Register Data Types

Formal Definition:

Registers provide means for modeling data storage elements.

Complete description: Language Reference Manual section §3.2.

Simplified Syntax:

reg range list_of_identifiers;

integer list_of_identifiers;

real list_of_identifiers;

time list_of_identifiers;

realtime list_of_identifiers;

Description:

Registers are data types that store assigned values until a new assignment occurs. A new value can be assigned to registers only by using procedural assignments.

The reg register is a 1-bit wide data type. If more than one bit is required then range declaration should be used (see Vectors for more explanations). Negative values assigned to reg data type variables are treated as unsigned values (see Arithmetic expressions with integers and registers for more explanations). Reg data type variables can be declared as memory.

The integer register is a 32-bit wide data type. Integer declarations cannot contain range specification. Integer variables can be declared as memory. Integers store signed values.

The time register is a 64-bit wide data type that is used to store simulation time and to check timing dependence. Time type registers store values as unsigned numbers. Time declaration cannot contain range specification. Time data type variables can be declared as memories.

The real register is a 64-bit wide data type that stores floating-point values. Real registers cannot be used with event control, concatenations ({}), modulus operator (%), case equality (===, !==), bit-wise operators (~, &, |, ^, ^~, ~^), reduction operators (^, ~^, ^~, &, &~, |, |~) and shift operators (<<, >>). Bit-selects and part-selects on real type variables are not allowed.

The realtime registers are treated in the same way as real registers.

Examples:

reg scal;

reg [7:0] vect;

reg [7:0] mem [31:0];

integer i;

integer i_mem [7:0];

time t;

time t_mem [3:0];

real r;

realtime rt1, rt2;

‘scal’ is a 1-bit wide reg type register.

‘vect’ is an 8-bit wide reg type register.

‘mem’ is a reg type memory of 32 8-bit words.

‘i’ is an integer type register.

‘i_mem’ is an integer type memory.

‘t’ is a time type register.

‘t_mem’ is a time type memory.

‘r’ is a real type register.

‘rt1’ and ‘rt2’ are realtime type registers.

Important Notes:

  1. New values can be assigned to registers only by using procedural statements.

  2. Some operators, bit-selects, part-selects, range and memory declaration arecannot be used with real and realtime type registers.

  3. Range can be specified only for reg data type registers.

  4. Real and realtime registers are initialized to zero value. Reg, integer and time registers are initialized to unknown value (x).


Simulation Control Tasks

Formal Definition:

Simulation control tasks allow you to stop or quit simulation.

Complete description: Language Reference Manual section §14.4.

Simplified Syntax:

$stop [(n)] ;

$finish [(n)] ;

Description:

The $stop system task is used to suspend simulation. When invoked it suspends simulation, prints simulation time and prints location. Optional expressions can determine the type of printed message:

Expression (n) | Message
0 | No message
1 | Simulation time and location
2 | Simulation time, location, memory consumption and CPU time used in simulation

By default the value 1 is used.

The $finish system task ends the simulation, exits the simulator and passes control back to the operating system. It can be invoked with the same arguments as the $stop system task and has the same default value.

Examples:

Example 1

$stop ;

Suspend simulation and print message (default argument = 1)

Example 2

#150 $finish(2) ;

Exits simulator after 150 time units from the last executed statement and prints message (argument == 2).

Important Notes:

  • Remember that $finish control system task makes the simulator exit, however $stop simply suspends simulation.


Simulation Time Functions

Formal Definition:

The simulation time function provides an access to current simulation time.

Complete description: Language Reference Manual section §14.8.

Simplified Syntax:

$time ;

$stime ;

$realtime ;

Description:

When the $time system function is called, it returns the current time as a 64-bit integer value. However, this value is scaled to the `timescale unit. (See Timescale chapter)

The $stime system function returns current time as a 32-bit unsigned integer value. If the current simulation time is too large and the value does not fit in 32 bits, the function only returns the 32 low order bits of the value. The returned value is also scaled to the `timescale.

The $realtime system function returns a value as a real number. As with the other time tasks, the returned value is scaled to the `timescale.

Examples:

Example 1

integer cur_time ;

cur_time = $time ;

Example 2

integer cur_time ;

cur_time = $stime ;

Example 3

real cur_time ;

cur_time = $realtime ;

Example 4

$display($time, "is current time.");

Important Notes:

  • $time, $stime, $realtime are functions which return specific values. If you are using these functions you have to declare registers that can support the returned value.


Specify Block

Formal Definition:

Allows a specific delay across a module.

Complete description: Language Reference Manual section §13.1, $13.2.

Simplified Syntax:

specify

specparam declaration ;

path declaration ;

system timing check ;

endspecify

Description:

The Specify block was designed to define a delay across a module. It starts with specify and ends with the endspecify keyword. Inside the block the user can specify: specparam declaration, path declaration or system timing check.

The syntax of specparam declaration is the same as that of the parameter declaration. After the specparam keyword the user can specify any number of parameters but only constant expressions are allowed on the right-hand sides of parameter assignments. A comma can separate the assignments, and the last statement ends with a semicolon. A previously declared specparameter can be used to declare the new specparameters. Unlike parameters, specparams cannot be overwritten, nor can they be used outside of a specify block.

Examples:

Example 1

module ...

...

specify

(In => Out) = (10);

endspecify

...

endmodule

A specify block with only a path declaration. Delay between input In and output Out is 10 time units.

Example 2

module ...

...

specify

specparam TRise = 10,

TFall = 15;

(In => Out) = (TRise, TFall) ;

endspecify

...

endmodule

Specparam declaration with two parameters TRise and TFall to specify delays on rising transition and falling transition.

Example 3

module ...

...

specify

specparam TRise = 10,

TFall = 15;

(In => Out) = (TRise, TFall) ;

$setup(Data_in, posedge Clock, TRise) ;

endspecify

...

endmodule

The full specify block with specparam declaration, path declaration and system timing check task.

Important Notes:

  • Specify blocks have to be inside the module declaration location.

  • Specparams are not visible outside of the Specify blocks.

  • The defparam keyword cannot be used to override a specparam value.


State Dependent Path

Formal Definition:

State Dependent Path is a path that occurs only when the condition is met.

Complete description: Language Reference Manual section §13.3.4.

Simplified Syntax:

if (condition) simple_module_path;

if (condition) edge_sensitive_path;

ifnone simple_module_path;

Description:

Generally, state dependent path is comprised of three parts. A condition that enables the module path, a module path description and a delay that applies to the module path.

The condition is an expression using scalars or vectors of any type. It can also be part-selects or bit-selects of a vector. Constant numbers and specparams can be used in the condition expression. The result of the conditional expression can be one bit or multiple bits. If it is more than one bit, the least significant bit represents the result.

When no edge transition is specified for the inputs, it is called the simple state-dependent path. Example 1 shows the simple-dependent path.

If any edge transition is specified for the input, then it is called an edge-sensitive state-dependent path. Different delays can be used to the same path if the following rules are followed:

  1. A declaration must be unique and should use an edge or a conditional expression or both.

  2. The port for which the delay is specified must be referenced in exactly the same way. You cannot mix part select, bit-select and complete ports.

Examples:

Example 1

module example1 (cond, in_1, in_2, out);

input in_1, in_2, cond ;

output out ;

and (out, in_1, in_2) ;

specify

specparam TRise1 = 5,

TFall1 = 5,

TRise2 = 7,

TFall2 = 7;

if (cond) ( in_1, in_2 *> out ) = (TRise1, TFall1);

if (~cond) ( in_1, in_2 *> out ) = (TRise2, TFall2);

endspecify

endmodule

If a conditional expression ‘cond’ is true, TRise1 and TFall1 will be assigned to a path as delays. When the conditional expression ‘cond’ is false, TRise2 and TFall2 will be used as the path delays.

Important Notes:

  • When a conditional expression evaluates to x or z, it should be treated as true.


Stochastic Analysis Tasks

Formal Definition:

Stochastic analysis tasks provide a means of managing queues.

Complete description: Language Reference Manual section §14.7.

Simplified Syntax:

$q_initialize(identifier, type, length, status) ;

$q_add(identifier, job, information, status) ;

$q_remove(identifiers, job, information, status) ;

$q_full(identifier, status) ;

$q_exam(identifier, statistic_code, statistic_value, status) ;

Description:

All statistic analysis tasks include identifier, and status arguments. The identifier is a unique integer value identifying the queue. The status argument is an output integer parameter giving information about the correctness of the specified task execution.

Status | Message
0 | The queue generation was successful.
1 | The queue cannot be increased; queue is full.
2 | The identifier is undefined; please define an identifier.
3 | Cannot remove a value; queue is empty.
4 | The queue cannot be generated; this type is unsupported.
5 | The length parameter is <= 0; the queue cannot be generated.
6 | The identifier is duplicated; please define new identifier.
7 | The queue cannot be generated; insufficient memory.

$q_initialize creates a queue. Parameter type determines the type of a queue. In case of 1, the created queue is FIFO and in case of 2 the queue is LIFO. Parameter length is an integer value specifying the maximum number of entries.

$q_add adds a new entry to the queue. Parameter job identifies the job. The special user-defined parameter, information, can maintain any information useful for the user.

$q_remove receives data from the queue. Parameters of this task are the same as those of the $q_add task.

$q_full checks to see of the queue identified by the identifier parameter is full.

$q_exam returns statistical information about the queue. Parameter statistic_code determines what you need to check and returns the result in statistic_value. The following table lists all possible values of statistic_code:

Statistic_code | Statistic_value
1 | Length of queue.
2 | Mean interarrival time.
3 | Maximum length of queue.
4 | Shortest wait time.
5 | Longest wait time for jobs still in the queue.
6 | Average wait time in the queue.

Examples:

Example 1

always @(posedge clk)

begin

// check if queue1 is full

$q_full(queue1, status);

// if full then show message and remove one item

if (status) begin

$display(“Queue is full”);

$q_remove(queue1, 1, info, status);

end

// add a new item to queue1

$q_add(queue1, 1, info, status);

// show message if there was an error

if (status)

$display(“Error %d”,status);

end

end

This example shows how to add a new element to the queues.

Important Notes:

  1. The status parameter value should be checked after all operations on the queue.


Strengths

Formal Definition:

The strength declaration construct is used for modeling net type variables for a close correspondence with physical wires.

Complete description: Language Reference Manual section §7.10.

Simplified Syntax:

(Strength1, Strength0)

(Strength0, Strength1)

Strength1:

supply1, strong1, pull1, large1, weak1, medium1, small1, highz1

Strength0:

supply0, strong0, pull0, large0, weak0, medium0, small0, highz0

Description:

Strengths can be used to resolve which value should appear on a net or gate output.

There are two types of strengths: drive strengths (Example 1) and charge strengths (Example 2). The drive strengths can be used for nets (except trireg net), gates, and UDPs. The charge strengths can be used only for trireg nets. The drive strength types are supply, strong, pull, weak, and highz strengths. The charge strength types are large, medium and small strengths.

All strengths can be ordered by their value. The supply strength is the strongest and the highz strength is the weakest strength level. Strength value can be displayed by system tasks ($display, $monitor – by using of the %v characters – see Display tasks for more explanation).

Strength | Value | Value displayed by display tasks
supply | 7 | Su
strong | 6 | St
pull | 5 | Pu
large | 4 | La
weak | 3 | We
medium | 2 | Me
small | 1 | Sm
highz | 0 | HiZ

Table 23 Strengths ordered by value

If two or more drivers drive a signal then it will have the value of the strongest driver (Example 3).

If two drivers of a net have the same strength and value, then the net result will have the same value and strength (Example 4).

If two drivers of a net have the same strength but different values then signal value will be unknown and it will have the same strength as both drivers (Example 5).

If one of the drivers of a net has an H or L value, then signal value will be n1n2X, where n1 is the strength value of the driver that has the smaller strength, and n2 is strength value of driver that has the larger strength (Example 6).

The combinations (highz0, highz1) and (highz1, highz0) are illegal.

Examples:

Example 1

and (strong1, weak0) b(o, i1, i2);

Instance of and gate with strong1 strength and weak0 strength specified.

Example 2

trireg (medium) t;

The charge strength declaration for trireg net.

Example 3

buf (strong1, weak0) g1 (y, a);

buf (pull1, supply0) g2 (y, b);

If a = 0 and b = 0 then y will be 0 with supply strength because both gates will set y to 0 and supply (7) strength has bigger value than weak (3) strength.

If a = 0 and b = 1 then y will be 1 with pull strength because g1 will set y to 0 with weak (3) strength and g2 will set y to 1 with pull (5) strength (pull strength is stronger than the weak strength).

If a = 1 and b = 0 then y will be 0 with supply strength because g1 will set y to 1 with strong (6) strength and g2 will set y to 0 with supply (7) strength (supply strength is stronger than the strong strength).

If a = 1 and b = 1 then y will be 1 with strong strength because g1 will set y to 1 with strong (6) strength and g2 will set y to 1 with pull (5) strength.

Example 4

buf (strong1, weak0) g1 (y, a);

buf (strong1, weak0) g1 (y, b);

If a = 0 and b = 0 then y will be 0 with weak strength.

If a = 1 and b = 1 then y will be 1 with strong strength.

Example 5

buf (strong1, weak0) g1 (y, a);

buf (weak1, strong0) g1 (y, b);

If a = 1 and b = 0 then y will be x with strong strength.

Example 6

bufif0 (strong1, weak0) g1 (y, i1, ctrl);

bufif0 (strong1, weak0) g2 (y, i2, ctrl);

If ctrl = x, i1 = 0, and i2 = 1 then y will be x with 36X strength, because g1 will set y to L with strong strength (StL - 6) and g2 will set y to H with weak strength (WeH - 3).

Important Notes:

  1. If one of the drivers has an H or L value, then the output value will be X.


Strings

Formal Definition:

The strings are sequences of 8-bit ASCII characters enclosed within quotation marks.

Complete description: Language Reference Manual section §2.6.

Simplified Syntax:

"This is a string"

reg [8*number_of_characters:1] string_variable;

Description:

The string should be given in one line. Strings can contain special characters (Example 1).

Character | Meaning
\n | New line character
\t | Tab character
\\ | \ character
\” | “ character
\ddd | A character specified by octal digit

Table 24: Summary of special characters

String variables should be declared as reg type vectors (Example 2). Each character needs 8 bits.

If a string variable is used in an expression, it should be treated as an unsigned value. If the size of a string assigned to a string variable is smaller than the declared size of the variable, then it will be left-padded with zeros.

The null string “” should be treated same as “\0”.

Concatenations of string variables preserve left-padded zeros of these variables (Example 3).

Examples:

Example 1

"\n This is the first line\n This is the second line"

"\t Line\t with\t tab\t characters"

Example 2

reg [8*12:1] message;

The message variable can contain 12 characters.

Example 3

reg [10*8:1] s1, s2;

s1 = "Verilog";

s2 = "-HDL";

{s1, s2} <> {"Verilog", "-HDL"}

These expressions are not equal because {s1, s2} has 0s between “Verilog” and “–HDL” and {“Verilog”, “-HDL”} does not have any 0s between words.

Important Notes:

  1. Concatenation of string variables preserves left-padded zeros of these variables.


Structured Procedures

Formal Definition:

Structured procedures provide a means of modeling blocks of procedural statements.

Complete description: Language Reference Manual section §9.9.

Simplified Syntax:

always statement

initial statement

function

task

Description:

Functions and tasks are described in the section: Task and Functions.

The initial statement (Example 1) is executed only during a simulation run. The always procedural block statement (Example 2) is executed continuously during simulation, i.e. when the flow of program reaches the last statement in the block, the flow continues with the first statement in the block.

The always statement should contain at least one procedural timing control because otherwise it may hang the simulation.

Module definition can contain more than one initial or always statement.

Care must be taken when same reg type variables are used in multiple procedural blocks, initial or always. This is because these blocks run in parallel and changing or assigning to one variable affects the same variable in another parallel block.

Examples:

Example 1

initial out = 1’b0;

initial begin

#10;

a = 1’b0;

#10;

a = 1’b1;

#10;

a = 1’bz;

end

Example 2

always @(posedge clk)

q = d;

always #10 clk = ~clk;

initial clk = 0;

initial repeat(20)#\0 clk=~clk;

The first initial statement sets clk to 0 at time 0, and the second initial block toggles the clk 20 times every 10 time units.

Important Notes:

  1. The always statement should contain at least one procedural timing control.


Tasks

Formal Definition:

Tasks provide a means of splitting code into small parts. Often tasks consist of frequently used functionalities.

Complete description: Language Reference Manual section §10.2.

Simplified Syntax:

task identifier;

parameter_declaration;

input_declaration;

output_declaration;

inout_declaration;

register_declaration;

event_declaration;

statement;

endtask

Description:

Task definition begins with the keyword task and ends with the keyword endtask. A task should be followed by a task identifier and end with a semicolon. A task can contain a declaration of parameters, input arguments, output arguments, inout arguments, registers and events (these declarations are similar to module items declaration) but they are not required. Net declaration is illegal.

A task can contain zero or more behavioral statements, e.g. case statement, if statement. A begin-end block is required for bracketing multiple statements.

The task enabling statement should be made up of a task identifier and the list of comma-separated task arguments. The list of task arguments should be enclosed in parenthesis. If the task does not contain any argument declarations, then it should be enabled by specifying its identifier followed by a semicolon (Example 2).

The list of task enabling arguments should correspond exactly to the list of task arguments. If a task argument is declared as an input, then a corresponding argument of the task enabling statement can be any expression. If a task argument is declared as an output or an inout then the corresponding argument of the task enabling statement should be one of the following items:

  1. Register data types

  2. Memory references

  3. Concatenations of registers or memory references

  4. Bit-selects and part-selects of reg, integer and time registers

Only the last assignment to an output or an inout argument is passed to the corresponding task enabling arguments. If a task has assignments to global variables, then all changes of these variables are effective immediately.

Tasks can enable others tasks (Example 3) and functions. A task may be enabled several times in a module. If one task is enabled concurrently, then all registers and events declared in that task should be static, i.e., one variable for all instances.

A task can contain time-controlling statements. A task does not return a value by its name.

Examples:

Example 1

task first_task;

parameter size = 4;

input a;

integer a;

inout [size-1:0] b;

output c;

reg [size-1:0] d;

event e;

begin

d = b;

c = |d;

b = ~b;

if (!a) -> e;

end

endtask

This is an example of using parameters, input arguments, inout arguments, output arguments, registers and events within tasks. The ‘a’ argument is declared as an input and as an integer data type.

‘First_task’ can be enabled as follows:

integer x;

reg a, b, y;

reg [3:0] z;

reg [7:0] w;

first_task(x, z, y);

first_task(x, w[7:4], w[1]);

first_task(1, {a, b, w[3], x[0]}, y);

When being enabled, the first argument of the ‘first_task’ should be an integer data type expression, the second should be a 4-bit register expression, and the last argument should be 1-bit register expression.

Example 2

reg a, b;

task my_task; // task definition

begin

a = 1'b1;

b = 1'bx;

end

endtask

my_task; // task enabling

If ‘my_task’ is enabled then it will change the value of global variables ‘a’ and ‘b’.

Example 3

task negation;

inout data;

data = ~data;

endtask

task my_nor;

input a, b;

output c;

begin

negation(a);

negation(b);

c = a & b;

end

endtask

The ‘my_nor’ task enables negation tasks.

Important Notes:

  1. A task can contain time-controlling statements

  2. A task does not return any value by its name


Timescale System Tasks

Formal Definition:

Timescale system tasks provide a means of setting and printing timescale information.

Complete description: Language Reference Manual section §14.3.

Simplified Syntax:

$printtimescale [(hierarchical_path)] ;

$timeformat [(unit_number, precision, suffix, min_width )] ;

Description:

The $printtimeformat system task is used when information about time units and precision is needed. An argument is optional. When the $printtimescale system task is invoked without an argument, the time unit and precision of the current modules are displayed. If an argument is specified, then the time unit and precision of the module specified is displayed in a hierarchical path. The following format is used to display this information:

Time scale of (module) is unit / precision

The $timeformat system task has double functionality.

First, when any delays are entered interactively, it specifies the time unit. Second, it specifies the %t format specification. These format specifications are used in $display, $fdisplay, $write, $fwrite, $strobe, $fstrobe and $monitor, $fmonitor system tasks.

The first argument of $timeformat system task should be an integer.

Unit | Time | Unit | Time
0 | 1 s | -8 | 10 ns
-1 | 100 ms | -9 | 1 ns
-2 | 10 ms | -10 | 100 ps
-3 | 1 ms | -11 | 10 ps
-4 | 100 us | -12 | 1 ps
-5 | 10 us | -13 | 100 fs
-6 | 1 us | -14 | 10 fs
-7 | 100 ns | -15 | 1 fs

Default argument values are given in the following table:

Argument | Value
Unit | The smallest time precision argument of all the `timescale compiler directives in the source description
Precision | 0
Suffix | Null
Minimum width | 20

Examples:

Example 1

`timescale 1 ns / 100 ps

module a (y, a, b);

output y;

input a, b;

assign y = a & b;

endmodule

`timescale 1 s / 10 fs

module top;

wire y, a, b;

a u(y, a, b);

initial $printtimescale(top.u);

endmodule

Important Notes:

  • The $timeformat system task specifies the %t format specification until the next `timescale compiler directive occurs.


Timing Check Tasks

Formal Definition:

Timing Check Tasks are for verification of timing properties of designs and for reporting timing violations.

Complete description: Language Reference Manual section §14.5.

Simplified Syntax:

$setup (data_event, reference_event, limit[, notifier]) ;

$skew (reference_event, data_event, limit[,notifier]) ;

$hold (reference_event, data_event, limit[,notifier]) ;

$recovery (reference_event, data_event, limit, [notifier]) ;

$setuphold (reference_event, data_event, setup_limit, hold_limit, [notifier]) ;

$width (reference_event, limit, threshold [,notifier]) ;

$period (reference_event, limit[,notifier]) ;

$nochange (reference_event, data_event, start_edge_offset, end_edge_offset [,notifier]) ;

Description:

Timing check tasks are invoked every time critical events occur within given time limits. See the table below with descriptions of all arguments:

Argument | Description | Type
Reference_event | The transition at a control signal that establishes the reference time for tracking timing violations on the data_event | Module input or inout that is scalar or vector net
Data_event | The signal change that initiates the timing check and is monitored for violations. | Module input or inout that is scalar or vector net
Limit | A time limit used to detect timing violations on the data_event | Constant expression or specparam
Threshold | The largest pulse width that is ignored by the timing check $width | Constant expression or specparam
Setup_limit | A time limit used to detect timing violations on the data_event for $setup. | Constant expression or specparam
Hold_limit | A time limit used to detect timing violations on the data_event for $hold. | Constant expression or specparam
Notifier | An optional argument that "notifies" the simulator when a timing violation occurs | Register

$setup checks setup time. When modeling synchronous circuits, flip-flops need time to force a correct value. Data cannot change within the setup time because flip-flops cannot detect the new value. If data changes within a given time limit, $setup reports a timing violation. If a data event and reference event occur at the same time there is no violation. The $setup first checks timing data then records a new data value. The formula to report a timing violation is as shown below:

(time of reference event) - (time of data event) < limit

Notice that the limit argument has to be a positive number.

$skew checks the following:

(time of data event) - (time of reference event) > limit

$skew can be used to check synchronicity of clocks inside a circuit. If different clocks are used in a design and are synchronized, $skew will report a timing violation when the active edge of one of them occurs outside the time limit allowed for the other clock to occur.

When the data event and the reference event occur at the same time, $skew will not report a timing violation.

$hold will report a timing violation if the following formula is true:

(time of data event) - (time of reference event) < limit

$hold simply checks that data is stable in the specified interval of time after the edge of the clock. In flip-flops, data should remain stable for a given time after the active edge of the clock to allow for propagation of data.

Also, a violation will be reported if the data event and the reference event occur at the same time.

$recovery responds when the following formula is true:

(time of data event) - (time of reference event) < limit

The ‘reference_event’ must be an edge-triggered event: posedge or negedge. A timing violation occurs if the time interval between an edge-triggered reference event and a data event exceeds the ‘limit’. If a reference event and data event occur at the same time, a timing violation is reported. If a ‘reference_event’ argument is specified without edge specification, an error is reported.

$setuphold checks setup and hold timing violations. This task combines the functionality of $setup and $hold in one task. The following formula has to be applied:

setup_limit + hold_limit > 0

‘reference_event’ have to be one of the following:

  1. $hold lower bound event

  2. $setup upper bound event

‘data_event’ have to be one of the following:

  1. $hold upper bound event

  2. $setup lower bound event

In $width both limit and threshold have to be positive numbers. The ‘reference_event’ must be the edge specification, otherwise an error will be reported. The ‘data_event’ is not specified directly, but by default means ‘reference_event’ with opposite edge. A timing violation occurs with the following formula:

threshold < (time of data event) - (time of reference event) < limit

$width reports when width of the active-edge is too small. In FF case it is very important to ensure that the width of an active-edge is sufficient and FF will work properly.

The $period checks that a period of signal is sufficiently long. The reference_event has to be an edge specification. The data_event is not specified directly and by default, is the same as a reference_event. The $period reports a timing violation when the following formula comes true:

(time of data event) - (time of reference event) < limit

The $nochange checks if the data signal is stable in an interval of start_edge_offset and end_edge_offset. If the signal has changed, a timing violation is reported. The reference_event argument can be posedge or negedge but the edge control specifiers are disallowed.

Examples:

Example 1

module setup (data1, data2, q);

input data1, data2;

output q;

and (q, data1, data2);

specify

specparam tsetup = 7, delay = 10 ;

(data1 => q) = 10 ;

$setup(data1, posedge data2, tsetup);

endspecify

endmodule

Example 2

module two_clocks (clk1, clk2, q);

input clk1, clk2;

output q;

specify

specparam tskew = 7;

$skew(posedge clk1, posedge clk2, tskew);

endspecify

endmodule

Example 3

module hold (data1, data2, q);

input data1, data2;

output q;

and (q, data1, data2);

specify

specparam thold = 7, delay = 10 ;

(data1 => q) = 10 ;

$hold(posedge data2, data1, thold);

endspecify

endmodule

Example 4

module recovery (in1, out1);

input in1 ;

output out1 ;

assign out1 = in1 ? 1'b1 : 1'bz ;

specify

specparam trecovery = 10;

$recovery(posedge in1, out1, trecovery);

endspecify

endmodule

Example 5

module setuphold (data1, data2, q);

input data1, data2;

output q;

and (q, data1, data2);

specify

specparam tsetup = 7,

thold = 7,

delay = 10 ;

(data1 => q) = 10 ;

$setuphold(posedge data2, data1, tsetup, thold);

endspecify

endmodule

Example 6

module width (data1, data2, q);

input data1, data2;

output q;

and (q, data1, data2);

specify

specparam twidth = 10,

delay = 10 ;

(data2 => q) = 10 ;

$width(posedge data2, twidth);

endspecify

endmodule

Example 7

module dff (clk, q);

input clk;

output q;

buf (q, clk);

specify

specparam tperiod = 100 ;

$period(posedge clk, tperiod);

endspecify

endmodule

Example 8

module nochange (data1, data2, q);

input data1, data2;

output q;

and (q, data1, data2);

specify

specparam tstart = -5,

tend = 5 ;

$nochange(posedge data2, data1, tstart, tend);

endspecify

endmodule

Important Notes:

  • All timing check system tasks should be invoked within specify blocks.


UDP Declaration

Formal Definition:

User Defined Primitives (UDP) provide a means of expanding a set of built-in primitives.

Complete description: Language Reference Manual section §8.1.

Simplified Syntax:

primitive udp_name ( port_list );

output output_port;

input list_of_imputs;

initial output_port = value;

table

combinational_input_list : output_value;

sequential_input_list : current_state : next_state;

endtable

endprimitive

Description:

User Defined Primitives can describe both combinational (Example 1) and sequential (Example 2) circuits. The behavioral description is provided as a truth table.

The UDP declaration starts with the keyword primitive and ends with the keyword endprimitive. A port list, an output port declaration and input ports declaration are similar to their equivalents in a module declaration.

Port list

The port list contains a comma-separated list of primitive ports. There can be only one output port and several input ports. The inout ports are illegal. The first port on the list should be the output port. There are some restrictions concerning the number of input ports. The combinational UDPs list of ports should not contain more than 10 inputs, and the sequential UDPs port list should not contain more than 9 inputs. If the port list contains more inputs, then a warning will be issued. These restrictions are caused by illegibility of written UDPs.

Port declaration

Input and output port declarations should match the port list of the UDP they are enclosed in. If the described UDP is sequential, then reg declaration for output port should be provided. All ports of the UDP should be of scalar type (1-bit wide). Vectors are illegal.

Initial statement

Sequential UDPs can contain an initial statement for an output port. This statement begins with the keyword initial, followed by an assignment to the output port. Assigned values should be 1-bit wide and there must not be any delays.

State table

The state table starts with the keyword table and ends with the keyword endtable. The state tables for combinational and sequential UDPs are different. The state table is comprised of rows each of which ended with a the semicolon. Table row describes the behavior of UDP for a particular combination of inputs. The combinational UDPs have two fields separated by a colon. One field is for the inputs and one for the outputs. The sequential UDPs have three fields: one for the inputs, one for the current output state, and one for the next output state. If any combination of input signals, is not explicitly specified in the UDP declaration, the output value will be unknown (x). A particular combination of inputs can be specified only one time.

Examples:

Example 1

primitive and_gate (o, in1, in2);

output o;

input in1, in2;

table

// in1 in2 : o

0 0 : 0;

0 1 : 0;

1 0 : 0;

1 1 : 1;

endtable

endprimitive

Example of simple combinational UDP based on the and gate truth table.

Example 2

primitive d_ff (q, d, clk);

output q;

reg q;

input d, clk;

table

// d clk : q : q+

0 p : ? : 0;

1 p : ? : 1;

? n : ? : -;

endtable

endprimitive

Example of sequential UDP based on a D flip-flop.

Important Notes:

  1. UDP can have only one output.

  2. Inout ports are illegal.

  3. Combinational UDP should not have more than 10 inputs.

  4. Sequential UDP should not have more than 9 inputs.

  5. Vector declaration for UDP ports is illegal.


UDP Instantiation

Formal Definition:

The UDP instantiation provides a means of using UDP in modules.

Complete description: Language Reference Manual section §8.6.

Simplified Syntax:

udp_name (strengths) #(delays) instance_name[range] (list of ports);

Description:

UDPs can be instantiated only within modules.

The name of an instance is optional (Example 1). A UDP instantiation can contain strength and delays declarations (Example 2). UDPs do not support high-impedance (z) values, therefore only two delays are permitted. Signals connected to input ports can be any net or reg data type. Only net data type variables can be connected to the output port. The strength declaration can contain only drive strength.

It is possible to specify an array of UDP instances by using a range (Example 3).

Examples:

Example 1

primitive d_ff (q, clk, d);

...

endprimitive

d_ff (q, clk, d);

The name of an instance is optional.

Example 2

d_ff (weak1, strong0) #5 d1 (q, clk, d);

UDP instance with strength and delay declaration.

Example 3

wire [3:0] q;

reg [3:0] d;

reg clk;

d_ff flips[3:0] (q, clk, d);

Important Notes:

  1. UDP instantiation can contain up to two delay values.


UDP State Table

Formal Definition:

A UDP state table defines the behavior of UDP.

Complete description: Language Reference Manual section §8.1.

Simplified Syntax:

table

comb_input comb_input ... comb_input : output;

seq_input seq_input ... seq_input : current_state : next_state;

endtable

Description:

Each row of the state table defines the behavior of the UDP for a specific input combination. Each combination of inputs can be given only one time. It is illegal to define the same combination of inputs for different outputs.

The number of input values must match the number of UDP inputs in a port declaration.

The UDP state table for combinational and sequential UDPs is different. The combinational UDPs (Example 1) contain two fields: an input field and an output field. The sequential UDPs (Example 2) contain three fields: an input, a current state, and the next state (output) field.

The input field should contain a list of values (separated by white spaces), which should match the number of UDP input ports. The order of these ports is highly important. The first input port on the UDP port list matches the first input value in each row.

The rows of the state table can contain only 0, 1, unknown (x) value, and special characters. The high-impedance (z) value cannot be specified. The special characters are provided to increase readability of a description and to make it easier (Example 3).

Symbol | Interpretation | Comments
0 | Logic 0 |
1 | Logic 1 |
x | Unknown value | Not permitted in output field.
b | Substitute for 0 and 1 | Not permitted in output field.
? | Substitute for 0, 1, and x | Not permitted in output field.
- | No change | Permitted only in output field of sequential UDPs.
(vw) | Transition from v to w value | Permitted only in input field of sequential UDPs. v and w can be 0, 1, x, b, and ?
* | Same as (??) | Any value change on input. Permitted only in input field of sequential UDPs.
r | Same as (01) | Rising edge on input. Permitted only in input field of sequential UDPs.
f | Same as (10) | Falling edge on input. Permitted only in input field of sequential UDPs.
p | Same as (01), (0x), (x1) | Positive edge on input. Permitted only in input field of sequential UDPs.
n | Same as (10), (1x), (x0) | Negative edge on input. Permitted only in input field of sequential UDPs.

Table 25: Summary of symbols

If some combinations of input signal values are not specified in a UDP state tables then the output value will be unknown (x).

Only one transition can appear in each row of sequential UDPs.

Examples:

Example 1

primitive mux (o, i3, i2, i1, i0, a1, a0);

output o;

input i3, i2, i1, i0, a1, a0;

table

// i3 i2 i1 i0 a1 a0 : o;

0 ? ? ? 1 1 : 0;

1 ? ? ? 1 1 : 1;

? 0 ? ? 1 0 : 0;

? 1 ? ? 1 0 : 1;

? ? 0 ? 0 1 : 0;

? ? 1 ? 0 1 : 1;

? ? ? 0 0 0 : 0;

? ? ? 1 0 0 : 1;

endtable

endprimitive

If any address bit (a1, a0) is unknown, then the output value will be unknown (because there is no row which describes the output value for this combination of address signals).

If a1 = 0 and a0 = 0 then the signal from input i0 is driven to output (value of others inputs does not matter).

If a1 = 0 and a0 = 1 then signal from input i1 is driven to the output.

If a1 = 1 and a0 = 0 then signal from input i2 is driven to the output.

If a1 = 1 and a0 = 1 then signal from input i3 is driven to the output.

Example 2

primitive special_d_ff (q, clk, m, d, rst, set);

output q;

reg q;

input clk, m, d, rst, set;

table

// clk m d rst set : current : next;

// positive edge on clk and normal mode (m = 0)

(01) 0 0 0 0 : ? : 0 ; // line 1

(0x) 0 0 0 0 : ? : 0 ; // line 2

(x1) 0 0 0 0 : ? : 0 ; // line 3

(01) 0 1 0 0 : ? : 1 ; // line 4

(0x) 0 1 0 0 : ? : 1 ; // line 5

(x1) 0 1 0 0 : ? : 1 ; // line 6

// positive edge on clk and negation mode (m = 1)

p 1 ? 0 0 : 0 : 1 ; // line 7

p 1 ? 0 0 : 1 : 0 ; // line 8

// negative edge on clk and any mode (m = 0 or m = 1)

n ? ? 0 0 : ? : - ; // line 9

// reset

? ? ? 1 ? : ? : 0 ; // line 10

// preset

? ? ? 0 1 : ? : 1 ; // line 11

// any changes on inputs with no changes on clk

? * ? ? ? : ? : - ; // line 12

? ? * ? ? : ? : - ; // line 13

? ? ? * ? : ? : - ; // line 14

? ? ? ? * : ? : - ; // line 15

endtable

endprimitive

This is ‘d’ flip-flop with an additional input, which can convert it into a modulo 2 counter.

If m = 0 then this UDP works as a normal ‘d’ flip-flop (lines 1-6), but if m = 1 then it negates its current value (lines 7 and 8). If any falling edge occurs on the clk input, then it will not change the output (line 9). If rst is 1, then the output will go to 0 (line 10). If the rst is 0 and set is 1, then the output will go to 1 (line 11 - it means that rst has higher priority than set).

Any changes on the data input will not cause any changes on output (lines 12-15).

Example 3

primitive circuit_1 (o, i1, i2, i3);

output o;

input i1, i2, i3;

table

0 0 0 : 1 ;

0 0 1 : 1 ;

0 0 x : 1 ;

0 1 0 : 1 ;

0 1 1 : 1 ;

0 1 x : 1 ;

1 0 0 : 0 ;

1 0 1 : 0 ;

1 0 x : 0 ;

1 1 0 : 1 ;

1 1 1 : 1 ;

1 1 x : 1 ;

x 0 0 : 0 ;

x 0 1 : 0 ;

x 0 x : 0 ;

x 1 0 : 0 ;

x 1 1 : 0 ;

x 1 x : 0 ;

endtable

endprimitive

primitive circuit_2 (o, i1, i2, i3);

output o;

input i1, i2, i3;

table

0 ? ? : 1 ;

1 0 ? : 0 ;

1 1 ? : 1 ;

x b ? : 0 ;

endtable

endprimitive

‘Circuit_1’ and ‘circit_2’ are the same circuit, but the behavior of the ‘circuit_1’ was specified without special characters.

Important Notes:

  1. Each row of sequential UDPs can contain only one transition.

  2. Special characters can make the UDP state table easier to read and write.

  3. Any undefined combination of inputs will set the output to x value.


Value Change Dump (VCD) File

Formal Definition:

The Value change dump (VCD) file contains information about any value changes on the selected variables.

Complete description: Language Reference Manual section §15.

Simplified Syntax:

$dumpfile(name)

$dumpvars

$dumpvars(level, list_of_variables_or_modules)

$dumpoff

$dumpon

$dumpall

$dumplimit

$dumpflush

Description:

$dumpfile(filename)

This task is used to specify the VCD file name. The filename parameter is optional. If it is not given, then the file will be named “Verilog.dump”.

$dumpvars(level, list_of_variables_or_modules)

This task is used to specify which variables should be dumped. Both parameters are optional and if none are used, then all variables will be dumped.

If level = 0, then all variables within the modules from the list will be dumped. If any module from the list contains module instances, then all variables from these modules will also be dumped.

If level = 1, then only listed variables and variables of listed modules will be dumped.

$dumpoff

This task stops the dumping of variables. All variables are dumped with x value and all next changes of variables will not be dumped.

$dumpon

This task starts previously stopped dumping of variables.

$dumpall

When this task is used, then the current value of all dumped variables will be written to file.

$dumplimit(filesize)

This task can set the maximum size of the VCD file.

$dumpflush

This task can be used to make sure that all changes of dumped variables are written to file.

Examples:

module top;

reg a, b;

wire y;

assign y = a & b;

always begin

a = 1'b0;

#10;

a = 1'b1;

#10;

a = 1'bx;

#10;

end

always begin

b = 1'b0;

#30;

b = 1'b1;

#30;

b = 1'bx;

#30;

end

initial begin

$dumpfile("test.txt");

$dumpvars(1,a,y);

#200;

$dumpoff;

#200;

$dumpon;

#20;

$dumpall;

#10;

$dumpflush;

end

endmodule

The dumpfile will contain only changes of ‘a’ and ‘y’ variables. After 200 time units, dumping will be suspended for 200 time units. Next, dumping will start again and after 20 time units, all variables will be dumped.

Important Notes:

  1. Value change dump file can be used for hierarchical monitoring of all signal changes within design modules.


Vectors

Formal Definition:

Vectors are multiple bit widths net or reg data type variables that can be declared by specifying their range.

Complete description: Language Reference Manual section §3.3.

Simplified Syntax:

net_type [msb:lsb] list_of_net_identifiers;

reg [msb:lsb] list_of_register_identifiers;

Description:

Vector range specification contains two constant expressions: the msb (most significant bit) constant expression, which is the left-hand value of the range and the lsb (least significant bit) constant expression, which is the right-hand value of the range. The msb and lsb constant expressions should be separated by a colon.

Both the msb constant expression and the lsb constant expression can be any value – positive, negative, or zero. The lsb constant expression can be greater, equal or less than the msb constant expression.

Vectors can be declared for all types of net data types and for reg data types. Specifying vectors for integer, real, realtime, and time data types is illegal.

Vector nets and registers are treated as unsigned values (see: Arithmetic expressions with registers and integers for more explanations).

Examples:

Example 1

reg [3:0] addr;

The ‘addr’ variable is a 4-bit vector register made up of addr[3] (the most significant bit), addr[2], addr[1], and addr[0] (the least significant bit).

Example 2

wire [-3:4] d;

The d variable is 8-bit vector net made up of d[-3] (msb), d[-2], d[-1], d[0], d[1], d[2], d[3], d[4] (lsb).

Example 3

tri [5:0] x, y, z;

The above line declares three 6-bit vectors.

Important Notes:

  1. Both the msb and the lsb expressions should be constant expressions.

  2. The msb and the lsb constant expressions may be positive, negative, or zero.

  3. The lsb constant expression may be greater, equal or less than the msb constant expression.

  4. Vectors can be declared only for nets and reg data types.

  5. Vector declaration for integer, real, realtime, and time data types are illegal.