Lecture 2:
Data types and Operators in
Verilog
Data type In Verilog
The different types of data type you can work with in
Verilog:
1. Nets (wire)
2. Regs
3. Integers
4. Times
5. Parameters
6. Strings
Nets
Nets (sometimes called wires) are the most common
data types in Verilog.
Nets are used to interconnect modules and primitives.
The default net type is a plain wire with no special
properties.
Net Types
Example: Net Declarations
Wire a,b, c; // Three 1-bit nets.
wire [7:0] d, e, f; // Three 8-bit vectors.
supply1 vcc;
supply0 gnd;
Vectors & their ranges
In Verilog, a wire can be 1 bit wide or much wider. A wire that is more
than 1 bit wide is called a vector in Verilog. Although such a wire is also
known as a bus.
The maximum width of a vector is dependent on the simulator being
used. The IEEE 1364 standard states that a simulator must support at
least 1024-bit wide vectors.
To declare a wire more than one bit wide, a range declaration is used.
Ranges
Ranges specify the most-significant and least-significant indexes of a
vector.
Ranges can be either ascending or descending.
The range [7:0] is an 8-bit range, same as [0:7].
Furthermore, ranges do not need to be zero-based.
The range [682:690] is a 9-bit range.
Regs
Regs are used for modeling in procedural blocks.
The reg data type does not always imply modeling of
a flip-flop, latch, or other form of register.
The reg data type can also be used to model
combinatorial logic.
A register can be 1 bit wide or declared a vector, just
as with nets.
Vector registers can be accessed a bit at a time or a
part at a time.
Example 2: Reg
reg a, b, c; // Three 1-bit registers.
reg [7:0] d, e, f; // Three 8-bit registers.
e[7]; // Refers to the most significant bit of e.
d[3:0] ;// Refers to the four Least significant bits of d
Arrays of registers: Memories
Memories are arrays of registers. A memory
declaration is similar to a reg declaration with the
addition of the range of words in the memory.
The range of words can be ascending or descending, as
with the range of a vector.
When referencing a memory, you can access only the
entire word of memory, not the individual bits.
Example 3: Memory
reg [7:0] a, b[0:15], c[971:960];
//a is an 8-bit register, b is a memory of sixteen
8-bit words, and c is a memory of twelve 8-bit words.
reg d, e[8:13];
//d is a 1-bit register and e is a 1-bit wide memory of
six words.
Integers and Reals
Integers in Verilog are usually 32 bits wide.
Strictly speaking, the number of bits in an integer is
machine-dependent.
Integers are signed and regs are unsigned.
Like integers, reals are 32-bit floating-point values.
Integers and reals are difficult to pass through ports
because in Verilog, ports are always bits or bit vectors.
Time and Realtime
You can declare variables of type time or realtime in
your models for timing checks.
The built in functions $time and $realtime return the
current simulation time.
Verilog uses the time keyword to represent the current
simulation time.
$time is double the size of an integer (usually 64 bits)
and is unsigned.
The $realtime returns a value as a real number. This
values is scaled to `timescale unit.
•`timescale for base unit of measurement and precision of time
Parameters
Parameters are run-time constants that take their size
from their value automatically.
The default size of a parameter is the size of an integer
(32 bits).
For backwards compatibility, you can declare
parameters with ranges to make them bigger or smaller
than their default size.
Parameters may be strings.
Strings
Verilog does not have a unique string data type.
Rather, strings are stored in long registers using 8 bits
(1 byte) to store each character.
When declaring a register to store a string, you must
declare a register of at least eight times the length of
the string.
Constant strings are treated as long numbers in verilog.
Example 6: String
module string1;
reg[8*13 : 1] s;
initial begin
s = "Hello Verilog";
$display("The string %s is stored as %h", s, s);
end
endmodule
Results
The string Hello Verilog is stored as
48656c6c6f20566572696c6f67
Procedural Assignments
The data types reg, integer, real, and time can only be
assigned values in procedural blocks of code. These
assignments are called procedural assignments.
When the statement is executed, the variable on the
left-hand side of the assignment receives a new value.
The destination of a procedural assignment is never a
wire.
The left-hand side of a procedural assignment is a reg.
Types of Procedural Assignment
There are three varieties of the procedural assignment:
1. The Blocking procedural assignment
2. The non-blocking procedural assignment
3. The procedural assignment with an intra-assignment
delay
Blocking procedural assignment
Blocking assignment executes "in series" because a
blocking assignment blocks execution of the next
statement until it completes.
The results of the next statement may depend on the
first one being completed.
The assignment must complete before the next line is
executed.
Example 7:
module Blocking_assign;
integer i, j;
reg [7:0] a, b;
initial begin
i = 3;
j = 4;
a = i + j;
b = a + 1;
#10 i = a;
j = b;
end
endmodule
Non-blocking Assignment
Non-blocking assignment executes in parallel because it
describes assignments that all occur at the same time.
The right hand side is evaluated immediately and assignment to
the left hand side is postponed until other evaluation in the
current time step are completed.
The result of a statement on the 2nd line will not depend on the
results of the statement on the 1st line.
The non-blocking assignment uses a different assignment
operator “<=”.
You can use the non-blocking procedural statement whenever
you want to make several register assignments within the same
time step without regard to order or dependence upon each other.
Example 8:
module nonblocking (clk,a,c);
input clk;
input a;
output c;
wire a, clk;
reg b, c;
always @ (posedge clk )
begin
b <= a;
c <= b;
end
endmodule
Example 9:
1. module block_nonblock();
2. reg a, b, c, d , e, f ;
3. // Blocking assignments
4. initial begin
5. a = #10 1'b1;// The simulator assigns 1 to a at time 10
6. b = #20 1'b0;// The simulator assigns 0 to b at time 30
7. c = #40 1'b1;// The simulator assigns 1 to c at time 70
8. end
9.
10. // Nonblocking assignments
11. initial begin
12. d <= #10 1'b1;// The simulator assigns 1 to d at time 10
13. e <= #20 1'b0;// The simulator assigns 0 to e at time 20
14. f <= #40 1'b1;// The simulator assigns 1 to f at time 40
15. end
16.
17. endmodule
The procedural assignment with an intra-
assignment delay
The intra-assignment delay is a special form of the
procedural assignment with a delay in the middle.
With the delay on the right-hand side of the equal
sign, the right-hand side is evaluated immediately,
but the assignment is delayed.
The operation of a procedural assignment with an
intra-assignment delay is sample the values on the
right hand side, delay, then assign.
Example 10: Intra-assignment Delays
module iaf1 ; module iaf2;
integer i, j; integer i, j;
initial begin initial begin
i =3; i =3;
j =4; j =4;
fork fork
#50i =j; i =#50 j;
#50j =i; j =#50 i;
join join
end end
endmodule endmodule
fork-join without Intra-assignment
Delays fork-join with Intra-assignment Delays
Operators in Verilog
Operators
Operators in Verilog can be divided into several
categories.
One way to categorize the operators is by the number
of operands they take.
Unary operators
Binary operators
Ternary operators
Contd.
Another way to group the operators is by the size of
values they return.
Some operators, when operating on vectors, return a
vector.
Some operators return a single-bit value even if they
are passed vectors.
The operators that return only a single bit are either
reduction or logical operators.
UNARY OPERATORS
The unary operators take only one operand to their
right for input.
It consist of negation operators and reduction operators.
Bitwise operators return a value of the same size as the
operand. Logical operators return only a 1-bit value
Example 1: Bit-wise and Logical
Operators
module uop;
reg [7:0] a, b, c;
initial begin
a=0;
b='bl0100101;
c='b1100xxzz;
$display("Value %b Bitwise '~' %b logical '!' %b",a,~a,!a);
$display ("Value %b Bitwise '~' %b logical '!' %b",b,~b,!b);
$display("Value %b Bitwise '~' %b logical '!' %b",c,~c,!c);
end
endmodule
Example 8-2 Results
Value 00000000 Bitwise '~' 11111111 logical '!' 1
Value 10100101 Bitwise '~' 01011010 logical '!' 0
Value 1100xxzz Bitwise '~' 0011xxxx logical '!' 0
Binary Operators
Most of the operators in Verilog take two operands,
and fall into the category of binary operators.
This includes a set of arithmetic, bit-wise, and logical
operators.
Register data types are used as unsigned values
(Negative numbers are stored in two's complement
form)
Arithmetic Operators:
Binary: +, -, *, /, % (the modulus operator).
Unary: +, - (This is used to specify the sign).
The result of a modulus operation takes the sign of the
first operand.
If any operand bit value is the unknown value x, then
the entire result value is x.
Example 2:
module arithmetic_operators(); Results:
initial begin
5 + 10 = 15
$display (" 5 + 10 = %d", 5 + 10);
5 - 10 = -5
$display (" 5 - 10 = %d", 5 - 10);
$display (" 10 - 5 = %d", 10 - 5); 10 - 5 = 5
$display (" 10 * 5 = %d", 10 * 5); 10 * 5 = 50
$display (" 10 / 5 = %d", 10 / 5); 10 / 5 = 2
$display (" 10 / -5 = %d", 10 / -5);
10 / -5 = -2
$display (" 10 %s 3 = %d","%", 10%3);
10 % 3 = 1
end
endmodule
Equality Operators
The result is a scalar value (example a < b) :
0 if the relation is false (a is bigger then b)
1 if the relation is true ( a is smaller then b)
x if any of the operands has unknown x bits (if a or b
contains X except Literal operators)
Contd.
The === and !== operators are special in that they will
never return x; their output is always 0 or 1.
A rule of thumb for equivalence vs. literal equivalence
operators is based in hardware.
In hardware there is no x, it would be 1 or 0. Therefore
use == and != for synthesizable hardware.
Test benches should test and catch x and z. Test
benches should use === and !==.
// A = 4, B = 3
// X = 4'b1010, Y = 4'b1101
// Z = 4'b1xxz, M = 4'b1xxz, N = 4'b1xxx
A == B // Results in logical 0
X != Y // Results in logical 1
X == Z // Results in x
Z === M // Results in logical 1 (all bits match, including x and z)
Z === N // Results in logical 0 (least significant bit does not match)
M !== N // Results in logical 1
Bitwise Operators
The bit-wise &, and ^ operators typically will be used with
two operands of the same size, and return a value of the
same size.
If one operand is shorter than the other, it will be extended
on the left side with zeroes to match the length of the
longer operand.
The shift operators can end up creating a larger (left shifts)
or smaller (right shifts) result.
All of the shift operators Except signed shift right >>>
zero fill. The signed shift right fills with whatever the
most significant bit of the right left hand operator was.
Contd.
// X = 4'b1100
Y = X >> 1; //Y is 4'b0110. Shift right 1 bit. 0 filled in MSB
position.
110
Y = X << 1; //Y is 4'b1000. Shift left 1 bit. 0
Logical Operators
Logical operators return a one bit result.
The result is a scalar value:
◦ 0 if the relation is false
◦ 1 if the relation is true
◦ x if any of the operands has x (unknown) bits
REDUCTION OPERATORS
Reduction operators are a special case of the bit-wise
operators.
The reduction operators act like unary operators in that
they take only one operand.
The reduction operators act on a multiple-bit operand
and reduce it to a single bit.
Contd.
Ternary Operator
The ternary operator takes three operands and uses the
question mark (?) and colon (:) to indicate the
operation.
A ternary operation is essentially an if-then-else
statement in an expression.
The first operand is logically evaluated.
If it is true, the second operand is returned.
If the first operand is not true, the third operand is
returned.
Concatenations
You can make larger operands with concatenations.
Concatenations are legal both as a result on the left-
hand side of the equals and as operands on the right-
hand side of the equals.
The concatenation is indicated with curly braces {}.
It is illegal to have an unsized number in a
concatenation.
// A = 1'b1, B = 2'b00, C = 2'b10, D = 3'b110
Y = {B , C} // Result Y is 4'b0010
Y = {A , B , C , D , 3'b001} // Result Y is 11'b10010110001
Y = {A , B[0], C[1]} // Result Y is 3'b101
Example 1:
reg [3:0] a, b;
reg [7:0] c, d;
reg [11:0] e, f;
c = {a,b}; // The most significant bit of c is the most
significant bit of a.
e = {b,a,b};
f = {a,d}; // 4 bits + 8 bits = 12 bits.
Replication Operator
Repetitive concatenation of the same number can be expressed by using a
replication constant. A replication constant specifies how many times to
replicate the number inside the brackets ( { } ).
reg A;
reg [1:0] B, C;
reg [2:0] D;
A = 1'b1; B = 2'b00; C = 2'b10; D = 3'b110;
Y = { 4{A} } // Result Y is 4'b1111
Y = { 4{A} , 2{B} } // Result Y is 8'b11110000
Y = { 4{A} , 2{B} , C } // Result Y is 8'b1111000010
Signed Operations
Nets, regs, and times in Verilog are unsigned; only
integer and real types are signed by default.
The signed keyword is used to represent signed
declarations.
Signed values use 2's complement format.
Example 2:
module signunsign(a, b, c, d);
input [7:0] a; // unsigned
input signed [7:0] b; // signed
output [7:0] c; // unsigned
output signed [7:0] d; //signed
wire signed [7:0] e; // signed.
reg signed [7:0] f; // signed.
reg [7:0] g; // unsigned
endmodule
Case Statement
The keyword are case, endcase, default.
Syntax:
Case(expression)
label 01:statement_01;
label 02:statement_02;
label 03:statement_03;
….
…..
default:default_statement;
endcase
Nand Gate using the Case Statement
module nand_case(a,b,c);
input a,b;
output c;
reg c;
always@(a or b)
Begin
Case ({a, b})
2’b00: begin
c=1’b1;
end
2’b01: begin
c=1’b1;
end
2’b10: begin
c=1’b1;
end
2’b11: begin
c=1’b0;
end
endcase
End
endmodule