The primary intent of data-types in the Verilog language is to represent data storage elements like bits in a flip-flop and transmission elements like wires that connect between logic gates and sequential structures. Almost all data-types can only have one of the four different values as given below except for
event data types.
|0||represents a logic zero, or a false condition|
|1||represents a logic one, or a true condition|
|x||represents an unknown logic value (can be zero or one)|
|z||represents a high-impedance state|
What does the verilog value-set imply ?
Since Verilog is essentially used to describe hardware elements like flip-flops and combinational logic like NAND and NOR, it has to model the value system found in hardware. A logic one would represent the voltage supply Vdd which can range anywhere between 0.8V to more than 3V based on the technology node the digital circuit will be built. A logic zero would represent ground and hence a value of 0V.
x means that the value is simply unknown at the time, and could be either 0 or 1. This is quite different from the way
X is treated in boolean logic, where it means "don't care".
As with any incomplete electric circuit, the wire that is not connected to anything will have a high-impedance at that node and is represented by
z. Even in verilog, any unconnected wire will result in a high impedance.
Watch a quick video !
Nets and Variables
Nets and variables are the two main groups of data types which represent different hardware structures and differ in the way they are assigned and retain values. Nets are used to connect between hardware entities like logic gates and hence do not store any value (except for
trireg) like shown in the image below. A net is used to connect between a NAND gate and a flip-flop. In a similar way, the NAND inputs and other flip flop pins are wired to other components via other nets. A variable is an abstraction of a data storage element and can hold values. A flip-flop is a good example of a storage element.
There are different types of nets each with different characteristics as shown in the table, but the most popular and widely used net in digital designs is the
wire. It is used to connect elements and for nets that are driven by a single gate or continuous assignment. The
tri net type can be used where multiple drivers drive a net. It is illegal to redeclare a name already declared by a net, parameter or variable.
module design; wire abc; wire abc; // Error: Identifier "abc" previously declared reg abc; // Error: Identifier "abc" previously declared endmodule
Now we'll take a look at the different types of variables supported in Verilog.
reg can be used to model hardware registers since it can hold values between assignments. Note that a
reg need not represent a hardware storage element because it can also be used to represent combinational logic.
Other data-types : integer, real
integer is a general purpose variable of 32-bits wide that can be used for other purposes while modeling hardware and stores integer values. A
time variable is unsigned, 64-bits wide and can be used to store simulation time quantities for debugging purposes. A
real variable can store floating point values and can be assigned the same way as
realtime variable simply stores time as a floating point quantity.
integer count; // Count is an integer value > 0 time end_time; // end_time can be stored a time value like 50ns real float; // float = 12.344 - can store floating numbers realtime rtime; // rtime = 40.25ps
Scalars and Vectors
A net or
reg declaration without a range specification is considered 1-bit wide and is a scalar. If a range is specified, then the net or
reg becomes a multibit entity known as a vector.
wire o_nor; // single bit scalar net wire [7:0] o_flop; // 8-bit vector net reg parity; // single bit scalar variable reg [31:0] addr; // 32 bit vector variable to store address
The range gives the ability to address individual bits in a vector. The most significant bit of the vector should be specified as the left hand value in the range while the least significant bit of the vector should be specified on the right.
wire [msb:lsb] name; integer my_msb; wire [15:0] priority; // msb = 15, lsb = 0 wire [my_msb: 2] prior; // illegal
A 16 bit wide net called priority will be created in the example above. Note that the msb and lsb should be a constant expression and cannot be substituted by a variable. But they can be any integer value - positive, negative or zero; and the lsb value can be greater than, equal to or less than msb value.
Any bit in a vectored variable can be individually selected and assigned a new value as shown below. This is called as a bit-select. If the bit-select is out of bounds or the bit-select is x or z, then the value returned will be x.
reg [7:0] addr; // 8-bit reg variable [7, 6, 5, 4, 3, 2, 1, 0] addr  = 1; // assign 1 to bit 0 of addr addr  = 0; // assign 0 to bit 3 of addr addr  = 1; // illegal : bit8 does not exist in addr
A range of contiguous bits can be selected and is known as a part-select. There are two types of part-selects, one with a constant part-select and another with an indexed part-select.
reg [31:0] addr; addr [23:16] = 8'h23; // bits 23 to 16 will be replaced by the new value 'h23 -> constant part-select
Having a variable part-select allows it to be used effectively in loops to select parts of the vector. Although the starting bit can be varied, the width has to be constant.
[<start_bit> +: <width>] // part-select increments from start-bit [<start_bit> -: <width>] // part-select decrements from start-bit
module des; reg [31:0] data; int i; initial begin data = 32'hFACE_CAFE; for (i = 0; i < 4; i++) begin $display ("data[8*%0d +: 8] = 0x%0h", i, data[8*i +: 8]); end $display ("data[7:0] = 0x%0h", data[7:0]); $display ("data[15:8] = 0x%0h", data[15:8]); $display ("data[23:16] = 0x%0h", data[23:16]); $display ("data[31:24] = 0x%0h", data[31:24]); end endmoduleSimulation Log
ncsim> run data[8*0 +: 8] = 0xfe // ~ data [8*0+8 : 8*0] data[8*1 +: 8] = 0xca // ~ data [8*1+8 : 8*1] data[8*2 +: 8] = 0xce // ~ data [8*2+8 : 8*2] data[8*3 +: 8] = 0xfa // ~ data [8*3+8 : 8*3] data[7:0] = 0xfe data[15:8] = 0xca data[23:16] = 0xce data[31:24] = 0xfa ncsim: *W,RNQUIE: Simulation is complete.
module tb; reg [15:0] data; initial begin $display ("data[0:9] = 0x%0h", data[0:9]); // Error : Reversed part-select index expression ordering end endmodule