The 2 most commonly used data types in Verilog are net (wire) and register (reg). The other types can be understood as extensions or auxiliary versions of these two data types.

[3:0] = 4'hF, where the width can be omitted;

The wire type represents physical connections between hardware units, continuously driven by the output terminals of the devices connected to it. If no driving element is connected to a wire variable, the default value is generally "Z". An example is as follows:

Example

wire   interrupt ;
wire   flag1, flag2 ;
wire   gnd = 1'b0 ;  

There are other net data types, including wand, wor, wri, triand, trior, trireg, etc. These data types are not used very frequently, so they are not introduced here.

Register (reg)

Register (reg) is used to represent storage elements. It retains the original value of data until it is rewritten. An example declaration is as follows:

Example

reg    clk_temp;
reg    flag1, flag2 ;

For example, in an always block, a register may be synthesized into an edge-triggered flip-flop, and in combinational logic it may be synthesized into a wire-type variable. Registers do not require a driving source and do not necessarily need a clock signal. During simulation, the value of a register can be changed at any time through assignment operations. For example:

Example

reg rstn ;
initial begin
    rstn = 1'b0 ;
    #100 ;
    rstn = 1'b1 ;
end

Vector

When the bit width is greater than 1, wire or reg can be declared in vector form. For example:

Example

reg [3:0]      counter ;    //Declare a 4-bit wide register counter
wire [32-1:0]  gpio_data;   //Declare a 32-bit wide wire variable gpio_data
wire [8:2]     addr ;       //Declare a 7-bit wide wire variable addr, with bit width range 8:2
reg [0:31]     data ;       //Declare a 32-bit wide register variable data, with the most significant bit being 0

For the vectors above, we can specify a particular bit or several adjacent bits for use in other logic. For example:

Example

wire [9:0]     data_low = data[0:9] ;
addr_temp[3:2] = addr[8:7] + 1'b1 ;

Verilog supports variable vector part-select. For example:

Example

reg [31:0]     data1 ;
reg [7:0]      byte1 [3:0];
integer j ;
always@* begin
    for (j=0; j<=3;j=j+1) begin
        byte1[j] = data1[(j+1)*8-1 : j*8];
        //Assign data1[7:0]…data1[31:24] to byte1
    end
end

Verilog also supports fixed-width vector part-select access after specifying a bit position.

  • [bit+: width]+: Increment from the starting bit position, with a bit width of width.
  • [bit-: width]-: Decrement from the starting bit position, with a bit width of width.

Example

//The following 2 assignments are equivalent
A = data1[31-: 8] ;
A = data1[31:24] ;

//The following 2 assignments are equivalent
B = data1[0+ : 8] ;
B = data1[0:7] ;

When recombining signals into a new vector, braces are required. For example:

Example

wire [31:0]    temp1, temp2 ;
assign temp1 = {byte1[0][7:0], data1[31:8]};  //Data concatenation
assign temp2 = {32{1'b0}};  //Assign a 32-bit value 0

Integer, Real, and Time Register Variables

Data types such as integer, real, and time actually also belong to the register type.

Integer

The integer type is declared with the keyword integer. There is no need to specify the bit width when declaring; the bit width depends on the compiler and is generally 32 bits. reg variables are unsigned, while integer variables are signed. For example:

Example

reg [31:0]      data1 ;
reg [7:0]       byte1 [3:0]; //Array variable, introduced later
integer j ;  //Integer variable, used to assist in generating digital circuits
always@* begin
    for (j=0; j<=3;j=j+1) begin
        byte1[j] = data1[(j+1)*8-1 : j*8];
        //Assign data1[7:0]…data1[31:24] to byte1
        end
end

In this example, the integer signal j is used as an auxiliary signal to assign the data of data1 to the array byte1 in sequence. After synthesis, the signal j does not actually exist in the circuit; j only assists in generating the corresponding hardware circuit.

Real

Real numbers are declared with the keyword real and can be expressed in decimal or scientific notation. Real declarations cannot have a range, and the default value is 0. If a real number is assigned to an integer, only the integer part of the real number is assigned to the integer. For example:

Example

real        data1 ;
integer     temp ;
initial begin
    data1 = 2e3 ;
    data1 = 3.75 ;
end
 
initial begin
    temp = data1 ; //The value of temp is 3
end

Time

Verilog uses a special time register variable of type time to store simulation time. Its width is generally 64 bits. The current simulation time is obtained by calling the system function $time. For example:

Example

time       current_time ;
initial begin
       #100 ;
       current_time = $time ; //The value of current_time is 100
end

Array

In Verilog, arrays of reg, wire, integer, time, real, and their vector types are allowed.

There is no limit on the number of array dimensions. Net arrays can also be used to connect ports of instantiated modules. Each element in an array can be used as a scalar or a vector in the same way, in the form of:<array_name>[<index>]. For multi-dimensional arrays, the user needs to specify the index for each dimension. For example:

Example

integer          flag [7:0] ; //An array consisting of 8 integers
reg  [3:0]       counter [3:0] ; //An array consisting of 4 4-bit counters
wire [7:0]       addr_bus [3:0] ; //An array consisting of 4 8-bit wire variables
wire             data_bit[7:0][5:0] ; //Declare a two-dimensional array of 1-bit wire variables
reg [31:0]       data_4d[11:0][3:0][3:0][255:0] ; //Declare a 4-dimensional array of 32-bit data variables

The following shows assignment operations to array elements:

Example

flag [1]   = 32'd0 ; //Assign the second element of the flag array a 32-bit value of 0
counter[3] = 4'hF ;  //Assign the value of the 4th element in the array counter to a 4-bit hexadecimal number F, equivalent to counter
assign addr_bus[0]        = 8'b0 ; //Assign the value of the first element in the array addr_bus to 0
assign data_bit[0][1]     = 1'b1;  //Assign the element in row 1, column 2 of the array data_bit to 1. Here the second access index cannot be omitted; that is, assign data_bit
data_4d[0][0][0][0][15:0] = 15'd3 ;  //Assign bits 15~0 of the register element labeled

Although arrays and vectors are accessed in a somewhat similar way, do not confuse vectors with arrays. A vector is a single element with a bit width of n; an array is composed of multiple elements, each with a bit width of n or 1. They differ in their structural definition.

Memory

A memory variable is a type of register array that can be used to describe the behavior of RAM or ROM. For example:

Example

reg               membit[0:255] ;  //256-bit 1-bit memory
reg  [7:0]        mem[0:1023] ;    //1Kbyte memory with an 8-bit width
mem[511] = 8'b0 ;                  //Set the value of the 512th 8-bit memory cell to 0

Parameter

Parameters are used to represent constants, declared with the keyword parameter, and can only be assigned once. For example:

Example

parameter      data_width = 10'd32 ;
parameter      i=1, j=2, k=3 ;
parameter      mem_size = data_width * 10 ;

However, the value of a parameter in a module can be changed through instantiation. This will be introduced later.

Local parameters are declared with localparam. Their function and usage are the same as parameter, except that their value cannot be changed. Therefore, when a parameter is only used within the current module, localparam can be used to declare it.

String

Strings are stored in variables of type reg, with each character occupying one byte (8 bits). Therefore, the width of the register variable should be large enough to prevent overflow.

Strings cannot be written across multiple lines; that is, a string cannot contain carriage return characters. If the width of the register variable is greater than the size of the string, 0s are used to fill the remaining bits on the left; if the width of the register variable is less than the size of the string, the excess data on the left of the string is truncated. For example, to store the string "run.example.com", 14*8 bits of storage are required:

Example

reg [0: 14*8-1]       str ;
initial begin
    str = "run.example.com";
end  

Some special characters have special meanings in display strings, such as newline, tab, etc. If you need to display these special characters in a string, you need to prefix them with an escape character\. For example, as shown in the following table:

Escape characterDisplayed character
\nNewline
\tTab
%%%
\\
\""
\ooo1 to 3 octal digit characters

Actually, in SystemVerilog (a programming language mainly used for Verilog simulation), the keyword string can already be used directly to represent the string variable type, which brings great convenience to Verilog simulation. Interested scholars can briefly learn SystemVerilog.