3. Data types

3.1. Introduction

In the Chapter 2, we used the data-types i.e. ‘wire’ and ‘reg’ to define ‘1-bit’ & ‘2-bit’ input and output ports and signals. Also, some operators e.g. ‘and (&)’ and ‘or (|)’ etc. were discussed. In this chapter, some more information is provided on these topics.

3.2. Lexical rules

Verilog is case sensitive language i.e. upper and lower case letters have different meanings. Also, Verilog is free formatting language (i.e. spaces can be added freely), but we use the python like approach to write the codes, as it is clear and readable. Lastly in Verilog, ‘//’ is used for comments; also, multiline comments can written between /* and */.

3.3. Data types

Data types can be divided into two groups as follows,

  • Net group: Net group represents the physical connection between components e.g. wire, wand and wor etc. In the tutorials, we will use only one net data type i.e. ‘wire’, which is sufficient to create all types of designs.
  • Variable group: Variable group represents the storage of values in the design. It is always used for the variables, whose values are assigned inside the ‘always’ block. Also, input port can not be defined as variable group. ‘reg’ and ‘integer’ are the example of variable group, which can be synthesized. We will use only ‘reg’ for designing purpose.

3.4. Logic values

Verilog has four logic values i.e. 0, 1, z and x as shown in Table 3.1,

Table 3.1 Logic values
Logic Description
0 logic ‘0’ or false condition
1 logic ‘1’ or true condition
z high impedance state (used for tri-state buffer)
x don’t care or unknown value

3.5. Number representation

The number can be represented in various format as follows, which are listed in Table 3.2. Note that, ‘reg’ can be replaced with ‘wire’ in the table.

  • Binary Format
reg [1:0] a = 2'b01; //  number =  1; size = 2 bit;
reg [2:0] a = -3'b1; // unsigned number= -1 (in 2's complement form); size = 3 bit;
  • Decimal Format
reg [3:0] a = 3'd1;  // number = 1; size =3 bit;
reg [3:0] a = -3'd1; // unsigned number = -1 (in 2's complement form); size =3 bit;

reg [3:0] a = 1; // unsigned number = 1; size = 4 bit;
reg [3:0] a = -1; // unsigned number = -1; size = 4 bit in 2's complement form;
  • Signed Decimal Form
integer a = 1; // signed number = 1; size = 32 bit;
integer a = -1; // signed number = -1; size = 32 bit in 2's complement form;
  • For hexadecimal and octal representations use ‘h’ and ‘o’ instead of ‘b’ in binary format.
Table 3.2 Number representation
Number Value Comment
reg [1:0] a = 2’b01; 01 b is for binary
reg [1:0] a = 2’b0001_1111; 00011111 _ is ignored
reg [2:0] a = -3’b1; 111 -1 in 2’s complement with 3 bit (unsigned)
reg [3:0] a = 4’d1; 0001 d is for decimal
reg [3:0] a = -4’d1; 1111 -1 in 2’s complement with 4 bit (unsigned)
reg [5:0] a = 6’o12; 001_010 o is for octal
reg [5:0] b = 6’h1f; 0001_1111 h is for hexadecimal
reg [3:0] a = 1; 0001 unsigned format
reg [3:0] a = -1; 1111 -1 in 2’s complement with 4 bit (unsigned)
reg signed [3:0] a = 1; 0001 signed format
reg signed [3:0] a = -1; 1111 -1 in 2’s complement with 4 bit (signed)
integer a = 1; 0000_0000_…_0001 32 bit i.e. 31-zeros and one-1 (signed)
integer a = -1; 1111_1111_…_1111 -1 in 2’s complement with 32 bit i.e. all 1 (signed)
reg [4:0] a = 5’bx xxxxx x is don’t care
reg [4:0] a = 5’bz zzzzz z is high impedance
reg [4:0] a = 5’bx01 xxx01 z is high impedance

Note

  • ‘wire’ and ‘reg’ are in unsigned-format by default. These can be used for synthesis and simulation.
  • ‘integer’ is in signed-format by default. This should be used for simulation.

3.6. Signed numbers

By default, ‘reg’ and ‘wire’ data type are ‘unsigned number, whereas ‘integer’ is signed number. Signed number can be defined for ‘reg’ and ‘wire’ by using ‘signed’ keywords i.e. ‘reg signed’ and ‘wire signed’ respectively as shown in Table 3.2.

Also, ‘signed numbers’ can be converted into ‘unsigned numbers’ using ‘$unsigned()’ keyword e.g. if ‘a = -3 (i.e. 101 in 2’s complement notation)’, then ‘$unsigned(a)’ will be ‘5 (i.e. value of 101)’. Similarly, ‘unsigned numbers’ can be converted into ‘signed numbers’ using ‘signed()’ keyword.

Warning

Although, numbers can be converted from one form to another, but it should be avoided as it may results in errors which are difficult to find.

3.7. Operators

In this section, various synthesizable operators of Verilog are discussed, which are shown in Table 3.3.

Table 3.3 Verilog operators
Type Symbol Description Note
Arithmetic + add  
  - subtract  
  * multiply  
  / divide may not synthesize
  % modulus (remainder) may not synthesize
  ** power may not synthesize
Bitwise ~ not  
  | or  
  & and  
  ^ xor  
  ~& or &~ nand mix two operators
Relational > greater than  
  < less than  
  >= greater than or equal  
  <= less than or equal  
  == equal  
  != not equal  
Logical ! negation  
  || logical OR  
  && logical AND  
Shift operator >> right shift  
  << left shift  
  >>> right shift with MSB shifted to right  
  <<< same as <<  
Concatenation { } Concatenation  
  { { } } Replication “e.g. { 2{3} } = {3 3}”
Conditional ? : conditional e.g. (2>3) ? 1 : 0
Sign-format $unsigned() signed to unsigned conversion $unsigned(-3)
  $signed() unsigned to signed conversion $signed(3)

3.8. Arithmetic operator

Three arithmetic operators i.e. +, -, and * can be synthesized in verilog.

3.8.1. Bitwise operators

Four bitwise operator are available in verilog i.e. ‘&’ (and), ‘|’ (or), ‘ ^ ‘ (xor) and ‘~’ (not). Further, we can combine these operators to define new operators e.g. ‘~&’ or ‘&~’ can be used as ‘nand’ operations etc.

3.8.2. Relational operators

We already see the equality relational operation i.e. ‘==’ in section Section 2.2.4. Further, five relational operators are defined in verilog i.e. ‘>’, ‘>=’, ‘<’, ‘<=’ and ‘!=’(not equal to).

3.8.3. Logical operators

We already see the ‘and’ relational operation i.e. ‘&&’ in section Section 2.2.4. Further, three relational operators are defined in verilog i.e. ‘||’ (or), ‘&&’ and ‘!’(negation).

3.8.4. Shift operators

Verilog provides 4 types of shif operators i.e. >>, <<, >>>, <<<. Let ‘a = 1011-0011’, then we will have following results with these operators,

  • a >>3 = 0001-0110 i.e. shift 3 bits to right and fill the MSB with zeros.
  • a << 3 = 1001-1000 i.e. shift 3 bits to left and fill the LSB with zeros.
  • a >>>3 = 1111-0110 i.e. shift 3 bits to right and fill the MSB with sign bit i.e. original MSB.
  • a <<<3 = 1111-0110 i.e. same as a<<3.

3.8.5. Concatenation and replication operators

Concatenation operation ‘{ }’ is used to combine smaller arrays to create a large array as shown below,

wire[1:0] a = 2b'01;
wire[2:0] b = 3b'001;
wire[3:0] c ;
assign c = {a, b} // c = 01001 is created using a and b;

Replication operator is used to repeat certain bits as shown below,

assign c = { 2{a}, 1'b0 } // c = 01010 i.e. a is repeated two times i.e. 01-01

3.8.6. Conditional operator

Conditional operator (?:) can be defined as follows,

assign c = (a>b) ? a : b; // i.e. c=a if a>b; else c=b;

Also, conditional expression can be cascaded as shown in Listing 3.1, where 4x1 multiplexer is designed. Multiplexer is a combinational circuit which selects one of the many inputs with selection-lines and direct it to output. Fig. 3.1 illustrates the truth table for 4x1 multiplexer. Here ‘i0 - i3’ the input lines, whereas ‘s0’ and ‘s1’ are the selection line. Base on the values of ‘s0’ and ‘s1’, the input is sent to output line, e.g. if s0 and s1 are 0 then i0 will be sent to the output of the multiplexer.

../_images/tableMultiplexer.jpg

Fig. 3.1 Truth table of 4x1 multiplexer

Listing 3.1 Cascaded conditional operator
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// conditionalEx.v

module conditionalEx(
    input wire[1:0] s,
    input wire i0, i1, i2, i3, 
    output wire y
);

assign y = (s == 2'b00) ? i0 : // y = i0 if s=00
            (s == 2'b01) ? i1 : // y = i1 if s=01
            (s == 2'b10) ? i2 : // y = i2 if s=10
            (s == 2'b11) ? i3 : // y = i3 if s=11
            y; // else y = y i.e. no change
endmodule

The design generated in Fig. 3.2 is exactly same as the design generated by ‘if-else statement’ which is discussed in Section 4.7. Therefore, Fig. 3.2 is described and compared with other designs in Section 4.7. Further, Fig. 3.3 shows the output waveform of the multiplexer which is generated by Listing 3.1.

../_images/conditionalEx.jpg

Fig. 3.2 Multiplexer generated by Listing 3.1

../_images/conditionalExWave.jpg

Fig. 3.3 Waveforms of Listing 3.1

3.8.7. Parameter and localparam

Parameter and localparam are used to create reusable codes along with avoiding the ‘hard literals’ from the code as shown in following section.

3.8.8. localparam

‘localparam’ keyword is used to defined the constants in verilog. In Listing 3.2, N is defined in line 8 with value 3. Then this value is used in line 10 and 11. Suppose we want to change the constant value to 4. Now, we need to change it only at one place i.e. line 8 (instead of changing everywhere in the code e.g. line 10 and 11 in this example). In this way, we can remove the hard literals from the codes.

Listing 3.2 Localparam
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// constantEx.v

module constantEx(
    input wire [3:0] a, b, 
    output wire [3:0] z
);

localparam N = 3, M = 2; //localparam

wire [N:0] x;
wire [2**N:0] y;

// use x and y here
assign z = a & b;

endmodule
  • It is better to define the size of the local-parameters otherwise 32-bit signed-format will be used for the local parameters, as shown below
// 32-bit signed-format
localparam N = 3, M = 2;

// N & M are 5 bit and 3 bit unsigned numbers respectively
localparam N = 5'd3, M = 3'd2;

3.8.9. Parameter and defparam

‘localparam’ can not be modified after declaration. But we can define the parameter in the module, which can be modified during component instantiation in structural modeling style as shown below.

Explanation Listing 3.3

In line 5, two parameters are defined i.e. ‘N’ and ‘M’. Then ports ‘a’ and ‘b’ are defined using parameter ‘N’. The always block (lines 13-19) compares ‘a’ and ‘b’ and set the value of ‘z’ to 1 if these inputs are equal, otherwise set ‘z’ to 0.

Listing 3.3 Parameter
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// parameterEx.v

module parameterEx
#(
    parameter N = 2, M = 3  //parameter
)

(
    input wire [N-1:0] a, b, 
    output reg [N-1:0] z
);

always @(a,b)
begin   
    if (a==b)
        z = 1;
    else 
        z = 0;
end
endmodule

Explanation Listing 3.4 and Listing 3.5

In line 5, ‘a’ and ‘b’ are defined as 4-bit vector. Structural modeling is used in Line 9, where parameter mapping and port mapping is performed. Note that, in line 16, ‘.N(5)’ will override the default value of N i.e. N=2 in Listing 3.3. Also, parameter ‘M’ is not mapped, therefore default value of M will be used, which is defined in Listing 3.3. In this way, we can remove ‘hard literals’ from the codes, which enhances the reusability of the designs. Value of the parameter ‘N’ can also be set using ‘defparam’ keyword, as shown in Listing 3.5.

Listing 3.4 Parameter instantiation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// parameterInstantEx.v

module parameterInstantEx
(
    input wire [4:0] a, b, 
    output wire [4:0] z
);

parameterEx #(.N(5)) compare4bit ( .a(a), .b(b), .z(z));

endmodule
Listing 3.5 Parameter instantiation using ‘defparam’
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// parameterInstantEx2.v

module parameterInstantEx2
(
    input wire [4:0] a, b, 
    output wire [4:0] z
);

parameterEx compare4bit ( .a(a), .b(b), .z(z));
    defparam compare4bit.N = 5;  // 'defparam' to set the value of parameter

endmodule
  • It is better to define the size of the parameters otherwise 32-bit signed-format will be used for the parameters, as shown below
// 32-bit signed-format
parameter N = 2, M = 3

// N & M are 5 bit and 4 bit unsigned numbers respectively
parameter N = 5'd2, M = 4'd3;

3.9. Conclusion

In this chapter, we saw various data types and operators. Further Parameters and localparam are shown which can be useful in creating the reusable designs.