Programmable Logic/Verilog Data Types
Verilog has four values any signal can take:
|0||A binary value of 0. Corresponds to zero volts.|
|1||A binary value of 1. Depending on the underlying fabrication technology, may correspond to +5V, +3.3V, or some other positive value.|
|x||A value of "don't care". x values are neither a 0 nor a 1, and should be treated as unknown values.|
|z||A high-impedance value from a tri-state buffer when the control signal is not asserted. Corresponds to a wire that is not connected, or is "floating".|
In practice, x and z values are difficult to use in synthesis, and should typically be avoided, unless there is a very specific reason for using them.
Wires, specified with the wire keyword represent physical wires that carry electrical signals from one module to the next. Wires do not store any data, and they must be constantly supplied with a value or they will not contain a value. Wires may not be the target of a blocking or sequential assignment.
Wires come in one of three varieties:
|wire||These wires carry simple data from one port to another.|
|wor||These wires are a logical OR of all input data values applied to the wire. These synthesize to OR gates with multiple input ports.|
|wand||These wires are a logical AND of all input data values applied to the wire. These synthesize to AND gates with multiple input ports.|
Wires can be assigned a value using the assign keyword. All assign declarations are considered to be running concurrently and continuously.
In the following case, the value of a is dependant on the values of b and c. Any change in either b or c will result in an automatic and instantaneous change in the value of a.
wire a, b, c; assign a = b & c;
Circular assignments cannot be made using the assign keyword, as this produces a continuous loop. In the following example, the value of a is undefined, because it depends on itself passed through combinational (i.e. asynchronous, continuously operating) logic.
wire a, b; assign a = a | b;
For the wand and wor data types, all assignments to that wire are considered to be ports to logic gates. For instance, the following code:
wire a, b, c; wor x; assign x = a; assign x = b; assign x = c;
Is equivalent to this code:
wire a, b, c, x assign x = (a | b | c);
While it may seem like more work to use wor or wand, they can greatly simplify some complicated logic operations, and they can help to improve the readability of the code.
A register, denoted with the keyword reg is a memory storage location. Registers store values without needing constant assignment, but they must be manually updated with a blocking or sequential assignment. Register values are all treated as being unsigned values, and any extension of a value into a larger register will not result in logical sign extension.
Registers can be used with the "=" and "<=" assignment operators:
reg a, b; wire w, x, y, z; a = w + x; b <= y + z;
Assignments with the "=" operator are blocking assignments, and they will be performed sequentially. Assignments with the "<=" operator are non-blocking. All non-blocking assignments in a particular code block will begin at the same time. The block will not terminate until all the non-blocking assignments have completed.
Integer values, specified with the integer keyword are similar in function to registers, except that they are treated implicitly as signed numbers. Integer values will be logically sign-extended on assignment.
A real number can be specified in one of the following two forms.
- decimal notation:examples of numbers in this form are: 2.0, 5.678, 1154.76, 0.1
- scientific notation: examples of numbers in this form are:
23_5.1e2 23510.0 (underscores are ignored) 3.6e2 360.0 (e and E are the same) 5E-4 0.0005
Register and wire types can be specified as multi-bit buses. This assignment is made in the variable declaration using the  operator. As an example:
wire [5:0] a;
This declares wire a to be a bus of 6 wires, with bit 5 (a) being the MSB, and bit 0 (a) being the LSB. The bit number of the LSB must be lower than the bit number for the MSB, but it needs not be zero.
The individual wires or registers in a bus can be interfaced with directly, and subsets of the bus can be manipulated. Given the following declaration:
wire [15:0] a;
The following code will set a value to bit 14 of the bus:
assign a = 1'b1;
And the following code will assign a value to the the lower 8 bits of the bus:
assign a[7:0] = 8'b01101101;
Likewise, we can read from only part of a bus. The following code assigns the 8-bit bus b to be the upper 8 bits of the 16-bit bus a:
wire [15:0] a; wire [7:0] b; assign b[7:0] = a[15:8];
Part-select operators let the compiler calculate the range based on a starting point and a data-width size;
wire [15:0] a; wire [7:0] b; assign b[7:0] = a[15:8]; assign b[7:0] = a[8+:8]; // equivalent assign b[7:0] = a[15-:8]; // equivalent