11.2   Basics of the Verilog Language

Chapter start

Previous page

Next page

11.2   Basics of the Verilog Language

A Verilog identifier [Verilog LRM2.7], including the names of variables, may contain any sequence of letters, digits, a dollar sign '$' , and the underscore '_' symbol. The first character of an identifier must be a letter or underscore; it cannot be a dollar sign '$' , for example. We cannot use characters such as '-' (hyphen), brackets, or '#' (for active-low signals) in Verilog names (escaped identifiers are an exception). The following is a shorthand way of saying the same thing:

identifier ::= simple_identifier | escaped_identifier
simple_identifier ::= [a-zA-Z][a-zA-Z_$]
escaped_identifier ::=
  \ {Any_ASCII_character_except_white_space} white_space
white_space ::= space | tab | newline

If we think of '::=' as an equal sign, then the preceding "equation" defines the syntax of an identifier. Usually we use the Backus-Naur form (BNF) to write these equations. We also use the BNF to describe the syntax of VHDL. There is an explanation of the BNF in Appendix A. Verilog syntax definitions are given in Appendix B. In Verilog all names, including keywords and identifiers, are case-sensitive. Special commands for the simulator (a system task or a system function) begin with a dollar sign '$' [Verilog LRM 2.7]. Here are some examples of Verilog identifiers:

module identifiers;
/* Multiline comments in Verilog
  look like C comments and // is OK in here. */
// Single-line comment in Verilog.
reg legal_identifier,two__underscores;
reg _OK,OK_,OK_$,OK_123,CASE_SENSITIVE, case_sensitive;
reg \/clock ,\a*b ; // Add white_space after escaped identifier.
//reg ,123_BAD; // Bad names even if we declare them!
initial begin 
legal_identifier = 0; // Embedded underscores are OK,
two__underscores = 0; // even two underscores in a row.
_OK = 0; // Identifiers can start with underscore
OK_ = 0; // and end with underscore.
OK$ = 0; // $ sign is OK, but beware foreign keyboards.
OK_123 =0; // Embedded digits are OK.
CASE_SENSITIVE = 0; // Verilog is case-sensitive (unlike VHDL).
case_sensitive = 1;
\/clock = 0; // An escaped identifier with \ breaks rules,
\a*b = 0; // but be careful to watch the spaces!
("Variable case_sensitive= %d",case_sensitive);
("Variable \/clock = %d",\/clock );
("Variable \a*b = %d",\a*b ); 
end endmodule

The following is the output from this model (future examples in this chapter list the simulator output directly after the Verilog code).

Variable case_sensitive= 1
Variable /clock = 0
Variable \a*b = 0

11.2.1   Verilog Logic Values

Verilog has a predefined logic-value system or value set [Verilog LRM 3.1] that uses four logic values: '0' , '1' , 'x' , and 'z' (lowercase 'x' and lowercase 'z' ). The value 'x' represents an uninitialized or an unknown logic value--an unknown value is either '1' , '0' , 'z' , or a value that is in a state of change. The logic value 'z' represents a high-impedance value, which is usually treated as an 'x' value. Verilog uses a more complicated internal logic-value system in order to resolve conflicts between different drivers on the same node. This hidden logic-value system is useful for switch-level simulation, but for most ASIC simulation and synthesis purposes we do not need to worry about the internal logic-value system.

11.2.2   Verilog Data Types

There are several data types in Verilog--all except one need to be declared before we can use them. The two main data types are nets and registers [Verilog LRM 3.2]. Nets are further divided into several net types. The most common and important net types are: wire and tri (which are identical); supply1 and supply0 (which are equivalent to the positive and negative power supplies respectively). The wire data type (which we shall refer to as just wire from now on) is analogous to a wire in an ASIC. A wire cannot store or hold a value. A wire must be continuously driven by an assignment statement (see Section 11.5). The default initial value for a wire is 'z' [Verilog LRM3.6]. There are also integer, time, event, and real data types.

module declarations_1;
wire pwr_good, pwr_on, pwr_stable; // Explicitly declare wires.
integer i; // 32-bit, signed (2's complement).
time t; // 64-bit, unsigned, behaves like a 64-bit reg.
event e; // Declare an event data type.
real r; // Real data type of implementation defined size.
// An assign statement continuously drives a wire:
assign pwr_stable = 1'b1; assign pwr_on = 1; // 1 or 1'b1
assign pwr_good = pwr_on & pwr_stable;
initial begin 
i = 123.456; // There must be a digit on either side 
r = 123456e-3; // of the decimal point if it is present.
t = 123456e-3; // Time is rounded to 1 second by default.
("i=%0g",i," t=%6.2f",t," r=%f",r); 
#2 ("TIME=%0d",," ON=",pwr_on,
  " STABLE=",pwr_stable," GOOD=",pwr_good);
; end 
i=123 t=123.00 r=123.456000

A register data type is declared using the keyword reg and is comparable to a variable in a programming language. On the LHS of an assignment a register data type (which we shall refer to as just reg from now on) is updated immediately and holds its value until changed again. The default initial value for a reg is 'x' . We can transfer information directly from a wire to a reg as shown in the following code:

module declarations_2;
reg Q, Clk; wire D;
// Drive the wire (D):
assign D = 1;
// At a +ve clock edge assign the value of wire D to the reg Q:
always @(posedge Clk) Q = D; 
initial Clk = 0; always #10 Clk = ~ Clk;
initial begin #50; ; end 
always begin 
("T=%2g", ," D=",D," Clk=",Clk," Q=",Q); #10; end 
T= 0 D=z Clk=0 Q=x
T=10 D=1 Clk=1 Q=x
T=20 D=1 Clk=0 Q=1
T=30 D=1 Clk=1 Q=1
T=40 D=1 Clk=0 Q=1

We shall discuss assignment statements in Section 11.5. For now, it is important to recognize that a reg is not always equivalent to a hardware register, flip-flop, or latch. For example, the following code describes purely combinational logic:

module declarations_3;
reg a,b,c,d,e;
initial begin 
  #10; a = 0;b = 0;c = 0;d = 0; #10; a = 0;b = 1;c = 1;d = 0;
  #10; a = 0;b = 0;c = 1;d = 1; #10; ;
always begin 
  @(a or b or c or d) e = (a|b)&(c|d);
  ("T=%0g",," e=",e);
T=10 e=0
T=20 e=1
T=30 e=0

A single-bit wire or reg is a scalar (the default). We may also declare a wire or reg as a vector with a range of bits [Verilog LRM 3.3]. In some situations we may use implicit declaration for a scalar wire ; it is the only data type we do not always need to declare. We must use explicit declaration for a vector wire or any reg . We may access (or expand) the range of bits in a vector one at a time, using a bit-select, or as a contiguous subgroup of bits (a continuous sequence of numbers--like a straight in poker) using a part-select [Verilog LRM 4.2]. The following code shows some examples:

module declarations_4;
wire Data; // A scalar net of type wire.
wire [31:0] ABus, DBus; // Two 32-bit-wide vector wires:
// DBus[31] = leftmost = most-significant bit  = msb
// DBus[0] = rightmost = least-significant bit = lsb
// Notice the size declaration precedes the names.
// wire [31:0] TheBus, [15:0] BigBus; // This is illegal.
reg [3:0] vector; // A 4-bit vector register.
reg [4:7] nibble; // msb index < lsb index is OK.
integer i;
initial begin 
i = 1;
vector = 'b1010; // Vector without an index.
nibble = vector; // This is OK too.
#1; ("T=%0g",," vector=", vector," nibble=", nibble);
#2; ("T=%0g",," Bus=%b",DBus[15:0]);
assign DBus [1] = 1; // This is a bit-select.
assign DBus [3:0] = 'b1111; // This is a part-select.
// assign DBus [0:3] = 'b1111; // Illegal : wrong direction.
T=1 vector=10 nibble=10
T=3 Bus=zzzzzzzzzzzz1111

There are no multidimensional arrays in Verilog, but we may declare a memory data type as an array of registers [Verilog LRM 3.8]:

module declarations_5;
reg [31:0] VideoRam [7:0]; // An 8-word by 32-bit wide memory.
initial begin 
VideoRam[1] = 'bxz; // We must specify an index for a memory.
VideoRam[2] = 1; 
VideoRam[7] = VideoRam[VideoRam[2]]; // Need 2 clock cycles for this.
VideoRam[8] = 1; // Careful! the compiler won't complain about this!
// Verify what we entered:
("VideoRam[0] is %b",VideoRam[0]);
("VideoRam[1] is %b",VideoRam[1]);
("VideoRam[2] is %b",VideoRam[2]);
("VideoRam[7] is %b",VideoRam[7]);
VideoRam[0] is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VideoRam[1] is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz
VideoRam[2] is 00000000000000000000000000000001
VideoRam[7] is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz

We may also declare an integer array or time array in the same way as an array of reg , but there are no real arrays [Verilog LRM 3.9]:

module declarations_6;
integer Number [1:100]; // Notice that size follows name
time Time_Log [1:1000]; // - as in an array of reg.
// real Illegal [1:10]; // Illegal. There are no real arrays.

11.2.3   Other Wire Types

There are the following other Verilog wire types (rarely used in ASIC design) [Verilog LRM 3.7]:

  • wand , wor , triand , and trior model wired logic. Wiring, or dotting, the outputs of two gates generates a logic function (in emitter-coupled logic, ECL, or in an EPROM, for example). This is one area in which the logic values 'z' and 'x' are treated differently.
  • tri0 and tri1 model resistive connections to VSS or VDD.
  • trireg is like a wire but associates some capacitance with the net, so it can model charge storage.

There are also other keywords that may appear in declarations:

  • scalared and vectored are properties of vectors [Verilog LRM 3.3].
  • small , medium , and large model the charge strength of trireg connections [Verilog LRM 7].

11.2.4   Numbers

Constant numbers are integer or real constants [Verilog LRM 2.5]. Integer constants are written as

width'radix value

where width and radix are optional. The radix (or base) indicates the type of number: decimal ( d or D ), hex ( h or H ), octal ( o or O ), or binary ( b or B ). A number may be sized or unsized. The length of an unsized number is implementation dependent. We can use '1' and '0' as numbers since they cannot be identifiers, but we must write 1'bx and 1'bz for 'x' and 'z' . A number may be declared as a parameter [Verilog LRM 3.10]. A parameter assignment belongs inside a module declaration and has local scope [Verilog LRM3.11]. Real constants are written using decimal (100.0) or scientific notation (1e2) and follow IEEE Std 754-1985 for double-precision floating-point numbers. Reals are rounded to the nearest integer, ties (numbers that end in .5) round away from zero [Verilog LRM 3.9], but not all implementations follow this rule (the output from the following code is from VeriWell, which rounds ties toward zero for negative integers).

module constants;
parameter H12_UNSIZED = 'h 12; // Unsized hex 12 = decimal 18.
parameter H12_SIZED = 6'h 12; // Sized hex 12 = decimal 18.
// Note: a space between base and value is OK.
// Note: `' (single apostrophes) are not the same as the ' character.
parameter D42 = 8'B0010_1010; // bin 101010 = dec 42
// OK to use underscores to increase readability.
parameter D123 = 123; // Unsized decimal (the default).
parameter D63 = 8'o 77; // Sized octal, decimal 63.
// parameter ILLEGAL = 1'o9; // No 9's in octal numbers!
// A = 'hx and B = 'ox assume a 32 bit width. 
parameter A = 'h x, B = 'o x, C = 8'b x, D = 'h z, E = 16'h ????; 
// Note the use of ? instead of z, 16'h ???? is the same as 16'h zzzz.
// Also note the automatic extension to a width of 16 bits.
reg [3:0] B0011,Bxxx1,Bzzz1; real R1,R2,R3; integer I1,I3,I_3;
parameter BXZ = 8'b1x0x1z0z;
initial begin 
B0011 = 4'b11; Bxxx1 = 4'bx1; Bzzz1 = 4'bz1; // Left padded.
R1 = 0.1e1; R2 = 2.0; R3 = 30E-01; // Real numbers.
I1 = 1.1; I3 = 2.5; I_3 = -2.5; // IEEE rounds away from 0.
end initial begin #1;

("H12_UNSIZED, H12_SIZED (hex) = %h, %h",H12_UNSIZED, H12_SIZED);
("D42 (bin) = %b",D42," (dec) = %d",D42);
("D123 (hex) = %h",D123," (dec) = %d",D123);
("D63 (oct) = %o",D63);
("A (hex) = %h",A," B (hex) = %h",B);
("C (hex) = %h",C," D (hex) = %h",D," E (hex) = %h",E);
("BXZ (bin) = %b",BXZ," (hex) = %h",BXZ);
("B0011, Bxxx1, Bzzz1 (bin) = %b, %b, %b",B0011,Bxxx1,Bzzz1);
("R1, R2, R3 (e, f, g) = %e, %f, %g", R1, R2, R3);
("I1, I3, I_3 (d) = %d, %d, %d", I1, I3, I_3);
H12_UNSIZED, H12_SIZED (hex) = 00000012, 12
D42 (bin) = 00101010 (dec) =  42
D123 (hex) = 0000007b (dec) =         123
D63 (oct) = 077
A (hex) = xxxxxxxx B (hex) = xxxxxxxx
C (hex) = xx D (hex) = zzzzzzzz E (hex) = zzzz
BXZ (bin) = 1x0x1z0z (hex) = XZ
B0011, Bxxx1, Bzzz1 (bin) = 0011, xxx1, zzz1
R1, R2, R3 (e, f, g) = 1.000000e+00, 2.000000, 3
I1, I3, I_3 (d) =           1,           3,          -2

11.2.5   Negative Numbers

Integer numbers are signed (two's complement) or unsigned. The following example illustrates the handling of negative constants [Verilog LRM 3.2 , 4.1]:

module negative_numbers;
parameter PA = -12, PB = -'d12, PC = -32'd12, PD = -4'd12; 
integer IA , IB , IC , ID ; reg [31:0] RA , RB , RC , RD ;
initial begin #1;
IA = -12; IB = -'d12; IC = -32'd12; ID = -4'd12; 
RA = -12; RB = -'d12; RC = -32'd12; RD = -4'd12; #1;
("     parameter    integer   reg[31:0]");
 ("-12     =",PA,IA,,,RA);
("         ",,,,PA,,,,IA,,,,,RA);
 ("-'d12   =",,PB,IB,,,RB);
("         ",,,,PB,,,,IB,,,,,RB);
 ("-32'd12 =",,PC,IC,,,RC);
("         ",,,,PC,,,,IC,,,,,RC);
 ("-4'd12  =",,,,,,,,,,PD,ID,,,RD);
("         ",,,,,,,,,,,PD,,,,ID,,,,,RD);
           parameter    integer   reg[31:0]
-12     =        -12        -12  4294967284
            fffffff4   fffffff4    fffffff4
-'d12   = 4294967284        -12  4294967284
            fffffff4   fffffff4    fffffff4
-32'd12 = 4294967284        -12  4294967284
            fffffff4   fffffff4    fffffff4
-4'd12  =          4        -12  4294967284
                   4   fffffff4    fffffff4

Verilog only "keeps track" of the sign of a negative constant if it is (1) assigned to an integer or (2) assigned to a parameter without using a base (essentially the same thing). In other cases (even though the bit representations may be identical to the signed number--hexadecimal fffffff4 in the previous example), a negative constant is treated as an unsigned number. Once Verilog "loses" the sign, keeping track of signed numbers becomes your responsibility (see also Section 11.3.1).

11.2.6   Strings

The code listings in this book use Courier font. The ISO/ANSI standard for the ASCII code defines the characters, but not the appearance of the graphic symbol in any particular font. The confusing characters are the quote and accent characters:

module characters; /*
" is ASCII 34 (hex 22), double quote.
' is ASCII 39 (hex 27), tick or apostrophe.
/ is ASCII 47 (hex 2F), forward slash.
\ is ASCII 92 (hex 5C), back slash.
` is ASCII 96 (hex 60), accent grave.
| is ASCII 124 (hex 7C), vertical bar.
There are no standards for the graphic symbols for codes above 128.
´ is 171 (hex AB), accent acute in almost all fonts.
" is 210 (hex D2), open  double quote, like 66 (in some fonts).
" is 211 (hex D3), close double quote, like 99 (in some fonts).
` is 212 (hex D4), open  single quote, like  6 (in some fonts).
' is 213 (hex D5), close single quote, like  9 (in some fonts).
*/ endmodule

Here is an example showing the use of string constants [Verilog LRM 2.6]:

module text;
parameter A_String = "abc"; // string constant, must be on one line
parameter Say = "Say \"Hey!\"";
// use escape quote \" for an embedded quote
parameter Tab = "	"; // tab character
parameter NewLine = "
"; // newline character
parameter BackSlash = "\"; // back slash
parameter Tick = "'"; // ASCII code for tick in octal
// parameter Illegal = "@"; // illegal - no such ASCII code
initial begin("A_String(str) = %s ",A_String," (hex) = %h ",A_String);
("Say = %s ",Say," Say \"Hey!\"");
("NewLine(str) = %s ",NewLine," (hex) = %h ",NewLine);
("\(str) = %s ",BackSlash," (hex) = %h ",BackSlash);
("Tab(str) = %s ",Tab," (hex) = %h ",Tab,"1 newline...");
("Tick(str) = %s ",Tick," (hex) = %h ",Tick);
#1.23; ("Time is %t", );
A_String(str) = abc  (hex) = 616263
Say = Say \"Hey!\"  Say "Hey!"
NewLine(str) = 
  (hex) = 0a
\(str) = \  (hex) = 5c
Tab(str) = 	  (hex) = 09 1 newline...

Tick(str) = '  (hex) = 27 
Time is                    1

Instead of parameters you may use a define directive that is a compiler directive, and not a statement [Verilog LRM 16]. The define directive has global scope:

module define;
define G_BUSWIDTH 32 // Bus width parameter (G_ for global).
/* Note: there is no semicolon at end of a compiler directive. The character ` is ASCII 96 (hex 60), accent grave, it slopes down from left to right. It is not the tick or apostrophe character ' (ASCII 39 or hex 27)*/
wire [`G_BUSWIDTH:0]MyBus; // A 32-bit bus.

Chapter start

Previous page

Next page

DownStream: Solutions for Post Processing PCB Designs
Verific: SystemVerilog & VHDL Parsers

© 2020 Internet Business Systems, Inc.
670 Aberdeen Way, Milpitas, CA 95035
+1 (408) 882-6554 — Contact Us, or visit our other sites:
AECCafe - Architectural Design and Engineering TechJobsCafe - Technical Jobs and Resumes GISCafe - Geographical Information Services  MCADCafe - Mechanical Design and Engineering ShareCG - Share Computer Graphic (CG) Animation, 3D Art and 3D Models
  Privacy PolicyAdvertise