0% found this document useful (0 votes)
21 views157 pages

Day One

The valid identifiers are: - asd - Sad$ - \2as 2as and We-are are invalid because the first character cannot be a digit or special character. end is invalid because it is a keyword.

Uploaded by

Ahmed Elgmmal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views157 pages

Day One

The valid identifiers are: - asd - Sad$ - \2as 2as and We-are are invalid because the first character cannot be a digit or special character. end is invalid because it is a keyword.

Uploaded by

Ahmed Elgmmal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 157

INTRODUCTION TO

VERILOG
Dina Tantawy
OBJECTIVES
▪ Learn basic usage of Verilog.
▪ Learn primitive types and data types.
▪ Learn creating concurrent modules and reusing it.
What is Verilog? And Why?
▪ Verilog is another type
of Hardware Description
Language(HDL).
What is Verilog? And Why?
▪ Verilog is easier to learn and use than VHDL.
▪ Verilog is C-like .
▪ Verilog like any other language has
➢ Variables
➢ Data types
➢ Operators
➢ Conditions
➢ Loops
➢ Functions
➢ …..
▪ But it is different than other languages in the implementation of the code
▪Verilog is now part of SystemVerilog.
Why Verilog?
▪Simulation
▪Synthesis
▪Timing analysis
▪Test analysis
▪Extensible via Programming Language Interface (PLI)
History of Verilog
• Verilog was started initially as a proprietary hardware modeling language
by Gateway Design Automation Inc. around 1980.

• Verilog was standardized as IEEE 1364 in 1995, and has undergone several
revisions since then.

• The most recent version is IEEE 1800-2017, which merged Verilog with
SystemVerilog, a superset of Verilog that adds many features for verification
and design
DESIGN MODELING
▪ We can model design using:
➢Behavioral Modeling.
➢Structural Modeling.
➢Mix between ways (which is the usual)

▪ Another Model is
➢RTL is used to describe the behavior of the circuit from a register to the next
one using the data flow through basic components like mux, adders, ..etc.
➢Now, RTL “Register transfer level” is defined as any synthesizable code. In other
words , any code that can be converted to hardware
How can we build a Half adder in
Verilog?
▪Behavioral model
▪Structural model using primitives.
HALF ADDER BEHAVIORAL
Module name ports

module half_adder(A, B, s, c);

input A, B; Ports and Nets


output s, c; definitions (direction,
type, size)

assign s = A ^ B;
assign c = A & B;
Module implementation

//this is a comment line

endmodule
HALF ADDER BEHAVIORAL
Module name ports

module half_adder(A, B, s, c);

input A, B; Ports and Nets


output reg s, c; definitions (direction,
type, size)

always @(*) begin


s = A^B;
c= A&B; Module implementation
end

endmodule
HALF ADDER STRUCT USING PRIMITIVES
Module name ports

module half_adder(A, B, s, c);

input A, B; Ports and Nets


output s, c; definitions (direction,
type, size)

xor my_xor(s,A,B);
and my_and(c,A,B); Module implementation
using primitive instances
endmodule
How can we build full-adder in Verilog?
▪Behavioral model
▪Structural model other modules
FULL ADDER BEHAVIORAL … 1
ports
Module name

module onebit_fulladder_RTL (A,B,Cin,S,Cout);


input A,B;
output S; Ports and Nets
input Cin; definitions (direction,
output Cout; type, size)

assign S = ( A ^ B ) ^ Cin;
assign Cout = ((A ^ B) & Cin ) | (A & B);

endmodule
Module implementation
describing data flow
FULL ADDER BEHAVIORAL … 2
ports
Module name

module onebit_fulladder_behav (A,B,Cin,S,Cout);


input A,B;
output S; Ports and Nets
input Cin; definitions (direction,
output Cout; type, size)

/* this is a comment block


assign S = ( A ^ B ) ^ Cin;
assign Cout = ((A ^ B) & Cin ) | (A & B);
*/

assign {Cout, S} = A + B + Cin; Module implementation


describing its behavior
endmodule
FULL ADDER BEHAVIORAL … 2 Ports: we can write port direction and type
here directly

module onebit_fulladder_struct(input A, B, Cin, output S, Cout);


wire tempSum, tempCarry1,tempCarry2;
half_adder u1 (A,B, tempSum, tempCarry1);
half_adder u2 (.s(S), .c(tempCarry2), .A(tempSum),.B(Cin));
or (Cout, tempCarry1,tempCarry2);
endmodule

Remember:
module half_adder(A, B, s, c);
FULL ADDER BEHAVIORAL … 3

First way of mapping to existing modules is to connect ports by order


half_adder u1 (A,B, tempSum, tempCarry1);
half_adder u2 (.s(S), .c(tempCarry2), .A(tempSum),.B(Cin));

Second way of mapping to existing modules is to connect ports by


name .originalName(wire name)

Remember:
module half_adder(A, B, s, c);
FULL ADDER BEHAVIORAL … 3
What if we don’t need to connect all Ports?

Just leave its place empty


half_adder u3 (A,B, tempSum);
Here we ignored the last port (c)
half_adder u4 (A,B, , tempCarry1);
Here we ignored a port in the middle (s)
half_adder u5 (.s(S), .c( ), .A(tempSum),.B(Cin));

Here we ignored a named port


Remember:
module half_adder(A, B, s, c);
Program Structure
Module Definition

module ha(input A, B, Cin, output S, Cout);

module ha(A, B, Cin, S, Cout);


input A, B, Cin;
output S, Cout;
Port Declaration
<direction> <type> <sign> <size> <port_name>
▪ Direction
➢input
▪ input a; //should be wire
➢output
▪ output cout; //can be wire or reg
➢inout
▪ inout somepath; //should be wire
▪ If direction is not mentioned, it will give an error!!
▪ Direction and port_name are obligatory fields, all others are optional.
Port Declaration
<direction> <type> <sign> <size> <port_name>
▪ type
➢wire
▪ input wire a;
➢reg
▪ output reg cout;
➢wire & reg has other subtypes which will talk about them later;
▪ If type is not mentioned, default is wire
Port Declaration
<direction> <type> <sign> <size> <port_name>
▪ sign x = -16;
➢signed y = -16;
▪ input signed x; //in two’s complement format
# x > 2 is 0, y > 2 is 1
➢unsigned
▪ input unsigned y;

▪ If sign is not mentioned, default is unsigned


Port Declaration
<direction> <type> <sign> <size> <port_name>
▪ size
➢[MSB:LSB] //any integer : any integer
▪ input [3:0] x; //x is 4-bits, where MSB is of index 3
▪ input [5:3] y; // y is 3-bits
▪ input [0:3] w; //w is 4-bit, where MSB is of index 0
▪ input [2**2:3] q; //q is 2-bit, where MSB is of index 4

▪ If size is not mentioned, default is 1 bit


Port Declaration

<direction> <type> <sign> <size> <name> <array range>;


Lexical Conventions & Operators
Lexical Convention
▪The language is case-sensitive.
➢ Ab is not same as ab

▪Keywords are lower case letter.

▪Lexical convention are close to C++ but describes hardware.

▪ The Verilog HDL value set consists of four basic values:


0 - represents a logic zero, or a false condition
1 - represents a logic one, or a true condition
x - represents an unknown logic value
z - represents a high-impedance state
Lexical Convention
▪ Identifiers:
➢ A simple identifier shall be any sequence of letters, digits, dollar signs ($), and underscore
characters (_).
➢ The first character of a simple identifier shall not be a digit or $; it can be a letter or an
underscore.
Identifiers shall be case sensitive
➢ Example:
➢ _myVariableName
➢ variableName2
➢ Var$name
➢ Bad variable names:
➢ $name x
➢ 2var x
Lexical Convention
▪ Escaped Identifier:
➢ Identifiers that starts with ‘\’ and ends with space.
➢ The beginning and terminating characters ‘\’ & space are not part of the identifier.
➢ Example:
➢ \cpu3 is same as cpu3
➢ \wire[3] is NOT same as wire[3].
➢ The first identifier [3] is part of the name.
➢ The second identifier [3] is an index of the name.
➢ It is generated by most tools to convert bus onto single nets.
Lexical Convention
▪ System tasks and functions:
➢ The dollar sign ($) introduces built-in system functions.
➢ System constructs are not design semantics, but refer to simulator functionality.
➢ Example:
➢ $display(“%s”,“display text to console”) //similar to printf in c
➢ $finish //finishes the simulation
➢ What other functions do we have ?
▪ Comment
➢ // to the end of the line.
➢ /* to */ across several lines
QUIZ

▪ Which of the following is a valid identifier?


➢ asd
➢2as
➢Sad$
➢We-are
➢\2as
➢ end
Lexical Convention
▪Numbers:
▪Numbers are specified in the traditional form or below .
<size><base format><number>

▪<size> : contains decimal digitals that specify the size of the constant in the
number of bits. [optional]

▪<base format>: is the single character ‘ followed by one of the following


characters b(binary),d(decimal),o(octal),h(hex). [optional]

▪<number>: legal digital.


Lexical Convention
➢ Example :
➢ 4'b101 // 4- bit binary number 0101
➢ 8’b 1111_0000 // 8- bit binary number 11110000 where ‘_’ is syntactic sugar
➢ 12'h7f7 // 12-bit hex number 7f7
➢ 2'd3 // 2-bit decimal number
➢ - 4’d3 // 4-bit decimal number -3 (in two’s complement = 4’b1101)
➢ 4’d-3 // error!!!

➢ 'o12 // octal number, size will be inferred as 32 bit


➢ 347 // decimal number, assumed 32-bit till optimization.
Truncation and extension
Truncation and extension … 2
Arithmetic Operators
Symbol Description Note
+ add
- subtract
* multiply
/ divide may not synthesize
modulus
% may not synthesize
(remainder)
** power may not synthesize
Arithmetic Operators
initial
begin: block1
integer add_1,add_2,add_3; reg signed [7:0] x; reg [7:0] y;

x = -16; //1111_0000
y = -16; //1111_0000
#2 $display(" x > 2 is %b, y > 2 is %b", x>2,y>2);
add_1 = 2'd3;
add_2 = -4'd3 ;
add_3 = 4'd3;
#5;
add_1 = add_1 + x;
add_2 = add_2 - y ;
add_3 = add_3 + y;
#5; //add_1 = -13 , add_2=-243, add_3 = 243
end Can you explain how did we get those numbers?
Shift operators
a = 8'b1111_0000;
b = 2;

Symbol Description Note


a << b Logic shift left a by b bits & append ‘0’ = 1100_0000
a >> b Logic shift right a by b bits & append ‘0’ = 0011_1100
a <<< b Same as << = 1100_0000
Arithmetic right a by b bits & extend sign
a >>> b = 1111_1100
bit
Bitwise operators
a = 8'b1111_0000;
b = 8'b0000_1111;

Symbol Description Note


~ not ~a = 0000_1111
| or a | b = 1111_1111
& and a & b = 0000_0000
^ xor a ^ b = 1111_1111
~& or &~ nand a ~& b = 1111_1111

Number of bits is the same as the larger number


Logical operators
a = 8'b1111_0000;
b = 8'b0000_1111;

Symbol Description Note


! Logical not !a=0
|| Logical or a || b = 1
&& and a && b = 1

It returns 1-bit either true or false, any number that is not zero is considered true
Unary Reduction Operators
a = 8'b1111_0000;
b = 8'b0000_1111;

Symbol Description Note


& a And all bits and result in 1-bit =0
~& a nand all bits and result in 1-bit =1
|a or all bits and result in 1-bit =1
~| a nor all bits and result in 1-bit =0
^a xor all bits and result in 1-bit =0
~^a or ^~ a xnor all bits and result in 1-bit =1

Number of bits is just 1 bit in the result


Relational Operator

Testing only
Conditional operator

1 module conditional_operator();
3 wire out;
4 reg enable,data;
5 // Tri state buffer
6 assign out = (enable) ? data : 1'bz;
7
8 initial begin
9 $display ("time\t enable data out");
10 $monitor ("%g\t %b %b %b",$time,enable,data,out);
11 enable = 0;
12 data = 0; time enable data out
13 #1 data = 1; 0 0 0 z
14 #1 data = 0; 1 0 1 z
15 #1 enable = 1; 2 0 0 z
16 #1 data = 1; 3 1 0 0
17 #1 data = 0; 4 1 1 1
18 #1 enable = 0; 5 1 0 0
19 #10 $finish; 6 0 0 z
20 end
21 endmodule
Concatenation Operator

1 module concatenation_operator();
2
3 initial begin
4 // concatenation
5 $display (" {4'b1001,4'b10x1} = %b", {4'b1001,4'b10x1});
6 #10 $finish;
7 end {4'b1001,4'b10x1} = 100110x1
8
9 endmodule
Replication Operator
1 module replication_operator();
2
3 initial begin
4 // replication
5 $display (" {4{4'b1001}} = %b", {4{4'b1001}});
6 // replication and concatenation
7 $display (" {4{4'b1001,1'bz}} = %b", {4{4'b1001,1'bz}});
8 #10 $finish;
9 end
10 {4{4'b1001} = 1001100110011001
11 endmodule {4{4'b1001,1'bz} = 1001z1001z1001z1001z
OPERATOR PRECEDENCE
QUIZ

▪ For
➢a = 8'b1111_0000;
➢b = 8'b0000_1111;
▪ Evaluate the following expression:
➢ assign F = {a[3:1],b[3:1]}*2 < {3{a[4:3]}} & 6’h03
➢ assign Y = -b >> 2;
Data Types
What do data types have to do with hardware?

Nothing, actually because everything is just ‘0’ & ‘1’. People just wanted to write
one more language that had data types in it. there's no point.

But wait... hardware does have two kinds of drivers.

A driver is a data type which can drive a load. Basically, in a physical circuit, a
driver would be anything that electrons can move through/into.

• (Reg) Driver that can store a value (example: flip-flop).


• (Wire) Driver that can not store value, but connects two points (example:
wire).
https://www.asic-world.com
Data Types
• Wires
• Registers
The rest are just a variations of the above or NON-synthesizable types:
• Size variations
• Vectors (vs Scalars)
• Arrays
• Memories (Array of vectors )
• Non-synthesizable
• Real
• String
• Time
• Others
• Constants (Parameters)
• Integer
Data Types
Wire / Nets
• Nets are physical connections between structural entities.
• A net must be driven by a driver, such as a gate or a continuous assignment.
• Many types of nets (tri,wand,wor, trior,triand,trireg), but all we care about is
wire.
•tri is same as wire
•wand/triand performs and operation in case of conflict.
•Wor/trior performs or operation in case of conflict.
•trireg keeps old value in case of high-impedance
•supply0 → ground
•supply1 → Power
•tri0\tri1 → Pulldown/pullUp resistor (when these nets are not being
driven, the net floats to 0 or 1)
Data Types
▪ Reg (sequential statements)
◦Implicit storage – unless variable of this type is modified it retains previously
assigned value
◦Does not necessarily imply a hardware register
◦Register type is denoted by reg , others like (integer, real, time) are
constrained reg types.
◦Any variable gets assigned inside an always block or initial block must be of
reg type.
Variable Declaration with size variations
Declaring a vector/scalar net
wire [signed][<range>] <net_name>;
Range is specified as [MSb:LSb]. Default is one bit wide (scalar)
Declaring a register (vector)
reg [signed] [<range>] <reg_name>;

Declaring an array
reg [signed] <reg_name> [<range>] ;
Declaring memory
reg [signed] [<range>] <memory_name> [<start_addr> : <end_addr>];
Variable Declaration with size variations
Examples
• reg r; // 1-bit reg variable
• wire w1, w2; // 2 1-bit wire variable
• reg [7:0] vreg; // 8-bit register
• reg areg [0:7]; // an array of 1-bit register
• reg [7:0] memory [0:1023]; // a 1 KB memory or an array of 1024
register where each register is 8-bits
QUIZ

▪ Which of the following is an illegal assignment, and what is the final value
➢wire [7:0] a = 10’h2FF;
➢reg [7:0] a = 568;
➢b[3:2] = 2’b10;
➢reg c [0:3] = 4’b1111;
➢reg d [0:5]; assign d[0] = 1;
➢reg [4:0] mem [0:14] ; mem = 5;
➢reg [4:0] mem [0:14] ; mem[0] = 5;
➢reg [4:0] mem [0:14] ; mem[0][2:0] = 5;
Can We Make A Shift Operation Using
Concatenation?
wire [7:0] a,b;
▪ Shift left
➢ assign a = {b[6:0], 1’b0}
▪ Shift right
➢ assign a = {1’b0,b[7:1]}
▪ Shift left 4 bits
➢assign a = {b[3:0],4’b0}
▪ What about Rotate right ??
ARRAY Declaration

Assignment
LET’S DESIGN SOME CIRCUITS
COMBINATIONAL
Structural Modeling
Example: //Using 2 input and, design a 3 input and
module AND(in1, in2, out2);
input in1,in2;
output out2;
and and2(out2,in1,in2);// first port must be output.
endmodule

AND3
module AND3 (i0, i1, i2, op);
input i0, i1, i2; i0
output op;
wire temp; i1
o
AND a0 (.in1(i0), .in2(i1), .out2(temp)); i2
AND a1 (.in1(i2), .in2(temp), .out2(op));
endmodule
Primitive Gates

Source: IEEE STANDARD FOR VERILOG


User Defined Primitive Gates (UDP)

▪ Defined using keyword primitive compare(out, in1, in2);


output out;
“primitive” input in1,in2;

▪ One output only table


// in1 in2 : out
▪ Defined by a table 0 0 : 1;
0 1 : 0;
▪ Used in simulations mainly. 1 0 : 0;
1 1 : 1;
endtable

endmodule

https://www.referencedesigner.com/tutorials/verilog/verilog_11.php
Structural Modeling
Example: What hardware will we get if we did the following
module AND3 (i0, i1, i2, op);
input i0, i1, i2;
output op;
wire temp;

AND a0 (.in1(i0), .in2(i1), .out2(temp));


AND a1 (.in1(i2), .in2(temp), .out2(op));
AND a2 (.in1(i0), .in2(i2), .out2(temp)); AND3

endmodule i0

i1
o
i2
• Verilog Structural modeling describes hardware and connections,
• hardware executes concurrently.
• Several connections on same wire will lead to unknown behavior ‘x’
• Each component should have a different wire connected to the output ports
• Exception exists for tri-stated components.
• Input ports can share connections
Behavioral Modeling
▪ Continuous assignment
➢ Starts with reserve word ‘assign’
➢ Continuous execution (concurrent as well)
➢ Models combinational circuits

▪ Procedural blocks (sequential blocks) … later


➢ Initial blocks: executed once, used in test-benches only
➢ Always block: always executed, can model both combinational
and sequential circuits
Continuous assignment
▪Continuous assignment statements drive nets (e.g.; wire data type).
•The left-hand side of a continuous assignment must be net data type.
•They are outside the procedural blocks (always and initial blocks).
•They can be used for modeling combinational logic and tri-state buffers.
•The continuous assign overrides any procedural assignments.
Examples:
//Explicit continuous assignment
wire [31:0] maxout;
assign maxout= in;

//Implicit continuous assignment


wire [31:0] x1=in;
EXAMPLES
Example 3 : 4x1 Multiplexer
a
lConditional Operator b
c
y

module mux_4x1(y, a, b, c, d, sel1, sel0); d


input a, b, c, d;
input sel1,sel0;
output y; sel1 & sel0
assign y =
(sel1 == 0 && sel0 == 0 ) ? a :
(sel1 == 0 && sel0 == 1 ) ? b :
(sel1 == 1 && sel0 == 0 ) ? c :
(sel1 == 1 && sel0 == 1) ? d : 1'bx;
endmodule
What if the input to MUX is bus?
Example : 4x1 Multiplexer
a[3:0]
lConditional Operator b[3:0]
c[3:0]
y[3:0]

module mux_4bits(y, a, b, c, d, sel); d[3:0]


input [3:0] a, b, c, d;
input [1:0] sel;
output [3:0] y; sel[1:0]
assign y =
(sel == 0) ? a :
(sel == 1) ? b :
(sel == 2) ? c :
(sel == 3) ? d : 4'bx;
endmodule
EXAMPLE : 3-TO-8 DECODER
module decoder (in,out);
input [2:0] in;
output [7:0] out;
wire [7:0] out;
assign out =
(in == 3'b000 ) ? 8'b0000_0001 :
(in == 3'b001 ) ? 8'b0000_0010 :
(in == 3'b010 ) ? 8'b0000_0100 :
(in == 3'b011 ) ? 8'b0000_1000 :
(in == 3'b100 ) ? 8'b0001_0000 :
(in == 3'b101 ) ? 8'b0010_0000 :
(in == 3'b110 ) ? 8'b0100_0000 :
(in == 3'b111 ) ? 8'b1000_0000 : 8'h00;
endmodule
QUIZ
Implement the one-bit full
subtractor using behavioral
model or structural model
using (half-subtractors)

F
SUMMARY

▪ Motivation
▪ Verilog lexical conventions, operators and constructs.
▪ Program structure.
▪ Modeling Methods.
➢Structural
➢Behavioral
THANK YOU
Next time: Testing And Verification, does the code do what it promises ?
Rest of behavioral modeling
COMBINATIONAL
LOGIC
AGENDA
▪ Review Last Lecture
▪ Language features:
➢ Parameters
▪ Continuous Statements
➢ For Generate Statements
▪ Sequential Statements
➢ Reg vs Wire
➢ Conditional Statements
▪ Testbenches
▪ Next Time: Sequential Logic
How To Make 2-bit adder
A[1:0] B[1:0]

module twobit (A,B,Cin,S,Cout);


input [1:0] A,B;
output [1:0] S;
input Cin;
output Cout; Cin 2-Bit Adder Cout

assign {Cout, S} = A + B + Cin;


endmodule

S[1:0]
How To Make N-bit adder … 1
A[N-1:0] B[N-1:0]

How many bits do we need?

Cin N-Bit Adder Cout

N=?
S[N-1:0]
How To Make N-bit adder … 2
How many bits do we need? N=4 A[N-1:0] B[N-1:0]
Module Definition 1. Define a variable parameter

module Adder #(parameter N=8) (A,B,Cin,S,Cout);


input [N-1:0] A,B;
output [N-1:0] S; 2. Use the parameter to
input Cin; decide size of inputs/outputs
output Cout; Cin N-Bit Adder Cout

assign {Cout, S} = A + B + Cin;


endmodule 3. Update implementation if
required

Module Instantiation S[N-1:0]


Adder #(4) test(A,B,Cin,S,Cout); 4. Set parameter upon
instantiation
How To Make N-bit adder … 3
How many bits do we need? N=8 A[N-1:0] B[N-1:0]
Module Definition
module Adder #(parameter N=8) (A,B,Cin,S,Cout);
input [N-1:0] A,B;
output [N-1:0] S;
input Cin;
output Cout; Cin N-Bit Adder Cout

assign {Cout, S} = A + B + Cin;


endmodule

Module Instantiation S[N-1:0]


Adder #(8) test(A,B,Cin,S,Cout); Here we can ignore setting
the parameter since the
Adder test2 (A,B,Cin,S,Cout);
default value is 8
PARAMETERS
• Parameters are CONSTANTS sent to the module or set by the module.
• Like all other constants in language those values can’t change during runtime.
• Different to other languages those parameters decide the hardware so they must be set to
constant BEFORE SYNTHESIS
• There are two types of parameters
• localparam : set by the module itself and used as a constant inside it.
• parameter : set by modules calling the current module, and still are constants.
• An additional param used for timing: (later)
• specparam: specify parameters are used for delays, it is also a constant during runtime.
Parameters

module Decode;
parameter Width = 8;
Defined Inside module parameter Polarity = 1;
Constants
parameter Add = 8'b1111_0000,
Halt= 8'hFF,
Sub = 4'o12;

localparam error_msg = "something wrong";

endmodule Any type

Defined with module


module M #(parameter Width,Polarity)();
endmodule

Copyright © Doulous 2001


1. Defparam overrides instantiation
values

2. Defparam CANNOT change


localparam

Copyright © Doulous 2001


module constants; module defparam_tb;
parameter c_a = 4'b1111, defparam top.t1 = 500, top.t2 = 400;
c_b = 4'd23; defparam top.myblock.b1 = 23,
endmodule top.myblock.b2 = "another name";
endmodule
module testparam;
parameter t1 = 100; module test_tb;
parameter t2 = 200; testparam #(1000) top();
localparam localt = 600 ; defparam_tb t ();
block myblock(); constants c();
endmodule endmodule

module block; test_tb


parameter b1 = 2;
parameter b2 = "this is a test" ;
endmodule constants c defparam_tb t testparam top

Using hierarchal names, we can access parallel


and child modules. block myblock

Note that synthesis tools do not generally support hierarchical names. The alternative
approach is to use the `include directive as will be shown later
module testparam;
parameter t1 = 100;
parameter t2 = 200;
localparam localt = 600 ;
block myblock();
initial begin
$monitor("t1 %d, t2 %d, t3 %d",t1,t2,localt);
#1;
$display("c_a %b, c_b %b", c.c_a, c.c_b);
#1;
$display("b1 %d, b2 %s", myblock.b1, myblock.b2);
#1;
$finish; test_tb
end
endmodule
constants c defparam_tb t testparam top

Using hierarchal names, we can access parallel


and child modules. block myblock

Note that synthesis tools do not generally support hierarchical names. The alternative
approach is to use the `include directive as will be shown later
Using Parameters

• As Size
➢ reg [Width-1] data;
• As constant (magic number)
➢ assign finish = Bus == Halt ? 1'b1:1'b0;
• As width in replica operator
➢assign Bus = Enable? dataIn : {Width{1'bz}}; //assign high
impedance on the bus
How To Make 2-bit Ripple adder … 1
A[1:0] B[1:0]

module twobit (A,B,Cin,S,Cout);


input [1:0] A,B;
output [1:0] S;
input Cin;
output Cout; Cin 2-Bit Adder Cout

assign {Cout, S} = A + B + Cin;


endmodule

S[1:0]
This is not necessary a ripple adder ! Let’s do it structural
How To Make 2-bit adder … 2
A[1] B[1] A[0] B[0]
module twobit_2 (a,b,cin,s,cout);
input [1:0] a,b;
output [1:0] s;
input cin;
Cin Full Adder Full Adder Cout
output cout;
wire w;

onebit f1(a[0],b[0],cin,s[0],w);
onebit f2(a[1],b[1],w,s[1],cout); S[1] S[0]

endmodule
How To Make 4-bit adder
module fourbit (a,b,cin,s,cout);
input [3:0] a,b;
output [3:0] s;
input cin;
output cout;
wire [2:0] w;

onebit f1(a[0],b[0],cin,s[0],w[0]);
onebit f2(a[1],b[1],w[0],s[1],w[1]);
onebit f3(a[2],b[2],w[1],s[2],w[2]);
onebit f4(a[3],b[3],w[2],s[3],cout);

endmodule
How To Make N-bit adder
1. Define a variable parameter
module fourbit (a,b,cin,s,cout); module adder #(parameter N=8) (a,b,cin,s,cout);
input [3:0] a,b; input [N-1:0] a,b;
output [3:0] s; output [N-1:0] s; 2. Use the parameter to
input cin; input cin; decide size of inputs/outputs
output cout; output cout; 3. Update implementation if
wire [2:0] w; wire [N:0] w; required

onebit f1(a[0],b[0],cin,s[0],w[0]); assign w[0] = cin;


onebit f2(a[1],b[1],w[0],s[1],w[1]); assign cout = w[N];
onebit f3(a[2],b[2],w[1],s[2],w[2]); genvar i;
onebit f4(a[3],b[3],w[2],s[3],cout); generate
for (i = 0; i<N ; i = i+1)
onebit fx(a[i],b[i],w[i],s[i],w[i+1]);
endmodule endgenerate
endmodule
Generate Blocks

• Generate has three blocks:


• For
• If
• Case

• All three blocks control the creation of hardware.


• The condition and number of iteration should be fixed (constant) at synthesis time
• Generation blocks can be nested.
Generate … for (Continuous/ Concurrent for)

genvar k;
generate
for (k = 0; k < 4; k=k+1) begin
assign val[k] = a[k] & b[k];
and ax (res[k],a[k],c[k]);
end
endgenerate
Generate … for (Continuous/ Concurrent for)
1. Define a loop parameter, this is not a wire or
reg, this is just a control parameter and doesn’t
synthesize to any hardware
genvar k; 3. Create for loop with constant assign val[0] = a[0] & b[0];
generate condition and ax_1 (res[0],a[0],c[0]);
for (k = 0; k < 4; k=k+1) begin assign val[1] = a[1] & b[1];
assign val[k] = a[k] & b[k]; and ax_2 (res[1],a[1],c[1]);
and ax (res[k],a[k],c[k]); Expands to assign val[2] = a[2] & b[2];
end and ax_3 (res[2],a[2],c[2]);
4. Loop will be unrolled and everything
endgenerate assign val[3] = a[3] & b[3];
inside the loop will be repeated the
and ax_4 (res[3],a[3],c[3]);
2. Define generate block same number of times as the loop
Generate … for (Continuous/ Concurrent for)

genvar k;
generate always@(posedge clk) begin
for (k = 0; k < 4; k++) begin val[0] = a[0] & b[0];
always@(posedge clk) begin val[1] = a[1] & b[1];
val[k] = a[k] & b[k]; Expands to val[2] = a[2] & b[2];
end val[3] = a[3] & b[3];
end end
endgenerate

Source: https://vlsiverify.com/
Generate … for (Continuous/ Concurrent for)

assign val = a[0] & b[0];


genvar k; and ax_1 (res[0],a[0],val);
generate assign val = a[1] & b[1];
for (k = 0; k < 4; k++) begin and ax_2 (res[1],a[1],val);
assign val = a[k] & b[k]; assign val = a[2] & b[2];
Expands to and ax_3 (res[2],a[2],val);
and ax (res[k],a[k], val);
end assign val = a[3] & b[3];
endgenerate and ax_4 (res[3],a[3],val);
BeWare !! This is a concurrent loop
Conflicts on val will occur;

Source: https://vlsiverify.com/
Generate … for (Continuous/ Concurrent for)

assign val = a[0] & b[0];


genvar k; and ax_1 (res[0],a[0],val);
generate assign val = a[1] & b[1];
for (k = 0; k < 4; k++) begin and ax_2 (res[1],a[1],val);
assign val[k] = a[k] & b[k]; assign val = a[2] & b[2];
fix Expands to and ax_3 (res[2],a[2],val);
and ax (res[k],a[k], val[k]);
end assign val = a[3] & b[3];
endgenerate and ax_4 (res[3],a[3],val);
BeWare !! This is a concurrent loop
Conflicts on val will occur;

Source: https://vlsiverify.com/
Generate … if (Continuous/ Concurrent if)

module gen_if_ex #(parameter sel = 0)(


input A, B, Cin,
output S, Cout);

generate
if(sel) begin
full_adder fa(A, B, Cin, S, Cout);
end
else begin
half_adder ha(A, B, S, Cout);
end
endgenerate
endmodule

Source: https://vlsiverify.com/
Generate … if (Continuous/ Concurrent if)

module gen_if_ex #(parameter sel = 0)(


input A, B, Cin,
output S, Cout);
1. Define generate
block 2. Create if with constant condition
generate
if(sel) begin
full_adder fa(A, B, Cin, S, Cout); 3. This component will be created only
end if condition is true
else begin
4. Having else for
half_adder ha(A, B, S, Cout);
if is optional.
end
endgenerate
endmodule

Source: https://vlsiverify.com/
Generate … else (Continuous/Concurrent case)
module gen_if_ex #(parameter sel = 0)(
input A, B, Cin,
output S, Cout);

generate
case(sel)
0: begin
half_adder ha(A, B, S, Cout);
end
1: begin
full_adder fa(A, B, Cin, S, Cout);
end
endcase
endgenerate
endmodule
PROCEDURAL BLOCKS
SEQUENTIAL STATEMENTS
Behavioral Modeling
▪ Review: Continuous assignment
➢ Starts with reserve word ‘assign’
➢ Continuous execution
➢ Models combinational circuits
➢ Concurrent execution

▪ Procedural blocks
➢ Initial blocks: executed once, used in test-benches only
➢ Always block: always executed, can model both combinational
and sequential circuits.
➢ Code inside it is executed sequential.
Sensitivity List
The sensitivity list is used at the beginning of an always procedure to infer
combinational logic or sequential logic behavior in simulation and synthesis.

• always @* infers combinational logic. Simulation and synthesis will


automatically be sensitive to all signals read within the procedure. @*
was added in Verilog-2001.

• always @(signal, signal, ... ) infers combinational logic if the list of


signals contains all signals read within the procedure.

• always @(posedge signal, negedge signal, ... ) infers sequential logic.


Either the positive or negative edge can be specified for each signal in
the list. A specific edge should be specified for each signal in the list.
Types Of Procedural Statements

▪ Procedural assignments
▪ Conditional statements (this is different from generate if/case)
➢If-else
➢case
▪ Looping statements (this is different from generate for)
➢for
➢while
➢repeat
Data Types
▪ Review : Nets (continuous statements)
▪ Registers (sequential statements)
◦Implicit storage – unless variable of this type is modified it retains previously
assigned value
◦Does not necessarily imply a hardware register
◦Register type is denoted by reg , others like (integer, real, time) are
constrained reg types.
◦Any variable gets assigned inside an always block or initial block must be of
reg type.
Procedural Block To Generate Combinational Circuit
Example : Half adder
module half_adder(x, y, s, c);
input x, y;
output s, c;
assign s = x ^ y;
assign c = x & y;
endmodule

module half_adder_proc(x, y, s, c);


input x, y;
output reg s, c;
always @(*) begin
s = x^y;
c= x&y;
end
endmodule
EXAMPLE :
EQUIVALENT ?
module randomCir1(a,b,c,d,e,g); module randomCir2(a,b,c,d,e,g);
input a,b,c; input a,b,c;
output d,e; output reg d,e;
output g; output g;
wire w; reg w;

always @(*)
assign w = a |b; begin
assign d = c & w; w = a |b;
d = c & w;
assign w = b & c;
assign e = w | a; w = b & c;
e = w | a;
end
assign g = w;
assign g = w;
endmodule
endmodule
EXAMPLE :
EQUIVALENT ?
module randomCir1(a,b,c,d,e,g);
input a,b,c;
output d,e;
output g;
wire w; • w will have a conflict, because on wire is
connected to two different drivers in
assign w = a |b; continuous assignment.
assign d = c & w;

assign w = b & c;
• Continuous assignment draws the hardware
assign e = w | a; once it sees the assign statement.
• All statement are concurrent, order doesnot
assign g = w;
matter.
endmodule
EXAMPLE :
EQUIVALENT ?
In procedural blocks: module randomCir2(a,b,c,d,e,g);
• Code is executed line by input a,b,c;
line. output reg d,e;
output g;
• Order matters and changing reg w;
order might result in
different hardware. always @(*)
begin
• A net assigned more than w = a |b;
once is treated as more than d = c & w;
one net.
w = b & c;
• If we reads the net assigned e = w | a;
more than once in the end
procedural block, then we
are reading the last changed assign g = w;
instance of it.
endmodule
SEQUENTIAL CONDITIONAL OPERATOR “IF”
Sequential Conditional Operator “if”
wire sel,a,b;
reg y,tempOut;
always@(*)
begin
if (sel == 0)
y = a; //single statement
else begin
y = b; //multiple statements require begin/end
tempOut = a;
end
end If conditions only exist in Procedural Blocks

In Verilog begin/end are similar to { } in c++

What hardware will be generated from this circuit


Sequential Conditional Operator “if”
wire sel,a,b; All variables that gets assigned in if condition
reg y,tempOut; generate their own multiplexers
always@(*)
begin
if (sel == 0)
y = a; //single statement
else begin
y = b; //multiple statements require begin/end
tempOut = a;
end
end
Any variable with unknown state will
generate a latch to save previous state

What hardware will be generated from this circuit


WARNING: UNWANTED LATCH
▪ Nets/wires can’t hold a value, they only connect it from
source to destination.
▪ We need some structure to hold previous state.
▪ Transparent latches are perfect for this usage, when
condition is true, it passes input, else it keeps the state.
▪ However, Latches use power and area!! And are easily
generated unnecessary it you wrote a bad code!! So be
ware of what you intend.
WARNING: UNWANTED LATCH
tempOut (data)
latch output
sel (enable)

• How to Avoid unnecessary latches?


– If you use conditional checking using "if”, then you need to
mention the "else" part. Missing the else part results in a latch.

– If you don't like typing the else part, then you must initialize all
the variables at the beginning of the procedural block.
Get rid of unwanted latches
wire sel,a,b; Get rid of unwanted latches.
reg y,tempOut;
always@(*)
begin
y=0;
tempOut=0;

if (sel == 0)
y = a; //single statement 0
else begin
y = b; //multiple statements require begin/end
tempOut = a;
end
end
Sequential Conditional Operator “if”
always@(*)
begin
if (sel == 0)
y = a;
else if (sel == 1 & a~= 0)
y = b;
else if (b == 1)
y = c;
end

A series of conditions generates a series of muxes

Remember: Any variable with


unknown state will generate a latch to
save previous state, how would you get
rid of it?
UP TO A CHALLENGE?
CAN YOU GUESS THE
HW?
input a,b,c1,c2;
output F;
reg w;
always @(*)
begin
if (~c1)
w = a;
else
w = b;
if (c2) w = ~w; Will we get an unwanted latch here?
end Why ?
assign F = w;
EXAMPLE :
EQUIVALENT ?
module randomCir1(a,b,c1,c2,w); module randomCir2(a,b,c1,c2,w);
input a,b,c1,c2; input a,b,c1,c2;
output reg w; output reg w;

always @(*) always @(*)


begin begin
if (c1) if (c1)
if (c2) begin
w = a; if (c2)
else w = a;
w = b; end
end else
w = b;
endmodule end

endmodule
EXAMPLE :
EQUIVALENT ?
module randomCir2(a,b,c1,c2,w);
input a,b,c1,c2;
output reg w;

always @(*)
begin
if (c1)
begin
if (c2)
w = a;
end
else
w = b;
end

endmodule
EXAMPLE :
EQUIVALENT ?
module randomCir1(a,b,c1,c2,w);
input a,b,c1,c2;
output reg w;

always @(*)
begin
if (c1)
if (c2)
w = a;
else
w = b;
end

endmodule
EXAMPLE :
EQUIVALENT ?
SEQUENTIAL CONDITIONAL OPERATOR “CASE”
EXAMPLE : 3-TO-8 DECODER
module decoder (in,out);
input [2:0] in;
output reg [7:0] out;
always @(*)
begin
case(in)
3'b000: out = 8'b0000_0001;
3'b001: out = 8'b0000_0010;
3'b010: out = 8'b0000_0100;
3'b011: out = 8'b0000_1000;
3'b100: out = 8'b0001_0000;
3'b101: out = 8'b0010_0000;
3'b110: out = 8'b0100_0000;
3'b111: out = 8'b1000_0000;
default: out = 8'b0000_0000; “_” in a number is a syntactic sugar
endcase
Do we really need the default case here?
end
endmodule
EXAMPLE :
module randomCir5 (in,out);
input [2:0] in;
output reg [3:0] out;
always @(*)
begin a “?” is a don’t care, can be 0 or 1 but NOT x or z
case(in)
3'b000: out = 4'b0001;
3'b001: out = 4'b0010;
3’b01?: out = 4'b0100;
3’b1??: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule

What will happen if we omitted the default case?


By examining the resulted hardware, we will find that
an “?” treats elements are don’t care they even can
be an “x” or “z”.
EXAMPLE :
module randomCir5 (in,out);
However, simulation will result in a wrong behavior,

input [2:0] in;


output reg [3:0] out;
always @(*)
begin a “?” is a don’t care, can be 0 or 1 but NOT x or z
case(in)
3'b000: out = 4'b0001;
3'b001: out = 4'b0010;
3’b01?: out = 4'b0100;
3’b1??: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule

WE NEVER NEVER NEVER continue with a design if


functional simulation behaves wrong NEVER.
You must fix the code first
WHAT IF WE WANT TO HANDLE
“X” OR “Z” IN CASE
USE CASEX OR CASEZ
It produces the exact same hardware, however, it will
have different simulation results.

EXAMPLE :
module randomCir5 (in,out);
input [2:0] in;
output reg [3:0] out;
always @(*)
begin a “?” is a don’t care, can be 0 or 1 or z
casez(in)
3'b000: out = 4'b0001;
3'b001: out = 4'b0010;
3’b01?: out = 4'b0100;
3’b1??: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule
EXAMPLE :
module randomCir5 (in,out);
input [2:0] in;
output reg [3:0] out;
always @(*)
begin Z is treated as ? Both are don’t cares
casez(in)
3'b000: out = 4'b0001;
3'b001: out = 4'b0010;
3’b01?: out = 4'b0100;
3’b1ZZ: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule
It produces the exact same hardware; however, it will
have different simulation results.

EXAMPLE :
module randomCir5 (in,out);
input [2:0] in;
output reg [3:0] out;
always @(*)
begin a “?” is a don’t care, can be 0 or 1 or x or z
casex(in)
3'b000: out = 4'b0001;
3'b001: out = 4'b0010;
3’b01?: out = 4'b0100;
3’b1??: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule

It is usually not recommended to allow a value of “x”


in synthesis.
EXAMPLE :
module randomCir5 (in,out);
input [2:0] in;
output reg [3:0] out;
always @(*)
begin X is also a don’t care same as ? and Z
casex(in)
3'b000: out = 4'b0001;
3'b001: out = 4'b0010;
3’b01?: out = 4'b0100;
3’b1XZ: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule
EXAMPLE :
module randomCir5 (in,out);
input [2:0] in;
output reg [3:0] out;
always @(*)
begin
casex(in)
3'b000: out = 4'b0001;
3’b?01: out = 4'b0010; What happens when a pattern match more than one
3’b01?: out = 4'b0100; case? “101” for example ? Priority solves the issue.
3’b1??: out = 4’b4000;
default: out = 4'b0000;
endcase
end
endmodule
EXAMPLE :
module randomCir6 (in,out);
input [2:0] in;
output reg [3:0] out, result;
always @(*)
begin
casex(in)
3'b000, 3’b010: begin Remember begin/end
Cases separated by a out = 4'b0001; are replacement of {}
comma, has the same result = 4’h3l4; in other languages.
body end
default: out = 4'b0000;
endcase
end
endmodule

Challenge: what is the generated hardware?


EXAMPLE :
module randomCir7 (in,out);
input [2:0] in;
wire [2:0] A [0:4];
output reg [3:0] out;
always @(*)
begin
case(in)
A[0]: out = 4'b0001;
Expression A[1]: out = 4'b0010;
A[2]: out = 4'b0100;
A[3]: out = 4’b1000;
default: out = 4'b0000;
endcase
end
endmodule
Copyright© Doulos 2001
Copyright© Doulos 2001
Copyright© Doulos 2001
Copyright© Doulos 2001
CASE guidelines
• Non-parallel case statements infer priority encoders. It is a poor coding practice to code priority encoders
using case statements. It is better to code priority encoders using if-else-if statements.

• Guideline: Code all intentional priority encoders using if-else-if statements. It is easier for a typical design
engineer to recognize a priority encoder when it is coded as an if-else-if statement.

• Guideline: Case statements can be used to create tabular coded parallel logic. Coding with case statements is
recommended when a truth-table-like structure makes the Verilog code more concise and readable.

• Guideline: Examine all synthesis tool case-statement reports.

• Guideline: Change the case statement code, as outlined in the above coding guidelines, whenever the
synthesis tool reports that the case statement is not parallel (whenever the synthesis tool reports "no" for
"parallel_case").

• Although good priority encoders can be inferred from case statements, following the above coding guidelines
will help to prevent mistakes and mismatches between pre-synthesis and postsynthesis simulations.
TESTBENCH
LET’S VERIFY SOME CIRCUITS
INTRODUCTION TO TEST BENCHES

▪ Test benches are used for the verification of the digital hardware design.
Verification is required to ensure the design meets the timing and functionality
requirements.
▪ Test benches are used to simulate and analyze designs without the need for any
physical hardware or any hardware device. you can inspect every signal /variable
(reg, wire in Verilog) in the design.
▪ Test benches saves cost and time.
▪ Test benches automate testing.
▪ Test benches don’t synthesize, the don’t generate any hardware
TEST BENCH FOR N-BIT ADDER

▪ Recall code for it


module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0;
#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4; Since testbench doesn’t simulate a real circuit
localparam T=100; and only used for testing, it has no input or
reg [N-1:0] A,B; output ports
reg Cin;
wire[N-1:0] S; Make sense?
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0;
#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4; Remember parameters, they are constants
localparam T=100; we can use in the testbench
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0;
#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B; Remember, any Net changes value inside
reg Cin; initial or always block has to be of type reg,
wire[N-1:0] S; we use those nets to act as input to unit
wire Cout; under test (N-bit adder)

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0;
#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B; We use those nets to read output from unit
reg Cin; under test, why they are not reg despite
wire[N-1:0] S; being read in initial block?
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0;
#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B; This is the module we want to test, can we
reg Cin; add it below the initial block ?
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0;
#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0; • This initial block is a type of procedural block,


#T Cin =1; • It is only executed once.
#T A=6; B=9; Cin=0; • Usually it got discarded on synthesis, so don’t use it in
#T Cin=1; making hardware
#T A=9; B=7; Cin=0; • We add the sequence of our testcases here.
#T Cin=1; • Code executed in initial block is sequential (one line at a
$stop; time)
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0; • We added 6 test cases, and separate each test case by a
#T Cin =1; delay (#T)
#T A=6; B=9; Cin=0; • What is the value of the delay?
#T Cin=1; • What will happen if we didn’t add delay?
#T A=9; B=7; Cin=0; • How does our UUT read the changed input ?
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0; • Remember what starts with “$”, it is built-in function


#T Cin =1; • This function stops the simulation
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0; • Remember what starts with “$”, it is built-in function


#T Cin =1; • It is a display function, similar to printf, that takes the
#T A=6; B=9; Cin=0; format first then the data and displays them.
#T Cin=1; • This function runs in the background, each time one of its
#T A=9; B=7; Cin=0; inputs changes, it prints the new values.
#T Cin=1;
$stop;
end
endmodule
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0; • Another builtin-function to display time (simulation time)


#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
STRING FORMAT
Argument Description
%h, %H Display in hexadecimal format
%d, %D Display in decimal format
%b, %B Display in binary format
%o or %O Display octal format
%m, %M Display hierarchical name
%s, %S Display as a string
%t, %T Display in time format
%f, %F Display 'real' in a decimal format
%e, %E Display 'real' in an exponential format
module tb_adder();
localparam N=4;
localparam T=100;
reg [N-1:0] A,B;
reg Cin;
wire[N-1:0] S;
wire Cout;

Adder #(N) UUT(A,B,Cin,S,Cout);

initial
begin
$monitor("Status: %s \t, T: %t \t,A:%d\t + B:%d\t + Cin:%d\t = Sum:%d\t , Caryy:%d",
(A+B+Cin) == {Cout,S} ? "Success":"Failure",$time,A,B,Cin,S,Cout);

A=3;B=5; Cin = 0; • Not use of a condition inside the monitor


#T Cin =1;
#T A=6; B=9; Cin=0;
#T Cin=1;
#T A=9; B=7; Cin=0;
#T Cin=1;
$stop;
end
endmodule
THANK YOU

You might also like