Introduction to Verilog
Outline
Array Instantiation
Behavioral Modeling
Verilog Operators
Behavioral Description of an Adder
Always block
Procedural Assignment
If Statements
Case Statements
Comparator, Arithmetic & Logic Unit
Multiplexor, Encoder, Priority Encoder, Decoder
Full Adder Module (Gate-Level Description)
module Full_Adder(input A, B, Cin, output Cout, Sum);
wire w1, w2, w3;
and (w1, A, B);
xor (w2, A, B);
and (w3, w2, Cin);
xor (Sum, w2, Cin);
or (cout, w1, w3);
endmodule
Modeling 4-bit Adder using Module
Instantiation
module Adder_4 (input [3:0] A, B, input Cin,
output [3:0] Sum, output Cout);
wire [4:0] C; // carry bits
assign C[0] = Cin; // carry input
assign Cout = C[4]; // carry output
Full_Adder FA0 (A[0], B[0], C[0], C[1], Sum[0]);
Full_Adder FA1 (A[1], B[1], C[1], C[2], Sum[1]);
Full_Adder FA2 (A[2], B[2], C[2], C[3], Sum[2]);
Full_Adder FA3 (A[3], B[3], C[3], C[4], Sum[3]);
endmodule
Modeling 4-bit Adder using Array
Instantiation
module Adder_4 (input [3:0] A, B, input Cin,
output [3:0] Sum, output Cout);
wire [4:0] C; // carry bits
assign C[0] = Cin; // carry input
assign Cout = C[4]; // carry output
Full_Adder FA [3:0] (A[3:0], B[3:0], C[3:0], C[4:1],
Sum[3:0]);
endmodule
Array Instantiation of identical modules by a single statement
Modeling 4-bit Adder using Assign
module Adder_4b (input [3:0] A, B, input Cin,
output [3:0] Sum, output Cout);
wire [4:0] C; // carry bits
assign C[0] = Cin; // carry input
assign Cout = C[4]; // carry output
assign Sum[3:0] = (A[3:0] ^ B[3:0]) ^ C[3:0];
assign C[4:1] = (A[3:0] & B[3:0]) |
(A[3:0] ^ B[3:0]) & C[3:0];
endmodule
Behavioral Modeling
Behavioral modeling describes the functionality of a
design
What the design will do
Not how the design will be built in hardware
Behavioral models specify the input-output model of a
logic circuit and suppress details about its low level
internal structure.
Behavioral modeling encourages designers to
Rapidly create a behavioral prototype of a design
Verify its functionality
Use synthesis tool to optimize and map design into a given
technology
Data Types for Behavioral Modeling
All variables in Verilog have a predefined type.
There are two families of data types: nets and registers.
Net variables act like wires in physical circuit and
establish connectivity between design objects.
Register variables act like variables in ordinary
procedural languages – they store information while the
program executes.
Register types include: reg, integer, real, realtime, time.
A wire and a reg have a default size of 1 bit.
Size of integer is the size of word length in a computer,
at least 32.
Integer Numbers in Verilog
constant numbers can be specified in decimal,
hexadecimal, octal, or binary format
integer numbers can be specified as:
Syntax: <size>'<radix><value> (size is in number of bits)
Sized or unsized numbers (Unsized size is 32 bits)
In a radix of binary, octal, decimal, or hexadecimal
Radix and hex digits (a,b,c,d,e,f) are case insensitive
Spaces are allowed between the size, radix and value
The character (_) is legal anywhere in a number except as the
first character (e.g. 12'b1011_1100_0010, 'hA8, 8'd15)
When <size> is smaller than <value>, then left-most bits of
<value> are truncated
Verilog Operators
{} concatenation ~ bit-wise NOT
+ - * / ** arithmetic & bit-wise AND
% modulus | bit-wise OR
^ bit-wise XOR
> >= < <= relational
^~ ~^ bit-wise XNOR
! logical NOT
& reduction AND
&& logical AND
| reduction OR
|| logical OR
~& reduction NAND
== logical equality
~| reduction NOR
!= logical inequality ^ reduction XOR
=== case equality ~^ ^~ reduction XNOR
!== case inequality << shift left
?: conditional >> shift right
Verilog Operators
Arithmetic Operators:
Each operator takes two operands. + and – could also take a
single operand
During synthesis, the + and - operators infer an adder and a
subtractor
Xilinx XST software can infer a block multiplier during synthesis for
the multiplication operator
/, %, and ** operators usually cannot be synthesized automatically
Shift operators: Four shift operators
>>, << logical shift right and left (0s inserted from the right or the
left)
>>>, <<< arithmetic shift right and left (sign bits are shifted in for
the >>> operation and 0's are shifted in for the <<< operation)
Verilog Operators
If both operands of a shift operator are signals, as in a << b, the
operator infers a barrel shifter, a fairly complex circuit
If the shifted amount is fixed, as in a << 2, the operation infers
no logic and involves only routing of the input signals (can also
be done with {} operator)
Examples of shift operations:
Verilog Operators
Relational and equality operators:
Compare two operands and return a 1-bit logical (Boolean)
value: either 0 or 1
4 relational operators: >, <, <=, and >=
Equality operators: ==, ! =,
The relational operators and the == and ! = operators infer
comparators during synthesis
Verilog Operators
Bitwise operators:
4 basic bitwise operators: & (and), I (or), ^ (xor), and ~ (not)
The first three operators require two operands
Negation and xor operation can be combined, as in ~^ or ^~ to
form the xnor
operations are performed on a bit-by-bit basis
Ex.: let a, b, and c be 4-bit signals: i.e. wire [3:0] a, b, c;
The statement: assign c = a I b ;
is the same as: assign c[3] = a[3] I b[3];
assign c[2] = a[2] I b[2];
assign c[1] = a[1] I b[1];
assign c[0] = a[0] I b[0];
Verilog Operators
Reduction operators: &, I, and ^ operators may have
only one operand and then are known as reduction
operators.
The single operand usually has an array data type.
The designated operation is performed on all elements of the
array and returns a I-bit result.
For example, let a be a 4-bit signal and y be a 1-bit signal:
wire [3:0] a; wire y ;
The statement: assign y = I a ; // only one
operand
is the same as: assign y = a[3] | a[2] | a[1] |
a[0] ;
Verilog Operators
Logical operators: && (logical and), II (logical or), and !
(logical negate)
Operands of a logical operator are interpreted as false (when all
bits are 0's) or true (when at least one bit is 1), and the
operation always returns a 1-bit result
Usually used as logical connectives of Boolean expressions
Bitwise and logical operators can be used interchangeably in
some situations.
Examples of bitwise and logical operations
Verilog Operators
Conditional operator: ? : takes three operands and its
general format is
[signal] = [boolean-exp] ? [true-exp] : [false-exp];
The [boolean-expl] is a Boolean expression that returns true (1)
or false ( 0).
Ex.: assign max = (a>b) ? a : b; //max will get the maximum of
the signals a and b
The operator can be thought of as a simplified if-then-else
statement.
Can be cascaded or nested
Verilog Operators
Concatenation operator: { }
{ } combines segments of elements and small arrays to
form a large array:
wire [7:0] a, ror, srl, sra;
assign ror = {a[2:0], a[7:3]} ; // Rotate a to right 3 bits
assign srl = {3'b000, a[7:3]} ; // shift a to right 3 bits and
insert 0s (logical shift)
assign sra = {a[7] , a[7] , a[7] , a[7:3]} ; // arithmetic shift
a to right 3 bits
Behavioral Description of an Adder
module adder #(parameter width = 4)
4-bit
(output cout, output [width-1:0] sum, operands,
5-bit result
input [width-1:0] a, b, input cin);
assign {cout, sum} = a + b + cin;
endmodule
{ Cout, S } is a 5 bit bus:
Cout S[3] S[2] S[1] S[0]
To pass parameter:
• adder #(32) M1 (Cout, Sum, A, B, Cin);
Procedural Blocks
There are two types of procedural blocks in Verilog
1. The initial block
Executes the enclosed statement(s) one time only
2. The always block
Executes the enclosed statement(s) repeatedly until
simulation terminates
The body of the initial and always blocks is procedural
Can enclose one or more procedural statements
Procedural statements are surrounded by begin … end
1. Multiple procedural blocks can appear in any order inside a
module and run in parallel inside the simulator
Always Block
always blocks are procedural blocks that contain sequential
statements.
Syntax
always @(sensitivity list) begin
end
sensitivity list prevents the always block from executing again
until another change occurs on a signal in the sensitivity list.
Level type
always @(a or b or c) OR always @(a, b, c)
Edge type
always @(posedge clock)
always @(negedge clock)
Sensitivity List for Combinational Logic
For combinational logic, the sensitivity list must include:
ALL the signals that are read inside the always block
Example: A, B, and sel must be in the sensitivity list below:
always @(A, B, sel) begin A, B, and sel are
if (sel == 0) Z = A; read inside the
else Z = B; always block
end
Combinational logic can also use: @(*) or @*
@(*) is automatically sensitive to all the signals that are read
inside the always block
Procedural Assignment
Assignments inside an always or initial block are called
procedural assignments
Can only be used within an always or initial block
Two types: blocking assignment and non-blocking
assignment. Basic syntax :
[variable-name] = [expression] ; // blocking assignment
[variable-name] <= [expression] ; // non-blocking assignment
In a blocking assignment, the expression is evaluated
and then assigned to the variable immediately, before
execution of the next statement (the assignment thus
"blocks" the execution of other statements). It behaves
like the normal variable assignment in the C language.
Procedural Assignment
In a non-blocking assignment, the evaluated expression
is assigned at the end of the always block (the
assignment thus does not block the execution of other
statements).
The basic rule of thumb is:
Use blocking assignments for a combinational circuit.
Use non-blocking assignments for a sequential circuit
There are two types of variables in Verilog:
wire (all outputs of assign statements must be wire)
reg (all outputs modified in always blocks must be reg)
if-else and case statement are only in procedural blocks.
If Statement
The if statement is procedural
Can only be used inside a procedural block
Syntax:
if (expression) statement
[ else statement ]
The else part is optional
A statement can be simple or compound
A compound statement is surrounded by begin ... end
if statements can be nested
Can be nested under if or under else part
If Statement
if (expression) module ALU #(parameter n=8)
begin (output reg [n-1:0] c, input [1:0] s,
input [n-1:0] a, b);
...procedural statements...
end always @(s, a, b) // begin
else if (expression) if (s==2'b00)
begin c = a + b;
...statements... else if (s==2'b01)
c = a - b;
end
else if (s==2'b10)
...more else if blocks c = a & b;
else else
begin c = a | b;
...statements... // end
endmodule
end
Case Statement
The case statement is procedural (used inside always block)
Syntax:
case (expression)
case_item1: statement
case_item2: statement
. . .
default: statement
endcase
The default case is required if not all case values are listed
A statement can be simple or compound
A compound statement is surrounded by begin ... end
Case Statement
case (expression)
case_choice1:
module ALU2 #(parameter n=8)
begin
(output reg [n-1:0] c, input [1:0] s,
...statements...
input [n-1:0] a, b);
end
case_choice2: always @(s, a, b) // begin
begin case (s)
...statements... 2'b00: c = a + b;
end 2'b01: c = a - b;
...more case choices blocks... 2'b10: c = a & b;
default: c = a | b;
default:
endcase
begin
// end
...statements... endmodule
end
endcase
Modeling a Magnitude Comparator
module Comparator #(parameter n=32)
(input [n-1:0] A, B,
output GT, EQ, LT);
// A and B are n-bit input vectors (unsigned)
// GT, EQ, and LT are 1-bit outputs
assign GT = (A > B);
assign EQ = (A == B); A[n–1:0] GT
n-bit
n
assign LT = (A < B); Magnitude EQ
B[n–1:0]
endmodule n Comparator LT
Modeling a Magnitude Comparator
module Comparator #(parameter n=32)
(input [n-1:0] A, B,
output reg GT, EQ, LT);
always @(A, B) begin
GT = 0; EQ = 0; LT = 0;
if (A == B) EQ = 1;
else if (A > B) GT = 1;
else LT = 1;
GT
end A[n–1:0] n-bit
n
endmodule Magnitude EQ
B[n–1:0]
n Comparator LT
Arithmetic Unit
module arithmetic #(parameter width=8)
(input [width-1:0] A, B, input [1:0] Sel, output reg [width-1:0] Y, output reg
Cout);
always @(A, B, Sel) // begin
case (Sel)
2'b 00 : {Cout,Y} = A+B;
2'b 01 : {Cout,Y} = A-B;
2'b 10 : {Cout,Y} = A+1;
2'b 11 : {Cout,Y} = A-1;
default: begin Cout=0; Y=0; end
endcase
// end
endmodule
Logic Unit
module logic #(parameter width=4)
(input [width-1:0] A, B, input [2:0] Sel, output reg [width-1:0] Y);
always @(A, B, Sel) begin
case (Sel)
3'b 000 : Y = A & B; // A and B
3'b 001 : Y = A | B; // A or B
3'b 010 : Y = A ^ B; // A xor B
3'b 011 : Y = ~A; // 1’s complement of A
3'b 100 : Y = ~(A & B); // A nand B
3'b 101 : Y = ~(A | B); // A nor B
default : Y = 0;
endcase
end
endmodule
2x1 Multiplexer
Method 1 Method 3
module mux2x1 (input b, c, select, module mux2x1 (input b, c, select,
output a); output reg a);
assign a = (select ? b : c); always@(select, b, c) //begin
endmodule case (select)
1’b1: a=b;
Method 2 1’b0: a=c;
module mux2x1 (input b, c, select, endcase
output reg a); //end
always@(select , b, c) //begin endmodule
if (select) a=b;
else a=c;
//end
endmodule
4x1 Multiplexer
// Parametric 4x1 Mux, default value for n = 1
module Mux4 #(parameter n = 1)
( input [n-1:0] A, B, C, D, n
input [1:0] sel, A 0
n
output [n-1:0] Z );
B 1 n
// sel is a 2-bit vector n Z
C 2
// Nested conditional operators
n
assign Z = (sel[1] == 0) ? D 3
((sel[0] == 0) ? A : B) : 2
((sel[0] == 0) ? C : D);
sel
endmodule
4x1 Multiplexer
module Mux4 #(parameter n = 1)
( input [n-1:0] A, B, C, D,
input [1:0] sel, n
output reg [n-1:0] Z ); A 0
n
always @(A, B, C, D, sel)
B 1 n
Case (sel) Z
n
2’b00: Z = A; C 2
2’b01: Z = B; n
D 3
2’b10: Z = C;
2’b11: Z = D; 2
endcase sel
endmodule
Modeling a 3x8 Decoder
module Decoder3x8 (input [2:0] A, output reg [7:0] D);
// Sensitivity list = @(A)
always @(A) // begin
if (A == 0) D = 8'b00000001;
else if (A == 1) D = 8'b00000010;
else if (A == 2) D = 8'b00000100;
else if (A == 3) D = 8'b00001000;
else if (A == 4) D = 8'b00010000;
else if (A == 5) D = 8'b00100000;
else if (A == 6) D = 8'b01000000;
else D = 8'b10000000;
// end
endmodule
Modeling an Encoder
module encoder (output reg [2:0] Code, input [7:0] Data);
always @(Data)
if (Data==8'b00000001) Code = 0; else
if (Data==8'b00000010) Code = 1; else
if (Data==8'b00000100) Code = 2; else
if (Data==8'b00001000) Code = 3; else
if (Data==8'b00010000) Code = 4; else
if (Data==8'b00100000) Code = 5; else
if (Data==8'b01000000) Code = 6; else
if (Data==8'b10000000) Code = 7; else
Code = 'bx;
endmodule
Modeling a Priority Encoder
module priority_encoder (output reg [2:0] Code, output valid_data, input
[7:0] Data);
assign valid_data = | Data;
always @(Data)
if (Data[7]) Code = 7; else
if (Data[6]) Code = 6; else
if (Data[5]) Code = 5; else
if (Data[4]) Code = 4; else
if (Data[3]) Code = 3; else
if (Data[2]) Code = 2; else
if (Data[1]) Code = 1; else
if (Data[0]) Code = 0; else Code = 'bx;
endmodule
Modeling a Priority Encoder
module priority_encoder2 (output reg [2:0] Code, output valid_data, input [7:0]
Data);
assign valid_data = | Data;
always @(Data)
casex (Data)
8'b1xxxxxxx : Code = 7; 8'b01xxxxxx : Code = 6;
8'b001xxxxx : Code = 5; 8'b0001xxxx : Code = 4;
8'b00001xxx : Code = 3; 8'b000001xx : Code = 2;
8'b0000001x : Code = 1;8'b00000001 : Code = 0;
default: Code = 'bx;
endcase
endmodule
Casex treats x values in the inputs as don’t care
Seven Segment Display Decoder
module Seven_Segment_Display (output reg [6:0] Display, input [3:0] BCD);
parameter BLANK = 7’b111_1111; parameter ZERO= 7’b000_0001; //abc_defg
parameter ONE= 7’b100_1111; parameter TWO= 7’b001_0010;
parameter THREE= 7’b000_0110; parameter FOUR= 7’b100_1100;
parameter FIVE= 7’b010_0100; parameter SIX= 7’b010_0000;
parameter SEVEN= 7’b000_1111; parameter EIGHT= 7’b000_0000;
parameter NINE= 7’b000_0100;
always @(BCD)
case (BCD)
0: Display = ZERO; 1: Display = ONE;
2: Display = TWO; 3: Display = THREE;
4: Display = FOUR; 5 : Display = FIVE;
6: Display = SIX; 7: Display = SEVEN;
8: Display = EIGHT; 9: Display = NINE; default: DISPLAY = BLANK;
endcase
endmodule
A piece of hardware is described as a Verilog module. One
of the given below Verilog codes is the correct description
of this piece:
Indicate which of these codes is valid and which is
invalid fully justifying your answer?
Give the logic diagram of this piece of hardware?