Professional Documents
Culture Documents
IN
Search ✔
Search ✔
............ARRAY METHODS
Specman E ..................... Array Methods
Interview Questions ..................... Array Querying Functions
..................... Array Locator Methods
..................... Array Ordering Methods
..................... Array Reduction Methods
..................... Iterator Index Querying
............DYNAMIC ARRAYS
..................... Declaration Of Dynmic Array
..................... Allocating Elements
..................... Initializing Dynamic Arrays
..................... Resizing Dynamic Arrays
............ASSOCIATIVE ARRAYS
..................... Associative Array Methods
............QUEUES
..................... Queue Operators
..................... Queue Methods
..................... Dynamic Array Of Queues Queues Of Queues
............COMPARISON OF ARRAYS
..................... Static Array
..................... Associative Array
..................... Dynamic Array
..................... Queues
............LINKED LIST
..................... List Definitions
..................... Procedure To Create And Use List
..................... List_iterator Methods
..................... List Methods
............CASTING
..................... Static Casting
..................... Dynamic Casting
..................... Cast Errors
............DATA DECLARATION
..................... Scope And Lifetime
..................... Global
..................... Local
..................... Alias
..................... Data Types On Ports
..................... Parameterized Data Types
..................... Declaration And Initialization
............OPERATORS 1
..................... Operators In Systemverilog
..................... Assignment Operators
..................... Assignments In Expression
..................... Concatenation
..................... Arithmetic
..................... Relational
..................... Equality
............OPERATORS 2
..................... Logical
..................... Bitwise
..................... Reduction
..................... Shift
..................... Increment And Decrement
..................... Set
..................... Streaming Operator
..................... Re-Ordering Of The Generic Stream
..................... Packing Using Streaming Operator
..................... Unpacking Using Streaming Operator
............OPERATOR PRECEDENCY
............EVENTS
..................... Triggered
..................... Wait()
..................... Race Condition
..................... Nonblocking Event Trigger
..................... Merging Events
..................... Null Events
..................... Wait Sequence
..................... Events Comparison
............CONTROL STATEMENTS
..................... Sequential Control
..................... Enhanced For Loop
..................... Unique
..................... Priority
............PROGRAM BLOCK
............PROCEDURAL BLOCKS
..................... Final
..................... Jump Statements
..................... Event Control
..................... Always
............FORK JOIN
..................... Fork Join None
..................... Fork Join Any
..................... For Join All
............FORK CONTROL
..................... Wait Fork Statement
..................... Disable Fork Statement
............SUBROUTINES
..................... Begin End
..................... Tasks
..................... Return In Tasks
..................... Functions
..................... Return Values And Void Functions:
..................... Pass By Reference
..................... Default Values To Arguments
..................... Argument Binding By Name
..................... Optional Argument List
............SEMAPHORE
............MAILBOX
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
............ENCAPSULATION
..................... Access Specifiers
OpenVera
Constructs ............POLYMORPHISM
Switch TB
............ABSTRACT CLASSES
RVM Switch TB
RVM Ethernet sample ............PARAMETERISED CLASS
..................... Type Parameterised Class
..................... Value Parameterised Class
..................... Generic Parameterised Class
Specman E ..................... Extending Parameterised Class
Interview Questions
............NESTED CLASSES
..................... Why Use Nested Classes
............CONSTANT
..................... Constant Class
..................... Global Constant
..................... Instance Constants
............STATIC
..................... Static Class Properties
............CASTING
............COPY
..................... Shallow Copy
..................... Deep Copy
..................... Clone
............NULL
............EXTERNAL DECLARATION
............TYPEDEF CLASS
..................... Forward Reference
..................... Circular Dependency
............PURE
............MISC
..................... Always Block In Classes
Search ✔
............CONSTRAINT BLOCK
OpenVera ..................... Inheritance
Constructs ..................... Overrighting Constraints
Switch TB
............INLINE CONSTRAINT
RVM Switch TB
RVM Ethernet sample ............GLOBAL CONSTRAINT
............CONSTRAINT MODE
..................... Disabling Constraint Block
Specman E
Interview Questions ............EXTERNAL CONSTRAINTS
..................... Constraint Hiding
............RANDOMIZATION CONTROLABILITY
..................... Controlability
............STATIC CONSTRAINT
............CONSTRAINT EXPRESSION
..................... Set Membership
..................... Weighted Distribution
..................... Implication
..................... If..Else
............VARIABLE ORDERING
..................... Functions
..................... Iterative Constraints
............RANDCASE
............RANDSEQUENCE
..................... Random Productions
..................... Random Production Weights
..................... If..Else
..................... Case
..................... Repeat Production Statements
..................... Rand Join
..................... Break
..................... Return
..................... Value Passing Between Productions
............RANDOM STABILITY
..................... Srandom
............ARRAY RANDOMIZATION
............CONSTRAINT GUARDS
............TITBITS
..................... Constraining Non Integral Data Types
..................... Saving Memory
Search ✔
............IGNORE BINS
OpenVera
Constructs ............ILLEGAL BINS
Switch TB
............CROSS COVERAGE
RVM Switch TB ..................... User-Defined Cross Bins
RVM Ethernet sample
............COVERAGE OPTIONS
..................... Weight
..................... Goal
Specman E ..................... Name
Interview Questions ..................... Comment
..................... At_least
..................... Detect_overlap
..................... Auto_bin_max
..................... Cross_num_print_missing
..................... Per_instance
..................... Get_inst_coverage
............COVERAGE METHODS
............SYSTEM TASKS
............COVER PROPERTY
..................... Cover Property Results
..................... Cover Sequence Results
..................... Comparison Of Cover Property And Cover Group.
Search ✔
............PROPERTIES
..................... Overlap Implication
OpenVera ..................... Non Overlapping Implication
Constructs
Switch TB ............VERIFICATION DIRECTIVE
..................... Assert
RVM Switch TB ..................... Assume
RVM Ethernet sample ..................... Cover Statement
..................... Expect Statement
..................... Binding
Specman E
Interview Questions
Search ✔
............DISABLIE
..................... Disable Dpi-C Tasks And Functions
..................... Include Files
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
............TOGGLE COVERAGE
Specman E
Interview Questions ............FSM COVERAGE
..................... State Coverage
..................... Transition Coverage
............FUNCTIONAL COVERAGE
..................... Introduction To Functional Coverage
..................... Item
..................... Cross
..................... Transitional
..................... Assertion Coverage
............PHASES OF VERIFICATION
..................... Verification Plan
..................... Building Testbench
..................... Writing Tests
..................... Integrating Code Coverage
..................... Analyze Coverage
............VERIFICATION PLAN
..................... Verification Plan Contains The Following
..................... Overview
..................... Feature Extraction
..................... Resources, Budget And Schedule
..................... Verification Environment
..................... System Verilog Verification Flow
..................... Stimulus Generation Plan
..................... Checker Plan
..................... Coverage Plan
..................... Details Of Reusable Components
Search ✔
............UVM FACTORY
Verilog ..................... Registration
Verification ..................... Construction
..................... Overriding
Verilog Switch TB
Basic Constructs ............UVM SEQUENCE 1
..................... Introduction
..................... Sequence And Driver Communication
..................... Simple Example
OpenVera ..................... Sequence Item
Constructs ..................... Sequence
Switch TB ..................... Sequencer
..................... Driver
RVM Switch TB ..................... Driver And Sequencer Connectivity
RVM Ethernet sample ..................... Testcase
............UVM SEQUENCE 2
..................... Pre Defined Sequences
Specman E ..................... Sequence Action Macro
Interview Questions ..................... Example Of Pre_do,Mid_do And Post_do
..................... List Of Sequence Action Macros
..................... Examples With Sequence Action Macros
............UVM SEQUENCE 3
..................... Body Callbacks
..................... Hierarchical Sequences
..................... Sequential Sequences
..................... Parallel Sequences
............UVM SEQUENCE 4
............UVM SEQUENCE 5
..................... Sequencer Registration Macros
..................... Setting Sequence Members
............UVM SEQUENCE 6
..................... Exclusive Access
..................... Lock-Unlock
..................... Grab-Ungrab
............UVM TLM 1
..................... Port Based Data Transfer
..................... Task Based Data Transfer
..................... Operation Supported By Tlm Interface
..................... Methods
..................... Tlm Terminology
..................... Tlm Interface Compilation Models
..................... Interfaces
..................... Direction
..................... All Interfaces In Uvm
............UVM TLM 2
..................... Analysis
..................... Tlm Fifo
..................... Example
............UVM CALLBACK
..................... Driver And Driver Callback Class Source Code
..................... Testcase Source Code
..................... Testcase 2 Source Code
..................... Testcase 3 Source Code
..................... Testcase 4 Source Code
..................... Methods
..................... Macros
Search ✔
............VMM CALLBACK
Verilog ..................... Complete Source Code
Verification ..................... Testcase 1 Source Code
..................... Testcase 2 Source Code
Verilog Switch TB ..................... Testcase 3 Source Code
Basic Constructs ..................... Testcase 4 Source Code
............VMM TEST
..................... Writing A Testcase
OpenVera ..................... Example Of Using Vmm_test
Constructs
Switch TB ............VMM CHANNEL RECORD AND PLAYBACK
..................... Recording
RVM Switch TB ..................... Playing Back
RVM Ethernet sample
............VMM SCENARIO GENERATOR
..................... Example
..................... Scenario Code
Specman E ..................... Testcase
Interview Questions
............VMM OPTS
Search ✔
............OVM SEQUENCE 4
..................... Sequencer Arbitration
..................... Setting The Sequence Priority
............OVM SEQUENCE 5
..................... Sequencer Registration Macros
..................... Setting Sequence Members
............OVM SEQUENCE 6
..................... Exclusive Access
..................... Lock-Unlock
..................... Grab-Ungrab
............OVM CONFIGURATION
..................... Set_config_* Methods
..................... Automatic Configuration
..................... Manual Configurations
..................... Configuration Setting Members
Search ✔
............PHASE 8 COVERAGE
..................... Source Code Of Coverage Class
..................... Source Code Of The Scoreboard Class
............PHASE 9 TESTCASE
..................... Source Code Of Constraint Testcase
Search ✔
Search ✔
............PHASE 4 PACKET
Verilog ..................... Packet
Verification ..................... Test The Transaction Implementation
Verilog Switch TB ............PHASE 5 SEQUENCER N SEQUENCE
Basic Constructs ..................... Sequencer
..................... Sequence
............PHASE 6 DRIVER
OpenVera ..................... Driver
Constructs ..................... Environment Updates
Switch TB ..................... Testcase Updates
RVM Switch TB ............PHASE 7 RECEIVER
RVM Ethernet sample ..................... Receiver
..................... Environment Class Updates
............PHASE 8 SCOREBOARD
Specman E ..................... Scoreboard
Interview Questions ..................... Environment Class Updates
Search ✔
............PHASE 3 RESET
Verilog
Verification ............PHASE 4 PACKET
..................... Packet Class Source Code
Verilog Switch TB ..................... Program Block Source Code
Basic Constructs
............PHASE 5 GENERATOR
..................... Environment Class Source Code
OpenVera ............PHASE 6 DRIVER
Constructs ..................... Driver Class Source Code
Switch TB ..................... Environment Class Source Code
RVM Switch TB ............PHASE 7 RECEIVER
RVM Ethernet sample ..................... Receiver Class Source Code
..................... Environment Class Source Code
............PHASE 8 SCOREBOARD
Specman E ..................... Scoreboard Class Source Code
Interview Questions ..................... Source Code Of The Environment Class
............PHASE 9 COVERAGE
..................... Source Code Of Coverage Class
Search ✔
Verilog ............CONFIGURATION
Verification
............DRIVER
Verilog Switch TB
Basic Constructs ............RECIEVER
............SCOREBOARD
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
............STIMULUS GENERATION
............RACE CONDITION
..................... What Is Race Condition?
..................... Why Race Condition?
..................... When Race Is Visible?
..................... How To Prevent Race Condition?
..................... Types Of Race Condition
..................... Write-Write Race
..................... Read-Write Race
..................... More Race Example
..................... Event Terminology
..................... The Stratified Event Queue
..................... Determinism
..................... Nondeterminism
..................... Guideline To Avoid Race Condition
..................... Avoid Race Between Testbench And Dut
............CHECKER
..................... Protocol Checker
..................... Data_checker
..................... Modularization
............PROCESS CONTROL
..................... Nonblocking Task
..................... Fork/Join Recap
..................... Fork/Join None
..................... Fork/Join Any
............WATCHDOG
............DEBUGGING
..................... Pass Or Fail
..................... Waveform Viewer
..................... Log File
..................... Message Control System
..................... Message Severity Levels
..................... Message Controlling Levels
..................... Passing Comments To Waveform Debugger
..................... $Display N $Strobe
..................... Who Should Do The Rtl Debugging?
............TESTING STRATIGIES
..................... Bottom-Up
..................... Unit Level
..................... Sub-Asic Level
..................... Asic Level
..................... System Level
..................... Flat
............FILE HANDLING
..................... Fopen And Fclose
..................... Fdisplay
..................... Fmonitor
..................... Fwrite
..................... Mcd
..................... Formating Data To String
............VERILOG SEMAPHORE
..................... Semaphore In Verilog
............FINDING TESTSENARIOUS
..................... Register Tests
..................... System Tests
..................... Interrupt Tests
..................... Interface Tests
..................... Functional Tests
..................... Error Tests
..................... Golden Tests
..................... Performance Tests
............TERIMINATION
............ERROR INJUCTION
..................... Value Errors
..................... Temporal Errors
..................... Interface Error
..................... Sequence Errors
............REGISTER VERIFICATION
..................... Register Verification
..................... Register Classification
..................... Features
............PARAMETERISED MACROS
............REGRESSION
............TIPS
..................... How To Avoid "Module Xxx Already Defined" Error
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
............CONTROL CONSTRUCTS
..................... If And If Else Statements
OpenVera ..................... Case
Constructs ..................... Forever
Switch TB ..................... Repeat
..................... While
RVM Switch TB ..................... For
RVM Ethernet sample
............PROCEDURAL TIMING CONTROLS
..................... Delay Control
..................... Event Control
Specman E ..................... Named Events
Interview Questions
............STRUCTURE
..................... Module
..................... Ports
..................... Signals
............BLOCK STATEMENTS
..................... Sequential Blocks
..................... Parallel Blocks
............STRUCTURED PROCEDURES
..................... Initial
..................... Always
..................... Functions
..................... Task
Search ✔
............CONTROL STATEMENTS
..................... Sequential Statements
............INTERPROCESS
..................... Interprocess Synchronization And Communication
............FORK JOIN
..................... Fork Join
............SHADOW VARIABLES
..................... Shadow Variables
............WAIT VAR
..................... Wait_var
............EVENT SYNC
..................... Event Methods
............EVENT TRIGGER
..................... Event Trigger
..................... Event Variables
............SEMAPHORE
..................... Semaphore
............REGIONS
..................... Regions
............MAILBOX
..................... Mailbox
............TIMEOUTS
..................... Timeouts
............OOP
..................... Object Oriented Programming
..................... Properties
..................... This
..................... Class Extensions
..................... Polymorphism
..................... Super
..................... Abstract Class
............CASTING
............RANDOMIZATION
..................... Constrained Random Verification
..................... Random Varible Declaration
..................... Rand Modifier
..................... Randc Modifier
............RANDOMIZATION METHODS
..................... Randomization Built-In Methods
..................... Randomize()
..................... Pre_randomize And Post_randomize
............CONSTRAINT BLOCK
..................... Constraint Block
..................... Inline Constraints
..................... Disabling Constraint Block
............CONSTRAINT EXPRESSION
..................... Constraint Expressions
..................... Set Membership
..................... Weighted Distribution
..................... Implication
..................... If..Else
..................... Iterative
............VARIABLE ORDARING
..................... Variable Ordaring
............AOP
..................... Aspect Oriented Extensions
............PREDEFINED METHODS
..................... Predefined Methods
..................... New()
..................... Finalize()
..................... Object_print
..................... Deep Object Compare
..................... Deep Object Copy
..................... Pack And Unpack
............STRING METHODS
............QUEUE METHODS
............DUT COMMUNICATION
..................... Connecting To Hdl
..................... Interface Declaration
..................... Direct Hdl Node Connection
..................... Blocking And Non-Blocking Drives
............FUNCTIONAL COVERAGE
..................... Functional Coverage
..................... Coverage Group
..................... Sample_event
..................... Coverage_point
..................... Cross Coverage
Search ✔
Verilog ............ENV
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog ............SCOREBOARD
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
TUTORIALS
SystemVerilog
Verification
Constructs UVM/OVM Killing Sequences on Sequencer Abruptly by Vishnu Prashant.
Interface Sometimes you may need to drive input until you see come condition or some timer expires. Read ...
OOPS
Randomization
Do not rely on illegal_bins for checking purpose. by Ankit Gopani.
Functional Coverage If you rely on cover group where you have written illegal_bins,
Assertion what happens when you turn off the coverage?? Read ...
DPI
UVM Tutorial
PASS and FAIL Messages with Colors...! by Ankit Gopani.
VMM Tutorial How many among you know that you can actually display color messages using Verilog and SystemVerilog? Read ...
OVM Tutorial
Easy Labs : SV
Easy Labs : UVM VMM 1.2 and VMM_sb_ds example by Ankit Shah.
Easy Labs : VMM
This example contains VMM 1.2 based layered testbench architeracture. My intensation here is to demonstrate
different component of testbench using different base class of VMM. Read ...
Easy Labs : OVM
AVM Switch TB
VMM Ethernet sample Whats new in Systemverilog 2009 ? by Ankit Shah.
The SystemVerilog working group worked hard in the past four years on improving the language and in 2009
Systemverilog LRM was released. There are 30+ noticeable new constructs and 25+ system task are introduced in
Verilog SystemVerilog 2009. Read ...
Verification
Verilog Switch TB
Basic Constructs
Introduction To Ethernet Frames: Part 1 by Bhavani shankar.
The Ethernet protocol basically implements the bottom two layers of the Open Systems Interconnection (OSI) 7-
layer model, i.e., the data link and physical sub layers. Read ...
OpenVera
Constructs
Introduction To Ethernet Frames: Part 2 by Bhavani shankar.
Switch TB we will see a simple testplan for 10G Ethernet Frames. Read ...
RVM Switch TB
RVM Ethernet sample
Introduction To PCI Express by Arjun Shetty.
We will start with a conceptual understanding of PCI Express. This will let us appreciate the importance of PCI
Specman E Express. This will be followed by a brief study of the PCI Express protocol. Then we will look at the enhancements
and improvements of the protocol in the newer 3.0 specs. Read ...
Interview Questions
Soft skills are extremely important for the people in Verification and this is something that is often found to be
neglected by the upcoming Verification engineers. Read ...
testbench.in was started in June 2007. This website gets 1,00,000 page visits per month.
If you are interested in sharing your knowledge and get noticed in VLSI WORLD, we are happy to host your thoughts.
If you are interested, please drop us a mail at feedback@testbench.in .
Search ✔
............EXTEND
Specman E ..................... Is Also
Interview Questions ..................... Is First
..................... Is Only
............EVENTS
............TEMPORAL EXPRESSIONS
..................... Basic Temporal Expressions
............Temporal operators 1
..................... Not
..................... Fail
..................... And
..................... Or
..................... { Exp ; Exp }
..................... Eventually
..................... [ Exp ]
..................... [ Exp..Exp ]
..................... ~[ Exp..Exp ]
..................... Temporal Yield Operator
............TEMPORAL OPERATORS 2
..................... Detach
..................... Delay
..................... @ Unary Event Operator
..................... @ Sampling Operator
..................... Cycle
..................... True(Exp)
..................... Change(Exp), Fall(Exp), Rise(Exp)
..................... Consume
..................... Exec
............PACKING N UNPACKING
..................... Packing.High
..................... Packing.Low
............COVERAGE
..................... Coverage Groups
..................... Cover Group Options
..................... Cross-Coverage
............COMMANDS
............Extendable Methods
Search ✔
Search ✔
Search ✔
TUTORIALS
SystemVerilog
Verification
Gopikrishna
Constructs
Interface He is working with Infinera as Verification Engineer. He has 4 years of experience as ASIC Design Verification
Engineer. Prior to Infinera, he worked with Synopsys,Axiom Design Automation,Syschip and Ample Communication.
OOPS He is expertise in various Hardware verification languages and methodologies. He has experience in Verification of
Randomization Ethernet,PCI Express,I2C and Interlaken.
He is an M.Tech in VLSI Design From Sathyabama University, Chennai.
Functional Coverage
Assertion You can reach him at: gopi@testbench.in
Connect to Gopi @ Linkedin : http://in.linkedin.com/in/systemverilog
DPI
UVM Tutorial Naresh
VMM Tutorial You can reach him at: naresh@testbench.in
OVM Tutorial
Easy Labs : SV
Easy Labs : UVM
Easy Labs : OVM
Easy Labs : VMM
AVM Switch TB
VMM Ethernet sample
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
TUTORIALS
SystemVerilog
Verification
We would like to express our gratitude to all those who gave us their great support to complete this website.
Constructs
Interface Special thanks to Mr. Vishnu Prasanth and Mr. Ankit J Shah for their valuble time in reviewing the contents of this
site.
OOPS
Randomization Vishnu is currently working with Vitesse, Hyderabad, India and Ankit is currently working with Sibridge Technologies
Pvt. Ltd, Ahmedabad,India .
Functional Coverage
Assertion
DPI
UVM Tutorial
VMM Tutorial
OVM Tutorial
Easy Labs : SV
Easy Labs : UMM
Easy Labs : VMM
Easy Labs : OVM
AVM Switch TB
VMM Ethernet sample
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
TUTORIALS
SystemVerilog
Verification
Hi Readers,
Constructs
Interface We are continuously working on this site. Since the collection is vast and lot of hard work goes in summing and
providing you the latest and correct information. We sincerely apologize for any typo error if you may come across.
OOPS Very religiously we are trying to improve the quality of the contents and we will really appreciate your suggestions
Randomization and comments. We welcome all innovative ideas and thoughts. Do write to us. You can reach us at
feedback@testbench.in .
Functional Coverage
Assertion
Happy Reading. Life is Good, keep smiling :)
DPI
UVM Tutorial Cheers,
TestBencher Team
VMM Tutorial
OVM Tutorial What People are saying about this Site
Easy Labs : SV
Easy Labs : UVM
Feedback form
Easy Labs : OVM
Easy Labs : VMM
* Required
AVM Switch TB
VMM Ethernet sample Your Email ID *
Verilog
Verification
Comments *
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Submit
Specman E
Powered by Google Docs
Interview Questions
Report Abuse - Terms of Service - Additional Terms
Search ✔
TABLE OF CONTENTS
............SystemVerilog Verification -- HOW TO CHECK WHETHER THE TESTBENCH HAS SATISFACTORILY EXERCISED THE DESIGN
............SystemVerilog Verification -- MAKE YOUR GOAL 100 PERCENT CODE COVERAGE NOTHING LESS
..................... Dont Be Fooled By The Code Coverage Report
..................... When To Stop Testing?
..................... Item
..................... Cross
..................... Transitional
..................... Assertion Coverage
..................... Comparison.
..................... Concatenation.
..................... Replication.
..................... Indexing.
............Specman E -- INTRODUCTION
............Specman E -- E BASICS
..................... Code Segments
..................... Comments
..................... Literals And Constants
..................... Sized Numbers
..................... Predeï¬Ned Constants
............Specman E -- OPERATORS
..................... Unary Bitwise Operators
..................... Binary Bitwise Operations
..................... Shift Operators
..................... Boolean Operators
..................... Arithmetic Operators
..................... Comparison Operators
..................... Extraction And Concatenation Operators
..................... Special-Purpose Operators
............Specman E -- STRUCT
............Specman E -- UNITS
..................... Units Vs Structs
............Specman E -- LIST
..................... Regular List
..................... List Operations
..................... Keyed List
............Specman E -- METHODS
..................... Time-Consuming Methods(Tcms)
..................... Invoking Tcms
..................... Execution Flow
............Specman E -- CONSTRAINTS
............Specman E -- EXTEND
..................... Is Also
..................... Is First
..................... Is Only
............Specman E -- EVENTS
............Specman E -- COVERAGE
..................... Coverage Groups
..................... Cover Group Options
..................... Cross-Coverage
............Specman E -- COMMANDS
Report a Bug or Comment on This section - Your input is what keeps Testbench.in improving with time!
Search ✔
SV methodologies
OpenVera
Constructs VMM
Switch TB AVM
RVM Switch TB Truss & Teal
RVM Ethernet sample
OVM
Specman E If you wanna see your blog/site in the above list, Please submit the details in below form
Interview Questions
Send Details about your site.
* Required
Your name
Your Email ID *
Description *
Submit
Search ✔
TUTORIALS
Specman E
Amazing effort. Very useful material.
Interview Questions
- Lakshman , MindTree
I find this website a valuable resource for the beginners to have a good jumpstart. I
would fully recommend this website to someone who wants to get a good starting
point in verification. The Website is good in texts,its explanations and illustrative
examples.
Good job ..Keep it up
- Emma , TI
Really very good site. Appreciate your continuous effort to show/share verification
world through your experience, indepth analysis with simple example.
You did a good job. This tutorial give a quick start for VMM and is easy to handle.
You can only feel like a Verification Engineer after visiting this site.
You have done a great job in your site www.testbench.in. Your materials are very
good.
You are maintaining a awesome site testbench.in with lots of useful material with
good example.
Besides, I would like to thank the development team for the great efforts made to
produce this wonderful site with detailed explanation, enabling us to learn and master
the hot in the market verificaton methodologies.
- Arun
Your site is very Useful in learning the important concepts in that. I would like to
appreciate your contribution for that.
This website is very informative and you guys have put a lot of effort in building
this...Keep up the good work and good luck.
- Santhosh , Mindspeed
- Nesan , Flowgicindia
My heartfelt congratulations for creating such a wonderful site with loads of useful
and quickly understandable information for professionals and beginners in the Chip
Verification domain.
I have been following your website testbech.in for some time, it has good resources.
One think I like about it is that it continues evolve, maintained well and is up to date.
Great work.
I just found your site and was very impressed with the depth of testbench topics that
you covered.
Just wanted to congratulate you on your website. I have been a verification engineer
for 8 years and have never found a site as useful as this one.
Very good site you made , the site is very well organized and very informative.
Thanks for providing so much information on System verilog and other topics you
included.
- Shankar , Freescale
Search ✔
TUTORIALS
OpenVera Openvera
Constructs This section covers the basics of Openvera with lots of examples and simulated results
to analyze deeply.
Switch TB
RVM Switch TB Verilog For Verification
Newbies in the world of verification are missing a place where they can learn
RVM Ethernet sample verification theory along with practical examples. All the examples are discussed in
Verilog. Most of them are applicable to other languages also.
Easy Labs
These labs takes you through the complete cycle of a simple switch
verification. These lab starts with creating test plan and ends with achieving
coverage goal. These labs are divided in to multiple phases and each phase
has a lab files which can be download. Unlike other labs, where user can only
simulates the environment after developing the complete environment, In
these labs, in every phase, user can simulate the environment and analyze the
implementation of that phase .
Simple Labs
These Labs are very simple and dry. User can download the labs and simulate
them.
Interview Questions
You can find Interview questions on Verification concepts, Verilog, Systemverilog,
SVA, Specman, STA and DFT.
Search ✔
TUTORIALS
SystemVerilog We don't make any claims, promises or guarantees about the accuracy, completeness, or adequacy of the contents
Verification of this website.
Constructs All the source code and tutorials are to be used on your own risk.
Interface
All trademarks are property of their respective owners.
OOPS
Randomization The content on this site is our own and not relates ,in any way, to organizations we work for.
Functional Coverage
Assertion
DPI
UVM Tutorial
VMM Tutorial
OVM Tutorial
Easy Labs : SV
Easy Labs : UVM
Easy Labs : OVM
Easy Labs : VMM
AVM Switch TB
VMM Ethernet sample
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions TIP : If you don't need the x and z values then use the SystemVerilog int and bit types
which make execution faster.
Integer types use integer arithmetic and can be signed or unsigned.The data types
byte, shortint, int, integer, and longint default to signed. The data types bit, reg, and
logic default to unsigned, as do arrays of these types.
int unsigned ui;
int signed si
byte unsigned ubyte;
Void :
The void data type represents nonexistent data. This type can be specified as the
return type of functions to indicate no return value.
void = function_call();
Search ✔
EXAMPLE
typedef struct {int a; shortreal b;} ab;
ab c;
c = '{0, 0.0}; // structure literal type determined from
// the left-hand context (c)
The C-like alternative '{1, 1.0, 2, 2.0} for the preceding example is not allowed.
Search ✔
endmodule
RESULTS :
5
test
BENCH
-18
-32
ST
111
Use the following method for pattern matching in SystemVerilog. Match method which
is in OpenVera or C , is not available in SystemVerilog . For using match method which
is in C , use the DPI calls . For native SystemVerilog string match method, hear is the
example.
CODE:
function match(string s1,s2);
int l1,l2;
l1 = s1.len();
l2 = s2.len();
match = 0 ;
if( l2 > l1 )
return 0;
for(int i = 0;i < l1 - l2 + 1; i ++)
if( s1.substr(i,i+l2 -1) == s2)
return 1;
endfunction
EXAMPLE:
program main;
string str1,str2;
int i;
initial
begin
str1 = "this is first string";
str2 = "this";
if(match(str1,str2))
$display(" str2 : %s : found in :%s:",str2,str1);
RESULTS:
String Operators
Equality
Checks whether the two strings are equal. Result is 1 if they are equal and 0 if they
are not. Both strings can be of type string. Or one of them can be a string literal. If
both operands are string literals, the operator is the same Verilog equality operator as
for integer types.
EXAMPLE
program main;
initial
begin
string str1,str2,str3;
str1 = "TEST BENCH";
str2 = "TEST BENCH";
str3 = "test bench";
if(str1 == str2)
$display(" Str1 and str2 are equal");
else
$display(" Str1 and str2 are not equal");
if(str1 == str3)
$display(" Str1 and str3 are equal");
else
$display(" Str1 and str3 are not equal");
end
endprogram
RESULT
Inequality.
Logical negation of Equality operator. Result is 0 if they are equal and 1 if they are
not. Both strings can be of type string. Or one of them can be a string literal. If both
operands are string literals, the operator is the same Verilog equality operator as for
integer types.
EXAMPLE
program main;
initial
begin
string str1,str2,str3;
str1 = "TEST BENCH";
str2 = "TEST BENCH";
str3 = "test bench";
if(str1 != str2)
$display(" Str1 and str2 are not equal");
else
$display(" Str1 and str2 are equal");
if(str1 != str3)
$display(" Str1 and str3 are not equal");
else
$display(" Str1 and str3 are equal");
end
endprogram
RESULT
Comparison.
Syntax:
Str1 < Str2
Str1 <= Str2
Str1 > Str2
Str1 >= Str2
EXAMPLE
program main;
initial
begin
string Str1,Str2,Str3;
Str1 = "c";
Str2 = "d";
Str3 = "e";
if(Str1 < Str2)
$display(" Str1 < Str2 ");
if(Str1 <= Str2)
$display(" Str1 <= Str2 ");
if(Str3 > Str2)
$display(" Str3 > Str2");
if(Str3 >= Str2)
$display(" Str3 >= Str2");
end
endprogram
RESULT
Concatenation.
Syntax: {Str1,Str2,...,Strn}
Each operand can be of type string or a string literal (it shall be implicitly converted
to type string). If at least one operand is of type string, then the expression evaluates
to the concatenated string and is of type string. If all the operands are string literals,
then the expression behaves like a Verilog concatenation of integral types; if the
result is then used in an expression involving string types, it is implicitly converted to
the string type.
EXAMPLE
program main;
initial
begin
string Str1,Str2,Str3,Str4,Str5;
Str1 = "WWW.";
Str2 = "TEST";
Str3 = "";
Str4 = "BENCH";
Str5 = ".IN";
$display(" %s ",{Str1,Str2,Str3,Str4,Str5});
end
endprogram
RESULT
WWW.TESTBENCH.IN
Replication.
Syntax : {multiplier{Str}}
Str can be of type string or a string literal. Multiplier must be of integral type and can
be nonconstant. If multiplier is nonconstant or Str is of type string, the result is a
string containing N concatenated copies of Str, where N is specified by the multiplier.
If Str is a literal and the multiplier is constant, the expression behaves like numeric
replication in Verilog (if the result is used in another expression involving string types,
it is implicitly converted to the string type).
EXAMPLE
program main;
initial
begin
string Str1,Str2;
Str1 = "W";
Str2 = ".TESTBENCH.IN";
$display(" %s ",{{3{Str1}},Str2});
end
endprogram
RESULT
WWW.TESTBENCH.IN
Indexing.
Syntax: Str[index]
Returns a byte, the ASCII code at the given index. Indexes range from 0 to N-1, where
N is the number of characters in the string. If given an index out of range, returns 0.
Semantically equivalent to Str.getc(index)
EXAMPLE
program main;
initial
begin
string Str1;
Str1 = "WWW.TESTBENCH.IN";
for(int i =0 ;i < 16 ; i++)
$write("%s ",Str1[i]);
end
endprogram
RESULT
WWW.TESTBENCH.IN
Search ✔
Specman E
Interview Questions
Search ✔
The first() method returns the value of the first member of the enumeration.
Specman E The last() method returns the value of the last member of the enumeration.
Interview Questions
The next() method returns the Nth next enumeration value (default is the next one)
starting from the current value of the given variable.
The prev() method returns the Nth previous enumeration value (default is the
previous one) starting from the current value of the given variable.
The name() method returns the string representation of the given enumeration value.
If the given value is not a member of the enumeration, the name() method returns the
empty string.
RESULTS :
red
blue
green
blue
EXAMPLE:
module enum_method;
typedef enum {red,blue,green} colour;
colour c,d;
int i;
initial
begin
$display("%s",c.name());
d = c;
$display("%s",d.name());
d = colour'(c + 1); // use casting
$display("%s",d.name());
i = d; // automatic casting
$display("%0d",i);
c = colour'(i);
$display("%s",c.name());
end
endmodule
RESULT
red
red
blue
1
blue
TIP: If you want to use X or Z as enum values, then define it using 4-state data type
explicitly.
enum integer {IDLE, XX='x, S1='b01, S2='b10} state, next;
Search ✔
Packed Structures:
For example
reg [0:47] my_data;
`define a_indx 16:47
`define b_indx 8:15
`define c_indx 0:7
my_data[`b_indx] = 8'b10; // writing to subfield b
$display(" %d ",my_data[`a_indx]); // reading subfield a
A packed structure is a mechanism for subdividing a vector into subfields that can be
conveniently accessed as members. Consequently, a packed structure consists of bit
fields, which are packed together in memory without gaps. A packed struct or union
type must be declared explicitly using keyword "packed".
struct packed {
integer a;
byte b;
bit [0:7] c;
} my_data;
my_data.b = 8'b10;
$display("%d", my_data.a);
One or more bits of a packed structure can be selected as if it were a packed array,
assuming an [n-1:0] numbering:
My_data [15:8] // b
If all members of packed structure are 2-state, the structure as a whole is treated as
a 2-state vector.
If all members of packed structure is 4-state, the structure as a whole is treated as a
4-state vector.
If there are also 2-state members, there is an implicit conversion from 4-state to 2-
state when reading those members, and from 2-state to 4-state when writing them.
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Operations On Arrays
In a list of multi dimensions, the rightmost one varies most rapidly than the left most
one. Packed dimension varies more rapidly than an unpacked.
In the following example, each dimension is having unique range and reading and
writing to a element shows exactly which index corresponds to which dimension.
module index();
bit [1:5][10:16] foo [21:27][31:38];
initial
begin
foo[24][34][4][14] = 1;
$display(" foo[24][34][4][14] is %d ",foo[24][34][4][14] );
end
endmodule
The result of reading from an array with an out of the address bounds or if any bit in
the address is X or Z shall return the default uninitialized value for the array element
type.
module array();
bit [1:5][10:16] foo1 [21:27][31:38],foo2 [31:27][33:38];
initial
begin
$display(" dimensions of foo1 is %d foo2 is
%d",$dimensions(foo1),$dimensions(foo2) );
$display(" reading with out of bound resulted %d",foo1[100][100][100][100]);
$display(" reading with index x resulted %d",foo1[33][1'bx]);
end
endmodule
RESULT:
bit [3:4][5:6]Array [0:2];
Search ✔
$dimensions
Specman E
$dimensions shall return the total number of dimensions in the array.
Interview Questions
EXAMPLE : arrays
module arr;
bit [2:0][3:0] arr [4:0][5:0];
initial
begin
$display(" $left %0d $right %0d $low %0d $high %0d $increment %0d $size %0d
$dimensions
%0d",$left(arr),$right(arr),$low(arr),$high(arr),$increment(arr),$size(arr),$dimensions(arr)
);
end
endmodule
RESULTS :
Array locator methods operate on any unpacked array, including queues, but their
return type is a queue. These locator methods allow searching an array for elements
(or their indexes) that satisfies a given expression. Array locator methods traverse the
array in an unspecified order. The optional "with" expression should not include any
side effects; if it does, the results are unpredictable.
The following locator methods are supported (the "with" clause is mandatory) :
find()
find_index()
find_index() returns the indexes of all the elements satisfying the given expression
find_first()
find_first_index()
find_first_index() returns the index of the first element satisfying the given expression
find_last()
find_last_index()
find_last_index() returns the index of the last element satisfying the given expression
For the following locator methods the "with" clause (and its expression) can be
omitted if the relational operators (<, >, ==) are defined for the element type of the
given array. If a "with" clause is specified, the relational operators (<, >, ==) must be
defined for the type of the expression.
min()
min() returns the element with the minimum value or whose expression evaluates to a
minimum
max()
max() returns the element with the maximum value or whose expression evaluates to
a maximum
unique()
unique() returns all elements with unique values or whose expression is unique
unique_index()
unique_index() returns the indexes of all elements with unique values or whose
expression is unique
EXAMPLE :
module arr_me;
string SA[10], qs[$];
int IA[*], qi[$];
initial
begin
SA[1:5] ={"Bob","Abc","Bob","Henry","John"};
IA[2]=3;
IA[3]=13;
IA[5]=43;
IA[8]=36;
IA[55]=237;
IA[28]=39;
// Find all items greater than 5
qi = IA.find( x ) with ( x > 5 );
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] );
$display("");
// Find indexes of all items equal to 3
qi = IA.find_index with ( item == 3 );
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] );
$display("");
// Find first item equal to Bob
qs = SA.find_first with ( item == "Bob" );
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] );
$display("");
// Find last item equal to Henry
qs = SA.find_last( y ) with ( y == "Henry" );
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] );
$display("");
// Find index of last item greater than Z
qi = SA.find_last_index( s ) with ( s > "Z" );
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] );
$display("");
// Find smallest item
qi = IA.min;
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] );
$display("");
// Find string with largest numerical value
qs = SA.max with ( item.atoi );
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] );
$display("");
// Find all unique strings elements
qs = SA.unique;
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] );
$display("");
// Find all unique strings in lowercase
qs = SA.unique( s ) with ( s.tolower );
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] );
end
endmodule
RESULTS :
13_43_36_39_237_
2_
Bob_
Henry_
3_
_
_Bob_Abc_Henry_John_
_Bob_Abc_Henry_John_
reverse()
sort()
sort() sorts the unpacked array in ascending order, optionally using the expression in
the with clause.
rsort()
rsort() sorts the unpacked array in descending order, optionally using the with clause
expression.
shuffle()
EXAMPLE:
module arr_order; string s[] = '{ "one", "two", "three" };
initial
begin
s.reverse;
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] );
s.sort;
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] );
s.rsort;
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] );
s.shuffle;
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] );
end
endmodule
RESULT:
Array reduction methods can be applied to any unpacked array to reduce the array to
a single value. The expression within the optional "with" clause can be used to specify
the item to use in the reduction. The following reduction methods are supported:
sum()
product()
and()
and() returns the bit-wise AND ( & ) of all the array elements.
or()
xor()
EXAMPLE:
module array_redu();
byte b[] = { 1, 2, 3, 4 };
int sum,product,b_xor;
initial
begin
sum = b.sum ; // y becomes 10 => 1 + 2 + 3 + 4
product = b.product ; // y becomes 24 => 1 * 2 * 3 * 4
b_xor = b.xor with ( item + 4 ); // y becomes 12 => 5 ^ 6 ^ 7 ^ 8
$display(" Sum is %0d, product is %0d, xor is %0b ",sum,product,b_xor);
end
endmodule
RESULT
The expressions used by array manipulation methods sometimes need the actual array
indexes at each iteration, not just the array element. The index method of an iterator
returns the index value of the specified dimension.
Search ✔
RESULT
4
8
0
The information about the size of the dynamic array is with the array itself. It can be
obtained using .size() method. This will be very helpful when you are playing with
array. You don't need to pass the size information explicitly. We can also use system
task $size() method instead of .size() method. SystemVerilog also provides delete()
method clears all the elements yielding an empty array (zero size).
Search ✔
The num() or size() method returns the number of entries in the associative array.
The delete() method removes the entry at the specified index.
Specman E The exists() function checks whether an element exists at the specified index within
Interview Questions the given array.
The first() method assigns to the given index variable the value of the first (smallest)
index in the associative array. It returns 0 if the array is empty; otherwise, it returns
1.
The last() method assigns to the given index variable the value of the last (largest)
index in the associative array. It returns 0 if the array is empty; otherwise, it returns
1.
The next() method finds the entry whose index is greater than the given index. If
there is a next entry, the index variable is assigned the index of the next entry, and
the function returns 1. Otherwise, the index is unchanged, and the function returns 0.
The prev() function finds the entry whose index is smaller than the given index. If
there is a previous entry, the index variable is assigned the index of the previous
entry, and the function returns 1. Otherwise, the index is unchanged, and the
function returns 0.
EXAMPLE
module assoc_arr;
int temp,imem[*];
initial
begin
imem[ 2'd3 ] = 1;
imem[ 16'hffff ] = 2;
imem[ 4'b1000 ] = 3;
$display( "%0d entries", imem.num );
if(imem.exists( 4'b1000) )
$display("imem.exists( 4b'1000) ");
imem.delete(4'b1000);
if(imem.exists( 4'b1000) )
$display(" imem.exists( 4b'1000) ");
else
$display(" ( 4b'1000) not existing");
if(imem.first(temp))
$display(" First entry is at index %0db ",temp);
if(imem.next(temp))
$display(" Next entry is at index %0h after the index 3",temp);
// To print all the elements alone with its indexs
if (imem.first(temp) )
do
$display( "%d : %d", temp, imem[temp] );
while ( imem.next(temp) );
end
endmodule
RESULT
3 entries
imem.exists( 4b'1000)
( 4b'1000) not existing
First entry is at index 3b
Next entry is at index ffff after the index 3
3 : 1
65535 : 2
Search ✔
Specman E
Interview Questions EXAMPLE
module queues;
byte qu [$] ;
initial
begin
qu.push_front(2);
qu.push_front(12);
qu.push_front(22);
qu.push_back(11);
qu.push_back(99);
$display(" %d ",qu.size() );
$display(" %d ",qu.pop_front() );
$display(" %d ",qu.pop_back() );
qu.delete(3);
$display(" %d ",qu.size() );
end
endmodule
RESULTS :
5
22
99
EXAMPLE:
module top;
typedef int qint_t[$];
// dynamic array of queues
qint_t DAq[]; // same as int DAq[][$];
// queue of queues
qint_t Qq[$]; // same as int Qq[$][$];
// associative array of queues
qint_t AAq[string]; // same as int AAq[string][$];
initial begin
// Dynamic array of 4 queues
DAq = new[4];
// Push something onto one of the queues
DAq[2].push_back(1);
// initialize another queue with three entries
DAq[0] = {1,2,3};
$display("%p",DAq);
// Queue of queues -two
Qq= {{1,2},{3,4,5}};
Qq.push_back(qint_t'{6,7});
Qq[2].push_back(1);
$display("%p",Qq);
// Associative array of queues
AAq["one"] = {};
AAq["two"] = {1,2,3,4};
AAq["one"].push_back(5);
$display("%p",AAq);
end
endmodule : top
RESULTS:
Search ✔
Specman E
Interview Questions
Search ✔
List_iterator Methods
The List_Iterator class provides methods to iterate over the elements of lists.
The next() method changes the iterator so that it refers to the next element in the
list.
The prev() method changes the iterator so that it refers to the previous element in
the list.
The eq() method compares two iterators and returns 1 if both iterators refer to the
same list element.
The neq() method is the negation of eq().
The data() method returns the data stored in the element at the given iterator
location.
List Methods
The List class provides methods to query the size of the list; obtain iterators to the
head or tail of the list;
retrieve the data stored in the list; and methods to add, remove, and reorder the
elements of the list.
The size() method returns the number of elements stored in the list.
The empty() method returns 1 if the number elements stored in the list is zero and 0
otherwise.
The push_front() method inserts the specified value at the front of the list.
The push_back() method inserts the specified value at the end of the list.
The front() method returns the data stored in the first element of the list.
The back() method returns the data stored in the last element of the list.
The pop_front() method removes the first element of the list.
The pop_back() method removes the last element of the list.
The start() method returns an iterator to the position of the first element in the list.
The finish() method returns an iterator to a position just past the last element in the
list.
The insert() method inserts the given data into the list at the position specified by the
iterator.
The insert_range() method inserts the elements contained in the list range specified
by the iterators first and last at the specified list position.
The erase() method removes from the list the element at the specified position.
The erase_range() method removes from a list the range of elements specified by the
first and last iterators.
The set() method assigns to the list object the elements that lie in the range specified
by the first and last iterators.
The swap() method exchanges the contents of two equal-size lists.
The clear() method removes all the elements from a list, but not the list itself.
The purge() method removes all the list elements (as in clear) and the list itself.
EXAMPLE
module lists();
List#(integer) List1;
List_Iterator#(integer) itor;
initial begin
List1 = new();
$display (" size of list is %d \n",List1.size());
List1.push_back(10);
List1.push_front(22);
$display (" size of list is %d \n",List1.size());
$display (" poping from list : %d \n",List1.front());
$display (" poping from list : %d \n",List1.front());
List1.pop_front();
List1.pop_front();
$display (" size of list is %d \n",List1.size());
List1.push_back(5);
List1.push_back(55);
List1.push_back(555);
List1.push_back(5555);
$display (" size of list is %d \n",List1.size());
itor = List1.start();
$display (" startn of list %d \n",itor.data());
itor.next();
$display (" second element of list is %d \n",itor.data());
itor.next();
$display (" third element of list is %d \n",itor.data());
itor.next();
$display (" fourth element of list is %d \n",itor.data());
itor = List1.erase(itor);
$display (" after erasing element,the itor element of list is %d \n",itor.data());
itor.prev();
$display(" prevoious element is %d \n",itor.data());
end
endmodule
RESULT:
size of list is 0
size of list is 2
poping from list : 22
poping from list : 22
size of list is 0
size of list is 4
startn of list 5
second element of list is 55
third element of list is 555
fourth element of list is 5555
after erasing element,the itor element of list is x
prevoious element is 555
Search ✔
EXAMPLE:
module enum_method;
typedef enum {red,blue,green} colour;
colour c,d;
int i;
initial
begin
d = (c + 1);
end
endmodule
RESULT
Illegal assignment
Following example shows the simulation error. This is compilation error free. In this
example , d is assigned c + 10 , which is out of bound in enum colour.
EXAMPLE:
module enum_method;
typedef enum {red,blue,green} colour;
colour c,d;
int i;
initial
begin
$cast(d,c + 10);
end
endmodule
RESULT
Search ✔
This example strips out the least and most significant bytes from a four byte bus:
Specman E
Interview Questions module byte_rip (inout wire [31:0] W, inout wire [7:0] LSB, MSB);
alias W[7:0] = LSB;
alias W[31:24] = MSB;
endmodule
Verilog restricts the data types that can be connected to module ports. Only net types
are allowed on the receiving side and Nets, regs or integers on the driving side.
SystemVerilog removes all restrictions on port connections. Any data type can be
used on either side of the port. Real numbers, Arrays, Structures can also be passed
through ports.
module foo #(parameter type VAR_TYPE = integer);
integer i = 1;
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Assignment Operators
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, <<<=,>>>=.
For example:
Following are the new SystemVerilog assignment operators and its equivalent in
verilog
Assignments In Expression
EXAMPLE
module assignment();
int a,b,c;
initial begin
a = 1; b =2;c =3;
if((a=b))
$display(" a value is %d ",a);
a = (b = (c = 5));
$display(" a is %d b is %d c is %d ",a,b,c);
end
endmodule
RESULT
a value is 2
a is 5 b is 5 c is 5
Concatenation :
EXAMPLE :Concatenation
program main ;
bit [4:0] a;
reg b,c,d;
initial begin
b = 0;
c = 1;
d = 1;
a = {b,c,0,0,d};
{b,c,d} = 3'b111;
$display(" a %b b %b c %b d %b ",a,b,c,d);
end
endprogram
RESULTS
a 00001 b 1 c 1 d 1
Arithmetic:
EXAMPLE :Arithmetic
program main;
integer a,b;
initial
begin
b = 10;
a = 22;
$display(" -(nagetion) is %0d ",-(a) );
$display(" a + b is %0d ",a+b);
$display(" a - b is %0d ",a-b);
$display(" a * b is %0d ",a*b);
$display(" a / b is %0d ",a/b);
$display(" a modulus b is %0d ",a%b);
end
endprogram
RESULTS
-(nagetion) is -22
a + b is 32
a - b is 12
a * b is 220
a / b is 2
a modules b is 2
Following tabel shows the opwer operator rules for calculating the result.
program main;
integer op1_neg,op1_n1,op1_0,op1_p1,op1_pos;
integer op2_pos_odd,op2_pos_even,op2_zero,op2_neg_odd,op2_neg_even;
initial
begin
op1_neg = -10;op1_n1 = -1;op1_0 = 0;op1_p1 = 1;op1_pos = 10;
op2_pos_odd = 9;op2_pos_even =10;op2_zero=0;op2_neg_odd
=-9;op2_neg_even=-10;
$display(" | -10 -1 0 1 10");
$display("---|--------------------------------------------------------");
$display(" 9| %d %d %d %d
%d",op1_neg**op2_pos_odd,op1_n1**op2_pos_odd,op1_0**op2_pos_odd,op1_p1**op2_pos_odd,op1_pos**op2_pos_odd
);
$display(" 10| %d %d %d %d
%d",op1_neg**op2_pos_even,op1_n1**op2_pos_even,op1_0**op2_pos_even,op1_p1**op2_pos_even,op1_pos**op2_pos_even
);
$display(" 0| %d %d %d %d
%d",op1_neg**op2_zero,op1_n1**op2_zero,op1_0**op2_zero,op1_p1**op2_zero,op1_pos**op2_zero
);
$display(" -9| %d %d %d %d
%d",op1_neg**op2_neg_odd,op1_n1**op2_neg_odd,op1_0**op2_neg_odd,op1_p1**op2_neg_odd,op1_pos**op2_neg_odd
);
$display("-10| %d %d %d %d
%d",op1_neg**op2_neg_even,op1_n1**op2_neg_even,op1_0**op2_neg_even,op1_p1**op2_neg_even,op1_pos**op2_neg_even
);
end
endprogram
RESULT
| -10 -1 0 1 10
---|--------------------------------------------------------
9| 3294967296 4294967295 0 1 1000000000
10| 1410065408 1 0 1 1410065408
0| 1 1 1 1 1
-9| 0 4294967295 x 1 0
-10| 0 1 x 1 0
Relational:
EXAMPLE :Relational
program main ;
integer a,b;
initial
begin
b = 10;
a = 22;
$display(" a < b is %0d \n",a < b);
$display(" a > b is %0d \n",a >b);
$display(" a <= b is %0d \n",a <= b);
$display(" a >= b is %0d \n",a >= b);
end
endprogram
RESULTS
a < b is 0
a > b is 1
a <= b is 0
a >= b is 1
Equality:
y equals a is TRUE.
EXAMPLE:case equality:
program main ;
reg a_1,a_0,a_x,a_z;
reg b_1,b_0,b_x,b_z;
initial
begin
a_1 = 'b1;a_0 = 'b0;a_x = 'bx;a_z = 'bz;
b_1 = 'b1;b_0 = 'b0;b_x = 'bx;b_z = 'bz;
$display("--------------------------");
$display (" == 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 == b_0,a_0 == b_1,a_0 == b_x,a_0 == b_z);
$display (" 1 %b %b %b %b ",a_1 == b_0,a_1 == b_1,a_1 == b_x,a_1 == b_z);
$display (" x %b %b %b %b ",a_x == b_0,a_x == b_1,a_x == b_x,a_x == b_z);
$display (" z %b %b %b %b ",a_z == b_0,a_z == b_1,a_z == b_x,a_z == b_z);
$display("--------------------------");
$display("--------------------------");
$display (" === 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 === b_0,a_0 === b_1,a_0 === b_x,a_0
=== b_z);
$display (" 1 %b %b %b %b ",a_1 === b_0,a_1 === b_1,a_1 === b_x,a_1
=== b_z);
$display (" x %b %b %b %b ",a_x === b_0,a_x === b_1,a_x === b_x,a_x
=== b_z);
$display (" z %b %b %b %b ",a_z === b_0,a_z === b_1,a_z === b_x,a_z
=== b_z);
$display("--------------------------");
$display("--------------------------");
$display (" =?= 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 =?= b_0,a_0 =?= b_1,a_0 =?= b_x,a_0 =?
= b_z);
$display (" 1 %b %b %b %b ",a_1 =?= b_0,a_1 =?= b_1,a_1 =?= b_x,a_1 =?
= b_z);
$display (" x %b %b %b %b ",a_x =?= b_0,a_x =?= b_1,a_x =?= b_x,a_x =?
= b_z);
$display (" z %b %b %b %b ",a_z =?= b_0,a_z =?= b_1,a_z =?= b_x,a_z =?
= b_z);
$display("--------------------------");
$display("--------------------------");
$display (" != 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0
!= b_0,a_0 != b_1,a_0 != b_x,a_0 != b_z);
$display (" 1 %b %b %b %b ",a_1
!= b_0,a_1 != b_1,a_1 != b_x,a_1 != b_z);
$display (" x %b %b %b %b ",a_x != b_0,a_x != b_1,a_x != b_x,a_x != b_z);
$display (" z %b %b %b %b ",a_z != b_0,a_z != b_1,a_z != b_x,a_z != b_z);
$display("--------------------------");
$display("--------------------------");
$display (" !== 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 !== b_0,a_0 !== b_1,a_0 !== b_x,a_0
!== b_z);
$display (" 1 %b %b %b %b ",a_1 !== b_0,a_1 !== b_1,a_1 !== b_x,a_1
!== b_z);
$display (" x %b %b %b %b ",a_x !== b_0,a_x !== b_1,a_x !== b_x,a_x
!== b_z);
$display (" z %b %b %b %b ",a_z !== b_0,a_z !== b_1,a_z !== b_x,a_z
!== b_z);
$display("--------------------------");
$display("--------------------------");
$display (" !?= 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 !?= b_0,a_0 !?= b_1,a_0 !?= b_x,a_0 !?
= b_z);
$display (" 1 %b %b %b %b ",a_1 !?= b_0,a_1 !?= b_1,a_1 !?= b_x,a_1 !?
= b_z);
$display (" x %b %b %b %b ",a_x !?= b_0,a_x !?= b_1,a_x !?= b_x,a_x !?
= b_z);
$display (" z %b %b %b %b ",a_z !?= b_0,a_z !?= b_1,a_z !?= b_x,a_z !?
= b_z);
$display("--------------------------");
end
endprogram
RESULTS
--------------------------
== 0 1 x z
--------------------------
0 1 0 x x
1 0 1 x x
x x x x x
z x x x x
--------------------------
--------------------------
=== 0 1 x z
--------------------------
0 1 0 0 0
1 0 1 0 0
x 0 0 1 0
z 0 0 0 1
--------------------------
--------------------------
=?= 0 1 x z
--------------------------
0 1 0 1 1
1 0 1 1 1
x 1 1 1 1
z 1 1 1 1
--------------------------
--------------------------
!= 0 1 x z
--------------------------
0 0 1 x x
1 1 0 x x
x x x x x
z x x x x
--------------------------
--------------------------
!== 0 1 x z
--------------------------
0 0 1 1 1
1 1 0 1 1
x 1 1 0 1
z 1 1 1 0
--------------------------
--------------------------
!?= 0 1 x z
--------------------------
0 0 1 0 0
1 1 0 0 0
x 0 0 0 0
z 0 0 0 0
--------------------------
Search ✔
|| b_z);
$display (" x %b %b %b %b ",a_x || b_0,a_x || b_1,a_x || b_x,a_x
|| b_z);
$display (" z %b %b %b %b ",a_z || b_0,a_z || b_1,a_z || b_x,a_z
|| b_z);
$display("--------------------------");
$display("--------------------------");
$display (" ! 0 1 x z ");
$display("--------------------------");
$display (" %b %b %b %b ",!b_0,!b_1,!b_x,!b_z);
$display("--------------------------");
end
endprogram
RESULTS
--------------------------
&& 0 1 x z
--------------------------
0 0 0 0 0
1 0 1 x x
x 0 x x x
z 0 x x x
--------------------------
--------------------------
|| 0 1 x z
--------------------------
0 0 1 x x
1 1 1 1 1
x x 1 x x
z x 1 x x
--------------------------
--------------------------
! 0 1 x z
--------------------------
1 0 x x
--------------------------
Bitwise :
In Systemverilog, bitwise exclusive nor has two notations (~^ and ^~).
EXAMPLE : Bitwise
program main ;
reg a_1,a_0,a_x,a_z;
reg b_1,b_0,b_x,b_z;
initial begin
a_1 = 'b1;a_0 = 'b0;a_x = 'bx;a_z = 'bz;
b_1 = 'b1;b_0 = 'b0;b_x = 'bx;b_z = 'bz;
$display("--------------------------");
$display (" ~ 0 1 x z ");
$display("--------------------------");
$display (" %b %b %b %b ",~b_0,~b_1,~b_x,~b_z);
$display("--------------------------");
$display("--------------------------");
$display (" & 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 & b_0,a_0 & b_1,a_0 & b_x,a_0 & b_z);
$display (" 1 %b %b %b %b ",a_1 & b_0,a_1 & b_1,a_1 & b_x,a_1 & b_z);
$display (" x %b %b %b %b ",a_x & b_0,a_x & b_1,a_x & b_x,a_x & b_z);
$display (" z %b %b %b %b ",a_z & b_0,a_z & b_1,a_z & b_x,a_z & b_z);
$display("--------------------------");
$display("--------------------------");
$display (" &~ 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 &~ b_0,a_0 &~ b_1,a_0 &~ b_x,a_0
&~ b_z);
$display (" 1 %b %b %b %b ",a_1 &~ b_0,a_1 &~ b_1,a_1 &~ b_x,a_1
&~ b_z);
$display (" x %b %b %b %b ",a_x &~ b_0,a_x &~ b_1,a_x &~ b_x,a_x
&~ b_z);
$display (" z %b %b %b %b ",a_z &~ b_0,a_z &~ b_1,a_z &~ b_x,a_z
&~ b_z);
$display("--------------------------");
$display("--------------------------");
$display (" | 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 | b_0,a_0 | b_1,a_0 | b_x,a_0 | b_z);
$display (" 1 %b %b %b %b ",a_1 | b_0,a_1 | b_1,a_1 | b_x,a_1 | b_z);
$display (" x %b %b %b %b ",a_x | b_0,a_x | b_1,a_x | b_x,a_x | b_z);
$display (" z %b %b %b %b ",a_z | b_0,a_z | b_1,a_z | b_x,a_z | b_z);
$display("--------------------------");
$display (" |~ 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 |~ b_0,a_0 |~ b_1,a_0 |~ b_x,a_0 |~ b_z);
$display (" 1 %b %b %b %b ",a_1 |~ b_0,a_1 |~ b_1,a_1 |~ b_x,a_1 |~ b_z);
$display (" x %b %b %b %b ",a_x |~ b_0,a_x |~ b_1,a_x |~ b_x,a_x |~ b_z);
$display (" z %b %b %b %b ",a_z |~ b_0,a_z |~ b_1,a_z |~ b_x,a_z |~ b_z);
$display("--------------------------");
$display("--------------------------");
$display (" ^ 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 ^ b_0,a_0 ^ b_1,a_0 ^ b_x,a_0 ^ b_z);
$display (" 1 %b %b %b %b ",a_1 ^ b_0,a_1 ^ b_1,a_1 ^ b_x,a_1 ^ b_z);
$display (" x %b %b %b %b ",a_x ^ b_0,a_x ^ b_1,a_x ^ b_x,a_x ^ b_z);
$display (" z %b %b %b %b ",a_z ^ b_0,a_z ^ b_1,a_z ^ b_x,a_z ^ b_z);
$display("--------------------------");
$display (" ^~ 0 1 x z ");
$display("--------------------------");
$display (" 0 %b %b %b %b ",a_0 ^~ b_0,a_0 ^~ b_1,a_0 ^~ b_x,a_0 ^~ b_z);
$display (" 1 %b %b %b %b ",a_1 ^~ b_0,a_1 ^~ b_1,a_1 ^~ b_x,a_1 ^~ b_z);
$display (" x %b %b %b %b ",a_x ^~ b_0,a_x ^~ b_1,a_x ^~ b_x,a_x ^~ b_z);
$display (" z %b %b %b %b ",a_z ^~ b_0,a_z ^~ b_1,a_z ^~ b_x,a_z ^~ b_z);
$display("--------------------------");
end
endprogram
RESULTS
--------------------------
~ 0 1 x z
--------------------------
1 0 x x
--------------------------
--------------------------
& 0 1 x z
--------------------------
0 0 0 0 0
1 0 1 x x
x 0 x x x
z 0 x x x
--------------------------
--------------------------
&~ 0 1 x z
--------------------------
0 0 0 0 0
1 1 0 x x
x x 0 x x
z x 0 x x
--------------------------
--------------------------
| 0 1 x z
--------------------------
0 0 1 x x
1 1 1 1 1
x x 1 x x
z x 1 x x
--------------------------
|~ 0 1 x z
--------------------------
0 1 0 x x
1 1 1 1 1
x 1 x x x
z 1 x x x
--------------------------
--------------------------
^ 0 1 x z
--------------------------
0 0 1 x x
1 1 0 x x
x x x x x
z x x x x
--------------------------
^~ 0 1 x z
--------------------------
0 1 0 x x
1 0 1 x x
x x x x x
z x x x x
--------------------------
Reduction :
EXAMPLE : Reduction
program main ;
reg [3:0] a_1,a_0,a_01xz,a_1xz,a_0xz,a_0dd1,a_even1;
initial
begin
a_1 = 4'b1111 ;
a_0 = 4'b0000 ;
a_01xz = 4'b01xz ;
a_1xz = 4'b11xz ;
a_0xz = 4'b00xz ;
a_0dd1 = 4'b1110 ;
a_even1 = 4'b1100 ;
$display("-------------------------------------------");
$display(" a_1 a_0 a_01xz a_1xz a_0xz ");
$display("-------------------------------------------");
$display("& %b %b %b %b
%b ",&a_1,&a_0,&a_01xz,&a_1xz,&a_0xz);
$display("| %b %b %b %b
%b ",|a_1,|a_0,|a_01xz,|a_1xz,|a_0xz);
$display("~& %b %b %b %b
%b ",~&a_1,~&a_0,~&a_01xz,~&a_1xz,~&a_0xz);
$display("~| %b %b %b %b
%b ",~|a_1,~|a_0,~|a_01xz,~|a_1xz,~|a_0xz);
$display("-------------------------------------------");
$display(" a_ood1 a_even1 a_1xz");
$display("-------------------------------------------");
$display(" ^ %b %b %b ",^a_0dd1,^a_even1,^a_1xz);
$display(" ~^ %b %b %b ",~^a_0dd1,~^a_even1,~^a_1xz);
$display("-------------------------------------------");
end
endprogram
RESULTS
-------------------------------------------
a_1 a_0 a_01xz a_1xz a_0xz
-------------------------------------------
& 1 0 0 x 0
| 1 0 1 1 x
~& 0 1 1 x 1
~| 0 1 0 0 x
-------------------------------------------
a_ood1 a_even1 a_1xz
-------------------------------------------
^ 1 0 x
~^ 0 1 x
-------------------------------------------
Shift :
The left shift operators, << and <<<, shall shift their left operand to the left by the
number by the number of bit positions given by the right operand. In both cases, the
vacated bit positions shall be filled with zeros. The right shift operators, >> and >>>,
shall shift their left operand to the right by the number of bit positions given by the
right operand. The logical right shift shall fill the vacated bit positions with zeros.
The arithmetic right shift shall fill the vacated bit positions with zeros if the result
type is unsigned. It shall fill the vacated bit positions with the value of the most
significant (i.e., sign) bit of the left operand if the result type is signed. If the right
operand has an x or z value, then the result shall be unknown. The right operand is
always treated.
EXAMPLE :Shift
program main ;
integer a_1,a_0;
initial begin
a_1 = 4'b1100 ;
a_0 = 4'b0011 ;
$display(" << by 1 a_1 is %b a_0 is %b ",a_1 << 1,a_0 << 1);
$display(" >> by 2 a_1 is %b a_0 is %b ",a_1 >> 2,a_0 >> 2);
$display(" <<< by 1 a_1 is %b a_0 is %b ",a_1 <<< 1,a_0 <<< 1);
$display(" >>> by 2 a_1 is %b a_0 is %b ",a_1 >>> 2,a_0 >>> 2);
end
endprogram
RESULTS
# ++ increment
# -- decrement
SystemVerilog includes the C increment and decrement assignment operators ++i, --i,
i++, and i--. These do not need parentheses when used in expressions. These
increment and decrement assignment operators behave as blocking assignments.
The ordering of assignment operations relative to any other operation within an
expression is undefined. An implementation can warn whenever a variable is both
written and read-or-written within an integral expression or in other contexts where
an implementation cannot guarantee order of evaluation.
For example:
i = 10;
j = i++ + (i = i - 1);
After execution, the value of j can be 18, 19, or 20 depending upon the relative
ordering of the increment and the assignment statements. The increment and
decrement operators, when applied to real operands, increment or decrement the
operand by 1.0.
a_0 -- ;
$display (" a_1 is %d a_0 is %d ",a_1,a_0);
end
endprogram
RESULTS
Set :
The expression on the left-hand side of the inside operator is any singular expression.
The set-membership open_range_list on the right-hand side of the inside operator is a
comma-separated list of expressions or ranges. If an expression in the list is an
aggregate array, its elements are traversed by descending into the array until
reaching a singular value. The members of the set are scanned until a match is found
and the operation returns 1'b1. Values can be repeated, so values and value ranges
can overlap. The order of evaluation of the expressions and ranges is non-
deterministic.
EXAMPLE : Set
program main ;
integer i;
initial begin
i = 20;
if( i inside {10,20,30})
$display(" I is in 10 20 30 ");
end
endprogram
RESULTS
I is in 10 20 30
Streaming Operator
The streaming operators perform packing of bit-stream types into a sequence of bits
in a user-specified order.
When used in the left-hand side , the streaming operators perform the
reverse operation, i.e., unpack a stream of bits intoone or more variables.
The stream_operator << or >> determines the order in which blocks of data are
streamed.
For Example
int j = { "A", "B", "C", "D" };
{ >> {j}} // generates stream "A" "B" "C" "D"
{ << byte {j}} // generates stream "D" "C" "B" "A" (little endian)
{ << 16 {j}} // generates stream "C" "D" "A" "B"
{ << { 8'b0011_0101 }} // generates stream 'b1010_1100 (bit reverse)
{ << 4 { 6'b11_0101 }} // generates stream 'b0101_11
{ >> 4 { 6'b11_0101 }} // generates stream 'b1101_01 (same)
{ << 2 { { << { 4'b1101 }} }} // generates stream 'b1110
Packing is performed by using the streaming operator on thr RHS of the expression.
For example:
int j = { "A", "B", "C", "D" };
bit [7:0] arr;
arr = { >> {j}}
arr = { << byte {j}}
arr = { << 16 {j}}
arr = { << { 8'b0011_0101 }}
arr = { << 4 { 6'b11_0101 }}
arr = { >> 4 { 6'b11_0101 }}
arr = { << 2 { { << { 4'b1101 }} }}
UnPacking is performed by using the streaming operator on thr LHS of the expression.
For example
int a, b, c;
logic [10:0] up [3:0];
logic [11:1] p1, p2, p3, p4;
bit [96:1] y = {>>{ a, b, c }}; // OK: pack a, b, c
int j = {>>{ a, b, c }}; // error: j is 32 bits < 96 bits
bit [99:0] d = {>>{ a, b, c }}; // OK: d is padded with 4 bits
{>>{ a, b, c }} = 23'b1; // error: too few bits in stream
{>>{ a, b, c }} = 96'b1; // OK: unpack a = 0, b = 0, c = 1
{>>{ a, b, c }} = 100'b1; // OK: unpack as above (4 bits unread)
{ >> {p1, p2, p3, p4}} = up; // OK: unpack p1 = up[3], p2 = up[2],
// p3 = up[1], p4 = up[0]
Streaming Dynamically Sized Data
Search ✔
Specman E
Interview Questions
Search ✔
RESULT
e is FALSE at 10
e is triggered at 20
e is TRUE at 20
e is FALSE at 30
e is triggered at 40
e is TRUE at 40
e is FALSE at 50
e is triggered at 60
e is TRUE at 60
e is FALSE at 70
e is triggered at 80
e is TRUE at 80
e is FALSE at 90
Wait()
EXAMPLE:
module event_m;
event a;
initial
repeat(4)
#20 -> a;
always
begin
@a;
$display(" ONE :: EVENT A is triggered ");
end
always
begin
wait(a.triggered);
$display(" TWO :: EVENT A is triggered ");
#1;
end
endmodule
RESULT:
Race Condition
For a trigger to unblock a process waiting on an event, the waiting process must
execute the @ statement before the triggering process executes the trigger operator,
->. If the trigger executes first, then the waiting process remains blocked.
In the following example, event "e1" is triggered and a process is waiting on "e1" in
the same time step. The process can never catch the triggering of "e1" as it occurs
after the event "e1" triggering. Event "e2" triggering occurrence can be recognized by
wait (e2.triggered) in spite of the above condition.
EXAMPLE:
module main;
event e1,e2;
initial
repeat(4)
begin
#20;
->e1 ;
@(e1)
$display(" e1 is triggered at %t ",$time);
end
initial
repeat(4)
begin
#20;
->e2 ;
wait(e2.triggered);
$display(" e2 is triggered at %t ",$time);
end
endmodule
RESULT
Nonblocking events are triggered using the ->> operator. The effect of the ->>
operator is that the statement executes without blocking and it creates a nonblocking
assign update event in the time in which the delay control expires, or the event-
control occurs. The effect of this update event shall be to trigger the referenced
event in the nonblocking assignment region of the simulation cycle.
Merging Events
An event variable can be assigned to another event variable. When a event variable is
assigned to other , both the events point to same synchronization object. In the
following example, Event "a" is assigned to event "b" and when event "a" is triggered,
event occurrence can be seen on event "b" also.
EXAMPLE:
module events_ab;
event a,b;
initial begin
#1 -> b; // trigger both always blocks
-> a;
#10 b = a; // merge events
#20 -> a; // both will trigger , 3 trigger events but have 4 trigger responses.
end
always@(a) begin
$display(" EVENT A is triggered ");
#20;
end
always@(b) begin
$display(" EVENT B is triggered ");
#20;
end
endmodule
RESULTS:
EVENT B is triggered
EVENT A is triggered
EVENT B is triggered
EVENT A is triggered
When events are merged, the assignment only affects the execution of subsequent
event control or wait operations. If a process is blocked waiting for event1 when
another event is assigned to event1, the currently waiting process shall never unblock.
In the following example, "always@(b)" is waiting for the event on "b" before the
assignment "b = a" and this waiting always block was never unblocked.
EXAMPLE:
module events_ab;
event a,b;
initial
begin
#20 -> a;
b = a;
#20 -> a;
end
always@(a)
$display(" EVENT A is triggered ");
always@(b)
$display(" EVENT B is also triggered ");
endmodule
RESULTS:
EVENT A is triggered
EVENT A is triggered
Null Events
SystemVerilog event variables can also be assigned a null object, when assigned null
to event variable, the association between the synchronization object and the event
variable is broken.
EXAMPLE:
program main;
event e;
initial
begin
repeat(4)
#($random()%10) -> e;
e = null;
repeat(4)
#($random()%10) -> e;
end
initial
forever
begin
@e ;
$display(" e is triggered at %t",$time);
end
endprogram
RESULT:
e is triggered at 348
e is triggered at 4967
e is triggered at 9934
e is triggered at 14901
Wait Sequence
The wait_order construct suspends the calling process until all of the specified events
are triggered in the given order (left to right) or any of the un-triggered events are
triggered out of order and thus causes the operation to fail. Wait_order() does not
consider time, only ordering in considered.
EXAMPLE:
module main;
event e1,e2,e3;
initial
begin
#10;
-> e1;
-> e2;
-> e3;
#10;
-> e3;
-> e1;
-> e2;
#10;
-> e3;
-> e2;
-> e3;
end
always
begin
wait_order(e1,e2,e3)
$display(" Events are in order ");
else
$display(" Events are out of order ");
end
endmodule
RESULT:
Events Comparison
Event variables can be compared against other event variables or the special value
null. Only the following operators are allowed for comparing event variables:
EXAMPLE:
module main;
event e1,e2,e3,e4;
initial
begin
e1 = null;
e2 = e3;
if(e1)
$display(" e1 is not null ");
else
$display(" e1 is null ");
if(e2)
$display(" e2 is not null");
else
$display(" e2 is null");
if(e3 == e4)
$display( " e3 and e4 are same events ");
else
$display( " e3 and e4 are not same events ");
if(e3 == e2)
$display( " e3 and e2 are same events ");
else
$display( " e3 and e2 are not same events ");
end
endmodule
RESULT:
e1 is null
e2 is not null
e3 and e4 are not same events
e3 and e2 are same events
Search ✔
I is equal to 20
integer i;
initial begin
repeat(10)begin
i = $random();
case(1) begin
(i<0) :$display(" i is less than zero i==%d\n",i);
(i>0) :$display(" i is grater than zero i=%d\n",i);
(i == 0):$display(" i is equal to zero i=%d\n",i);
end
end
end
endprogram
RESULTS
EXAMPLE : forloop
program for_loop;
integer count, i;
initial begin
for(count = 0, i=0; i*count<50; i++, count++)
$display("Value i = %0d\n", i);
end
endprogram
RESULTS
Value i = 0
Value i = 1
Value i = 2
Value i = 3
Value i = 4
Value i = 5
Value i = 6
Value i = 7
EXAMPLE : whileloop
program while_loop;
integer operator=0;
initial begin
while (operator<5)begin
operator += 1;
$display("Operator is %0d\n", operator);
end
end
endprogram
RESULTS
Operator is 1
Operator is 2
Operator is 3
Operator is 4
Operator is 5
EXAMPLE : dowhile
program test;
integer i = 0;
initial begin
do
begin
$display("i = %0d \n", i);
i++;
end
while (i < 10);
end
endprogram
RESULTS
i= 0
i= 1
i= 2
i= 3
i= 4
i= 5
i= 6
i= 7
i= 8
i= 9
The foreach construct specifies iteration over the elements of an array. Its argument
is an identifier that designates any type of array (fixed-size, dynamic, or associative)
followed by a list of loop variables enclosed in square brackets. Each loop variable
corresponds to one of the dimensions of the array. The foreach construct is similar to
a repeat loop that uses the array bounds to specify the repeat count instead of an
expression.
The first foreach causes i to iterate from 0 to 1, j from 0 to 2, and k from 0 to 3. The
second foreach causes q to iterate from 5 to 1, r from 0 to 3, and s from 2 to 1
(iteration over the third index is skipped).
EXAMPLE : foeach
program example;
string names[$]={"Hello", "SV"};
int fxd_arr[2][3] = '{'{1,2,3},'{4,5,6}};
initial begin
foreach (names[i])
$display("Value at index %0d is %0s\n", i, names[i]);
foreach(fxd_arr[,j])
$display(fxd_arr[1][j]);
end
endprogram
RESULTS
Value at index 1 is SV
4
5
6
EXAMPLE : randcase
program rand_case;
integer i;
initial begin
repeat(10)begin
randcase
begin
10: i=1;
20: i=2;
50: i=3;
end
$display(" i is %d \n",i);end
end
endprogram
RESULTS
i is 3
i is 2
i is 3
i is 3
i is 3
i is 3
i is 1
i is 1
i is 1
i is 2
In Verilog, the variable used to control a for loop must be declared prior to the loop.
If loops in two or more parallel procedures use the same loop control variable, there is
a potential of one loop modifying the variable while other loops are still using it.
SystemVerilog adds the ability to declare the for loop control variable within the for
loop. This creates a local variable within the loop. Other parallel loops cannot
inadvertently affect the loop control variable.
For example:
module foo;
initial begin
for (int i = 0; i <= 255; i++)
...
end
initial begin
loop2: for (int i = 15; i >= 0; i--)
...
end
endmodule
Unique:
EXAMPLE :
module uniq;
initial
begin
for (int a = 0;a< 6;a++)
unique if ((a==0) || (a==1) ) $display("0 or 1");
else if (a == 2) $display("2");
else if (a == 4) $display("4"); // values 3,5,6 cause a warning
end
endmodule
RESULTS:
0 or 1
0 or 1
2
RT Warning: No condition matches in 'unique if' statement.
4
RT Warning: No condition matches in 'unique if' statement.
Priority:
EXAMPLE:
module prioriti;
initial
for(int a = 0;a<7;a++)
priority if (a[2:1]==0) $display("0 or 1");
else if (a[2] == 0) $display("2 or 3");
else $display("4 to 7"); //covers all other possible values, so no warning
endmodule
RESULTS:
0 or 1
0 or 1
2 or 3
2 or 3
4 to 7
4 to 7
4 to 7
If the case is qualified as priority or unique, the simulator shall issue a warning
message if no case item matches. These warnings can be issued at either compile time
or run time, as soon as it is possible to determine the illegal condition.
EXAMPLE:
module casee;
initial
begin
for(int a = 0;a<4;a++)
unique case(a) // values 3,5,6,7 cause a warning
0,1: $display("0 or 1");
2: $display("2");
4: $display("4");
endcase
for(int a = 0;a<4;a++)
priority casez(a) // values 4,5,6,7 cause a warning
3'b00?: $display("0 or 1");
end
endmodule
RESULTS:
0 or 1
0 or 1
2
Warning: No condition matches in 'unique case' statement.
0 or 1
0 or 1
2 or 3
2 or 3
Search ✔
program schedules events in the Reactive region, the clocking block construct is very
useful to automatically sample the steady-state values of previous time steps or clock
cycles. Programs that read design values exclusively through clocking blocks with #0
input skews are insensitive to read-write races. It is important to note that simply
sampling input signals (or setting non-zero skews on clocking block inputs) does not
eliminate the potential for races. Proper input sampling only addresses a single
clocking block. With multiple clocks, the arbitrary order in which overlapping or
simultaneous clocks are processed is still a potential source for races.
Following example demonstrates the difference between the module based testbench
and program based testbenchs.
module DUT();
reg q = 0;
reg clk = 0;
initial
#10 clk = 1;
always @(posedge clk)
q <= 1;
endmodule
module Module_based_TB();
always @ (posedge DUT.clk) $display("Module_based_TB : q = %b\n", DUT.q);
endmodule
program Program_based_TB();
initial
forever @(posedge DUT.clk) $display("Program_based_TB : q = %b\n", DUT.q);
endprogram
RESULT:
Module_based_TB : q = 0
program_based_TB : q = 1
Search ✔
EXAMPLE:
always_comb
a = b & c;
always_latch
if(ck) q <= d;
always_ff @(posedge clock iff reset == 0 or posedge reset)
r1 <= reset ? 0 : r2 + 1;
Search ✔
end
join_none
$display(" time = %d Outside the main fork ",$time );
#(40);
end
endprogram
RESULTS
The parent process blocks until any one of the processes spawned by this fork
completes.
The parent process blocks until all the processes spawned by this fork complete.
initial
begin
#(10);
$display(" BEFORE fork time = %d ",$time );
fork
begin
# (20);
$display("time = %d # 20 ",$time );
end
begin
#(10);
$display("time = %d # 10 ",$time );
end
begin
#(5);
$display("time = %d # 5 ",$time );
end
join
$display(" time = %d Outside the main fork ",$time );
#(40);
end
endprogram
RESULTS
When defining a fork/join block, encapsulating the entire fork inside begin..end,
results in the entire block being treated as a single thread, and the code executes
consecutively.
Search ✔
begin
#(5);
$display(" time = %0d # 5 ",$time );
end
join_any
$display(" time = %0d Outside the main fork ",$time );
wait fork ;
$display(" time = %0d After wait fork ",$time );
end
endprogram
RESULTS
BEFORE fork time = 10
time = 15 # 5
time = 15 Outside the main fork
time = 20 # 10
time = 30 # 20
time = 30 After wait fork
The disable fork statement terminates all active descendants (subprocesses) of the
calling process.
In other words, if any of the child processes have descendants of their own, the
disable fork statement shall terminate them as well. Sometimes, it is required to kill
the child processes after certain condition.
EXAMPLE
program main();
initial begin
#(10);
$display(" BEFORE fork time = %0d ",$time );
fork
begin
# (20);
$display(" time = %0d # 20 ",$time );
end
begin
#(10);
$display(" time = %0d # 10 ",$time );
end
begin
#(5);
$display(" time = %0d # 5 ",$time );
end
join_any
$display(" time = %0d Outside the main fork ",$time );
end
initial
#100 $finish;
endprogram
RESULTS
BEFORE fork time = 10
time = 15 # 5
time = 15 Outside the main fork
time = 20 # 10
time = 30 # 20
In the following example, disable for kills the threads #10 and #20.
EXAMPLE
program main();
initial begin
#(10);
$display(" BEFORE fork time = %0d ",$time );
fork
begin
# (20);
$display(" time = %0d # 20 ",$time );
end
begin
#(10);
$display(" time = %0d # 10 ",$time );
end
begin
#(5);
$display(" time = %0d # 5 ",$time );
end
join_any
$display(" time = %0d Outside the main fork ",$time );
disable fork;
$display(" Killed the child processes");
end
initial
#100 $finish;
endprogram
RESULTS
BEFORE fork time = 10
time = 15 # 5
time = 15 Outside the main fork
Killed the child processes
Search ✔
Functions:
function logic [15:0] myfunc1(int x, int y);
Function declarations default to the formal direction input if no direction has been
specified. Once a direction is given, subsequent formals default to the same direction.
In the following example, the formal arguments a and b default to inputs, and u and v
are both outputs:
function logic [15:0] myfunc3(int a, int b, output logic [15:0] u, v);
EXAMPLE:
function [15:0] myfunc2 (input [7:0] x,y);
return x * y - 1; //return value is specified using return statement
endfunction
// void functions
function void myprint (int a);
Pass By Reference:
In verilog,method arguments takes as pass by value.The inputs are copyed when the
method is called and the outputs are assigned to outputs when exiting the method.In
SystemVerilog ,methods can have pass by reference.Arguments passed by reference
are not copied into the subroutine area, rather, a reference to the original argument
is passed to the subroutine. The subroutine can then access the argument data via the
reference.
In the following example, variable a is changed at time 10,20 and 30. The method
pass_by_val , copies only the value of the variable a, so the changes in variable a
which are occurred after the task pass_by_val call, are not visible to pass_by_val.
Method pass_by_ref is directly referring to the variable a. So the changes in variable a
are visible inside pass_by_ref.
EXAMPLE:
program main();
int a;
initial
begin
#10 a = 10;
#10 a = 20;
#10 a = 30;
#10 $finish;
end
task pass_by_val(int i);
forever
@i $display("pass_by_val: I is %0d",i);
endtask
task pass_by_ref(ref int i);
forever
@i $display("pass_by_ref: I is %0d",i);
endtask
initial
pass_by_val(a);
initial
pass_by_ref(a);
endprogram
RESULT
pass_by_ref: I is 10
pass_by_ref: I is 20
pass_by_ref: I is 30
EXAMPLE:
program main();
task display(int a = 0,int b,int c = 1 );
$display(" %0d %0d %0d ",a,b,c);
endtask
initial
begin
display( , 5 ); // is equivalent to display( 0, 5, 1 );
display( 2, 5 ); // is equivalent to display( 2, 5, 1 );
display( , 5, ); // is equivalent to display( 0, 5, 1 );
display( , 5, 7 ); // is equivalent to display( 0, 5, 7 );
display( 1, 5, 2 ); // is equivalent to display( 1, 5, 2 );
end
endprogram
RESULT:
0 5 1
2 5 1
0 5 1
0 5 7
1 5 2
EXAMPLE:
program main();
initial
begin
fun( .j(2), .s("yes") ); // fun( 2, "yes" );
fun( .s("yes") ); // fun( 1, "yes" );
endprogram
RESULT
j is 2 : s is yes
j is 1 : s is yes
j is 1 : s is yes
j is 2 : s is no
j is 2 : s is yes
j is 1 : s is no
j is 2 : s is no
j is 1 : s is no
When a task or function specifies no arguments, the empty parenthesis, (), following
the task/function name shall be optional. This is also true for tasks or functions that
require arguments, when all arguments have defaults
specified.
EXAMPLE
program main();
function void fun( );
$display("Inside function");
endfunction
initial
begin
fun( );
fun;
end
endprogram
RESULT
Inside function
Inside function
Search ✔
RESULTS:
Search ✔
RESULTS:
Search ✔
Specman E The await() task allows one process to wait for the completion of another process. It
shall be an error to call this task on the current process, i.e., a process cannot wait
Interview Questions for its own completion.
suspend
The suspend() task allows a process to suspend either its own execution or that of
another process. If the process to be suspended is not blocked waiting on some other
condition, such as an event, wait expression, or a delay then the process shall be
suspended at some unspecified time in the current time step. Calling this method
more than once, on the same (suspended) process, has no effect.
resume
The example below starts an arbitrary number of processes, as specified by the task
argument N. Next, the task waits for the last process to start executing, and then
waits for the first process to terminate. At that point the parent process forcibly
terminates all forked processes that have not completed yet.
task do_n_way( int N );
process job[1:N];
endtask
Search ✔
TUTORIALS
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB Ad Requirements & Guidelines:
* You can submit ads in either JPG, GIF, Flash or HTML formats.
RVM Ethernet sample * Ads may not contain nudity or content that is not family safe.
* Ad placement locations shown in the picture are only approximate. Actual
placement location can change due to editorial content length.
Specman E
Interview Questions
For more information, please contact
gopi@testbench.in
naresh@testbench.in
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
1 module top();
2 reg clk;
3 wire read, enable;
4 wire [7:0] addr;
5 wire [7:0] data;
6
7 Dut D (clk,read,enable,Addr,data);
8
9 Testbench TB(clk,read,enable,Addr,data);
10
11 endmodule
All the connection clk, read, enable, addr, data are done manually. Line 7 and 9 has
same code structure which is duplicating work. If a new port is added, it needs
changes in DUT ports, TestBench Ports, and in 7, 10 lines of Top module. This is time-
consuming and maintaining it is complex as the port lists increases.
To resolve the above issues, SystemVerilog added a new powerful features called
interface. Interface encapsulates the interconnection and communication between
blocks.
interface intf #(parameter BW = 8)(input clk);
logic read, enable;
logic [BW -1 :0] addr,data;
endinterface :intf
Here the signals read, enable, addr, data are grouped in to "intf". Interfaces can have
direction as input, output and inout also. In the above example, clk signal is used as
input to interface. Interfaces can also have parameters like modules. Interface
declaration is just like a module declaration. Uses keywords interface, endinterface
for defining. Inside a module, use hierarchical names for signals in an interface.
TIP: Use wire type in case of multiple drivers. Use logic type in case of a single
driver.
Let use see the DUT and Testbench modules using the above declared interface.
endmodule
module Testbench(intf tb_if);
initial
begin
tb_if.read = 0;
repeat(3) #20 tb_if.read = ~tb_if.read;// driving a signal
$finish;
end
endmodule
module top();
bit clk;
initial
forever #5 clk = ~clk;
endmodule
See, how much code we got reduced in this small example itself. In the above
example, I demonstrated the connectivity between DUT and TestBench. Interfaces can
also be used for connectivity between the DUT sub modules also.
Search ✔
6 endmodule
A mod port can also define expressions. They can also define their own names. Module
can use the modport declared name. For example
modport dut (input read,enable,.addr(2),output .d(data[1:5]);
module dut(intf.dut dut_if);
assign dut_if.d = temp; // using the signal name declared by modport.
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
In the above example, the first line declares a clocking block called cb that is to be
Verilog clocked on the positive edge of the signal clk. The second line specifies that by
Verification default all signals in the clocking block shall use a 10ns input skew and a 2ns output
Verilog Switch TB skew by default. The next line adds three output signals to the clocking block: read,
enable and addr. The fourth line adds the signal data to the clocking block as input.
Basic Constructs Fourth line also contains negedge which overrides the skew ,so that data is sampled
on the negedge of the clk.
OpenVera
Constructs
Skew
Switch TB If an input skew is specified then the signal is sampled at skew time units before the
RVM Switch TB clock event. If output skew is specified, then output (or inout) signals are driven skew
time units after the corresponding clock event. A skew must be a constant expression,
RVM Ethernet sample and can be specified as a parameter.
Specman E
Interview Questions
If skew is not specified, default input skew is 1step and output skew is 0.
output read,enable,addr;
input data;
endclocking
modport dut (input read,enable,addr,output data);
modport tb (clocking cb); // synchronous testbench modport
endinterface :intf
module testbench(intf.tb tb_if);
......
initial
tb_if.cb.read <= 1; //writing to synchronous signal read
...
endmodule
Cycle Delay
## <integer_expression>;
##3; // wait 3 cycles
##1 tb_if.addr <= 8'h00;// waits for 1 cycle and then writes address.
repeat(3) @(posedge clock); sync_block.a <= 1;
Just use
##3 sync_block.a <= 1;
sync_block.a <= ##3 1;
##3; can be used.
But there may be more than one clocking block is defined in a project.
##3 waits for 3 clocks cycles,of the block which is defined as default.
default clocking sync_block @(posedge clock);
Search ✔
If you are working on protocol which has multiple sub bus protocol, there are several
ways to create interfaces.
One Big single interface with all the sub protocol signals inside it. With single
interface, it is easy to pass around the whole system. You have to name all the signals
with the sub protocol prefix like pcie_enable, Eth_enable etc. Restrict the access
using clocking blocks else all signals can be accessed by all the modules using this
interface. Reusability will be very less as all the sub protocols are in one interface.
Using multiple interfaces, one for each sub protocol, each interface for each sub
bus will increase the complexity while passing around the system. No need to prefix
the sub protocol name as the sub protocol name is reflected in the interface name
itself. With this you can only pass the sub interfaces required by other modules. All
the interfaces will be reusable as each interface represents an individual protocol.
Using one big interface with sub multiple interfaces will be easy for passing
around the system. With this the sub interfaces can be reused for other components
and other designs.
Search ✔
We can also convert the verilog module with port list in to SystemVerilog module with
interface by creating wrapper around the verilog module.
Search ✔
Objects are the basic unit of object orientation with behavior, identity. As we
mentioned above, these are part of a class but are not the same. An object is
OpenVera expressed by the variable and methods within the objects. Again these variables and
Constructs methods are distinguished from each other as instant variables, instant methods and
Switch TB class variable and class methods.
RVM Switch TB
RVM Ethernet sample Methods
We know that a class can define both attributes and behaviors. Again attributes are
defined by variables and behaviors are represented by methods. In other words,
Specman E methods define the abilities of an object.
Interview Questions
Inheritance
This is the mechanism of organizing and structuring program. Though objects are
distinguished from each other by some additional features but there are objects that
share certain things common. In object oriented programming classes can inherit some
common behavior and state from others. Inheritance in OOP allows to define a general
class and later to organize some other classes simply adding some details with the old
class definition. This saves work as the special class inherits all the properties of the
old general class and as a programmer you only require the new features. This helps
in a better data analysis, accurate coding and reduces development time. In Verilog ,
to write a new definition using the exesisting definitioan is done inserting `ifdef
conpilation controls into the exesisting code.
Abstraction
The process of abstraction in SystemVerilog is used to hide certain details and only
show the essential features of the object. In other words, it deals with the outside
view of an object.
Encapsulation
Polymorphism
It describes the ability of the object in belonging to different types with specific
behavior of each type. So by using this, one object can be treated like another and in
this way it can create and define multiple level of interface. Here the programmers
need not have to know the exact type of object in advance and this is being
implemented at runtime.
Search ✔
Local Variables :
OpenVera Local Variables Similar to how an object stores its state in fields, a method will often
store its temporary state in local variables. The syntax for declaring a local variable is
Constructs
similar to declaring a field (for example, int count = 0;). There is no special keyword
Switch TB designating a variable as local; that determination comes entirely from the location in
RVM Switch TB which the variable is declared , which is between the opening and closing braces of a
method. As such, local variables are only visible to the methods in which they are
RVM Ethernet sample declared; they are not accessible from the rest of the class.
Parameters :
Specman E The important thing to remember is that parameters are always classified as
"variables" not "fields".
Interview Questions
Constants :
Class properties can be made read-only by a const declaration like any other
SystemVerilog variable.
Search ✔
2 0
OpenVera 4 0
Constructs
Switch TB
RVM Switch TB Definition (Object) An object is an instance of a class. It can be uniquely identified by
RVM Ethernet sample its name and it defines a state which is represented by the values of its attributes at a
particular time.
The state of the object changes according to the methods which are applied to it. We
Specman E refer to these possible sequence of state changes as the behaviour of the object.
Interview Questions
Definition (Behaviour) The behaviour of an object is defined by the set of methods
which can be applied on it.
We now have two main concepts of object-orientation introduced, class and object.
Object-oriented programming is therefore the implementation of abstract data types
or, in more simple words, the writing of classes. At runtime instances of these
classes, the objects, achieve the goal of the program by changing their states.
Consequently, you can think of your running program as a collection of objects.
Creating Objects
As you know, a class provides the blueprint for objects; you create an object from a
class. In the following statements ,program creates an object and assigns it to a
variable:
The first line creates an object of the packet class, and the second create an
object of the driver class.
1. Declaration: The code set in bold are all variable declarations that associate
a variable name with an object type.
2. Instantiation: The new keyword is a SV operator that creates the object.
3. Initialization: The new operator is followed by a call to a constructor, which
initializes the new object.
Declaration:
type name;
This notifies the compiler that you will use name to refer to data whose type is type.
With a primitive variable, this declaration also reserves the proper amount of memory
for the variable.
You can also declare a reference variable on its own line. For example:
packet pkt;
If you declare pkt like this, its value will be undetermined until an object is actually
created and assigned to it using the new method. Simply declaring a reference
variable does not create an object. For that, you need to use the new operator. You
must assign an object to pkt before you use it in your code. Otherwise, you will get a
compiler error.
EXAMPLE:
class packet ;
int length = 0;
function new (int l);
length = l;
endfunction
endclass
program main;
initial
begin
packet pkt;
pkt.length = 10;
end
endprogram
RESULT
Instantiating A Class:
The new operator instantiates a class by allocating memory for a new object and
returning a reference to that memory. The new operator also invokes the object
constructor.
The new operator returns a reference to the object it created. This reference is
usually assigned to a variable of the appropriate type, like:
Initializing An Object
EXAMPLE
class packet ;
int length = 0;
//constructor
function new (int l);
length = l;
endfunction
endclass
This class contains a single constructor. You can recognize a constructor because its
declaration uses the same name as the class and it has no return type. The
constructor in the packet class takes one integer arguments, as declared by the code
(int l). The following statement provides 10 as value for those arguments:
If a class does not explicitly declare any, the SV compiler automatically provides a no-
argument constructor, called the default constructor. This default constructor calls
the class parent's no-argument constructor, or the Object constructor if the class has
no other parent.
Constructor
SystemVerilog does not require the complex memory allocation and deallocation of
C++. Construction of an object is straightforward; and garbage collection, as in Java,
is implicit and automatic. There can be no memory leaks or other subtle behavior that
is so often the bane of C++ programmers.
The new operation is defined as a function with no return type, and like any other
function, it must be nonblocking. Even though new does not specify a return type, the
left-hand side of the assignment determines the return type.
Search ✔
Each argument to the second constructor shadows one of the object's fields inside
the constructor "length" is a local copy of the constructor's first argument. To refer to
the legnth field inside the object , the constructor must use "this.length".
Search ✔
A subclass inherits all of the public and protected members of its parent. You can use
OpenVera the inherited members as is, replace them, hide them, or supplement them with new
Constructs members:
Switch TB
The inherited fields can be used directly, just like any other fields.
RVM Switch TB You can declare a field in the subclass with the same name as the one in the
RVM Ethernet sample superclass, thus hiding it (not recommended).
You can declare new fields in the subclass that are not in the superclass.
Specman E
The inherited methods can be used directly as they are.
Interview Questions
You can write a new instance method in the subclass that has the same signature
as the one in the superclass, thus overriding it.
You can write a new static method in the subclass that has the same signature as
the one in the superclass, thus hiding it.
You can declare new methods in the subclass that are not in the superclass.
You can write a subclass constructor that invokes the constructor of the
Overriding
Following example shows, adding new varibles, new methods, redefining existing
methods.
EXAMPLE:
class parent;
task printf();
$display(" THIS IS PARENT CLASS ");
endtask
endclass
class subclass extends parent;
task printf();
$display(" THIS IS SUBCLASS ");
endtask
endclass
program main;
initial
begin
parent p;
subclass s;
p = new();
s = new();
p.printf();
s.printf();
end
endprogram
RESULT
Super
The super keyword is used from within a derived class to refer to members of the
parent class. It is necessary to use super to access members of a parent class when
those members are overridden by the derived class.
EXAMPLE:
class parent;
task printf();
$display(" THIS IS PARENT CLASS ");
endtask
endclass
class subclass extends parent;
task printf();
super.printf();
endtask
endclass
program main;
initial
begin
subclass s;
s = new();
s.printf();
end
endprogram
RESULT
The member can be a member declared a level up or be inherited by the class one
level up. There is no way to reach higher (for example, super.super.count is not
allowed).
Subclasses (or derived classes) are classes that are extensions of the current class
whereas superclasses (parent classes or base classes) are classes from which the
current class is extended, beginning with the original base class.
NOTE: When using the super within new, super.new shall be the first statement
executed in the constructor. This is because the superclass must be initialized before
the current class and, if the user code does not provide an initialization, the compiler
shall insert a call to super.new automatically.
Is Only Method
EXAMPLE:
class parent;
task printf();
$display(" THIS IS PARENT CLASS ");
endtask
endclass
class subclass extends parent;
task printf();
$display(" THIS IS SUBCLASS ");
endtask
endclass
program main;
initial
begin
subclass s;
s = new();
s.printf();
end
endprogram
RESULT:
THIS IS SUBCLASS
Is First Method
EXAMPLE:
class parent;
task printf();
$display(" THIS IS PARENT CLASS ");
endtask
endclass
class subclass extends parent;
task printf();
$display(" THIS IS SUBCLASS ");
super.printf();
endtask
endclass
program main;
initial
begin
subclass s;
s = new();
s.printf();
end
endprogram
RESULT:
THIS IS SUBCLASS
THIS IS PARENT CLASS
Is Also Method
EXAMPLE:
class parent;
task printf();
$display(" THIS IS PARENT CLASS ");
endtask
endclass
class subclass extends parent;
task printf();
super.printf();
$display(" THIS IS SUBCLASS ");
endtask
endclass
program main;
initial
begin
subclass s;
s = new();
s.printf();
end
endprogram
RESULT:
Overriding Constraints.
Programmers can override the existing constraint and replaces with new constraint as
shown in below example.
EXAMPLE:
class Base;
rand integer Var;
constraint range { Var < 100 ; Var > 0 ;}
endclass
class Extended extends Base;
constraint range { Var < 100 ; Var > 50 ;} // Overrighting the Base class
constraints.
endclass
program inhe_31;
Extended obj;
initial
begin
obj = new();
for(int i=0 ; i < 100 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
end
endprogram
RESULT:
Overriding Datamembers
Only virtual methods truly override methods in base classes. All other methods and
properties do not override but provide name hiding.
EXAMPLE
class base;
int N = 3;
function int get_N();
return N;
endfunction
endclass
function int get_N();
return N;
endfunction
function int get_N1();
return super.N;
endfunction
endclass
program main;
initial
begin
ext e = new;
base b = e; // Note same object!
$display(b.get_N()); // "3"
$display(e.get_N()); // "4"
$display(e.get_N1()); // "3" - super.N
end
endprogram
RESULT
3
4
3
Search ✔
task set(int j);
i = j;
$display(i);
endtask
endclass
program main;
initial
begin
base b = new();
b.set(123);
end
endprogram
RESULT
123
Local member 'i' of class 'base' is not accessible from scope 'ext'
A protected class property or method has all of the characteristics of a local member,
except that it can be inherited; it is visible to subclasses.
In the above example, the varible i is overloaded in subclass with different qualifier.
end
endprogram
RESULT
Protected member 'i' of class 'base' is not accessible from scope 'main'
Within a class, a local method or class property of the same class can be referenced,
even if it is in a different instance of the same class.
EXAMPLE
class Packet;
local integer i;
function integer compare (Packet other);
compare = (this.i == other.i);
endfunction
endclass
A strict interpretation of encapsulation might say that other.i should not be visible
inside of this packet because it is a local class property being referenced from outside
its instance. Within the same class, however, these references are allowed. In this
case, this.i shall be compared to other.i and the result of the logical comparison
returned.
Search ✔
This is class A
Specman E This is class A
Interview Questions
EXAMPLE: with virtual
class A ;
virtual task disp ();
$display(" This is class A ");
endtask
endclass
class EA extends A ;
task disp ();
RESULTS
This is class A
This is Extended class A
Observe the above two outputs. Methods which are declared as virtual are executing
the code in the object which is created.
The methods which are added in the subclasses which are not in the parent class
canot be acessed using the parent class handle. This will result in a compilation error.
The compiler check whether the method is exesting the parent class definition or not.
EXAMPLE:
class A ;
endclass
class EA extends A ;
task disp ();
$display(" This is Extended class A ");
endtask
endclass
program main ;
EA my_ea;
A my_a;
initial
begin
my_ea = new();
my_a = my_ea;
my_ea.disp();
my_a.disp();
end
endprogram
RESULT:
To access the varible or method which are only in the subclass and not in the parent
class, revert back the object to the subclass handle.
EXAMPLE:
class A ;
endclass
class EA extends A ;
task disp ();
$display(" This is Extended class A ");
endtask
endclass
program main ;
EA my_ea;
A my_a;
initial
begin
my_ea = new();
my_a = my_ea;
just(my_a);
end
endprogram
task just(A my_a);
EA loc;
$cast(loc,my_a);
loc.disp();
endtask
RESULT
Let us see one more example, A parent class is extended and virtual method is
redefined in the subclass as non virtual method. Now if furthur extention is done to
the class, then the method is still considered as virtual method and Polymorphism can
be achived still. It is advised to declare a method as virtual in all its subclass, if it is
declared as virtual in baseclass , to avoid confusion to the end user who is extend the
class.
EXAMPLE:
class A ;
virtual task disp ();
$display(" This is class A ");
endtask
endclass
class EA_1 extends A ;
task disp ();
$display(" This is Extended 1 class A ");
endtask
endclass
class EA_2 extends EA_1 ;
task disp ();
$display(" This is Extended 2 class A ");
endtask
endclass
program main ;
EA_2 my_ea;
EA_1 my_a;
initial
begin
my_ea = new();
my_a = my_ea;
my_a.disp();
just(my_a);
end
endprogram
task just(A my_a);
EA_1 loc;
$cast(loc,my_a);
loc.disp();
endtask
RESULT
Search ✔
RESULT
Virtual keyword is used to express the fact that derived classes must redefine the
properties to fulfill the desired functionality. Thus from the abstract class point of
view, the properties are only specified but not fully defined. The full definition
including the semantics of the properties must be provided by derived classes.
Search ✔
EXAMPLE
List#(packet) pl; // Object pl is a list of packet
OpenVera List#(string) sl; // Object sl is a list of strings
Constructs
Switch TB The first line declares List#(packet) to be a list for packets. At this time, the compiler
uses the template definition, substitutes every occurrence of T with "packet" and
RVM Switch TB creates an actual class definition for it. This leads to a class definition similar to the
RVM Ethernet sample one that follows:
EXAMPLE
Specman E class List {
Interview Questions //attributes:
packet data_node;
......
......
// methods:
task append(packet element);
function packet getFirst();
function packet getNext();
......
......
}
This is not exactly, what the compiler generates. The compiler must ensure that we
can create multiple lists for different types at any time. For example, if we need
another list for, say "strings", we can write:
EXAMPLE
List#(packet) pl; // Object pl is a list of packet
List#(string) sl; // Object sl is a list of strings
In both cases the compiler generates an actual class definition. The reason why both
do not conflict by their name is that the compiler generates unique names. However,
since this is not viewable to us, we don't go in more detail here. In any case, if you
declare just another list of "strings", the compiler can figure out if there already is an
actual class definition and use it or if it has to be created. Thus,
EXAMPLE
List#(packet) rcv_pkt; // Object rcv_pkt is a list of packet
List#(packet) sent_pkt; // Object sent_pkt is a list of packet
will create the actual class definition for packet List and will reuse it for another List.
Consequently, both are of the same type. We summarize this in the following
definition:
We are able to define template classes with more than one parameter. For example,
directories are collections of objects where each object can be referenced by a key.
Of course, a directory should be able to store any type of object. But there are also
various possibilities for keys. For instance, they might be strings or numbers.
Consequently, we would define a template class Directory which is based on two type
parameters, one for the key and one for the stored objects.
EXAMPLE
class Base#(int size = 3);
bit [size:0] a;
task disp();
$display(" Size of the vector a is %d ",$size(a));
endtask
endclass
program main();
initial
begin
Base B1;
Base#(4) B2;
Base#(5) B3;
B1 = new();
B2 = new();
B3 = new();
B1.disp();
B2.disp();
B3.disp();
end
endprogram
RESULT
EXAMPLE
vector #(10) vten; // object with vector of size 10
vector #(.size(2)) vtwo; // object with vector of size 2
typedef vector#(4) Vfour; // Class with vector of size 4
All matching specializations of a particular generic class shall represent the same
type. The set of matching specializations of a generic class is defined by the context
of the class declaration. Because generic classes in a package are visible throughout
the system, all matching specializations of a package generic class are the same type.
In other contexts, such as modules or programs, each instance of the scope containing
the generic class declaration creates a unique generic class, thus, defining a new set
of matching specializations.
A generic class is not a type; only a concrete specialization represents a type. In the
example above, the class vector becomes a concrete type only when it has had
parameters applied to it, for example:
typedef vector my_vector; // use default size of 1
EXAMPLE
vector#(6) vx; // use size 6
EXAMPLE
typedef vector#(4) Vfour;
typedef stack#(Vfour) Stack4;
Stack4 s1, s2; // declare objects of type Stack4
EXAMPLE
class C #(type T = bit);
...
endclass // base class
class D1 #(type P = real) extends C; // T is bit (the default)
Class D1 extends the base class C using the base class¿s default type (bit) parameter.
Class D3 extends the base class C using the parameterized type (P) with which the
extended class is parameterized.
Search ✔
It is a way of logically grouping classes that are only used in one place.
OpenVera It increases encapsulation.
Constructs
Nested classes can lead to more readable and maintainable code.
Switch TB Logical grouping of classes : If a class is useful to only one other class, then it is
RVM Switch TB logical to embed it in that class and keep the two together. Nesting such "helper
classes" makes their package more streamlined.
RVM Ethernet sample
Increased encapsulation : Consider two top-level classes, A and B, where B needs
access to members of A that would otherwise be declared private. By hiding class B
Specman E within class A, A's members can be declared private and B can access them. In
addition, B itself can be hidden from the outside world.
Interview Questions
More readable, maintainable code:Nesting small classes within top-level classes
places the code closer to where it is used.
Search ✔
function new( int size );
payload = new[ size > max_size ? max_size : size ];
OpenVera endfunction
Constructs endclass
Switch TB
EXAMPLE: error : chaning const varible
RVM Switch TB class A ;
RVM Ethernet sample const int i = 10;
endclass
program main ;
Specman E A my_a;
Interview Questions
initial
begin
my_a = new();
my_a.i = 55;
end
endprogram
RESULT
Instance Constants
Instance constants do not include an initial value in their declaration, only the const
qualifier. This type of constant can be assigned a value at run time, but the
assignment can only be done once in the corresponding class constructor not from
outside or any other method.
EXAMPLE
class A ;
const int i;
function new();
i = 20;
endfunction
endclass
program main ;
A my_a;
initial
begin
my_a = new();
$display(my_a.i);
end
endprogram
RESULT
20
task set();
i = 20;
endtask
endclass
RESULT
Typically, global constants are also declared static because they are the same for all
instances of the class. However, an instance constant cannot be declared static
because that would disallow all assignments in the constructor
Search ✔
OpenVera
Constructs The static class properties can be accessed using class name.
Switch TB
EXAMPLE: using class name
RVM Switch TB class A ;
RVM Ethernet sample static int i;
endclass
program main ;
Specman E A obj_1;
Interview Questions
initial
begin
obj_1 = new();
obj_1.i = 123;
$display(A::i);
end
endprogram
RESULT
123
The static class properties can be used without creating an object of that type.
RESULT
123
123
Static Methods
Methods can be declared as static. A static method is subject to all the class scoping
and access rules, but behaves like a regular subroutine that can be called outside the
class.
EXAMPLE
class A ;
static task incr();
int j; //automatic variable
j++;
$display("J is %d",j);
endtask
endclass
program main ;
A obj_1;
A obj_2;
initial
begin
$display("Static task - static task with automatic variables");
obj_1 = new();
obj_2 = new();
obj_1.incr();
obj_2.incr();
obj_1.incr();
obj_2.incr();
obj_1.incr();
$display("Static task - Each call to task will create a separate copy of 'j' and
increment it");
end
endprogram
RESULT
EXAMPLE
class A ;
int j;
static task incr();
j++;
$display("J is %d",j);
endtask
endclass
program main ;
A obj_1;
A obj_2;
initial
begin
obj_1 = new();
obj_2 = new();
obj_1.incr();
obj_2.incr();
end
endprogram
RESULT
EXAMPLE
class A ;
int j;
virtual static task incr();
$display("J is %d",j);
endtask
endclass
RESULT
RESULT
Im static method.
The static methods can be used without creating an object of that type.
initial
a.who();
endprogram
RESULT
Im static method.
By default, class methods have automatic lifetime for their arguments and
variables.
All variables of a static lifetime method shall be static in that there shall be a single
variable corresponding to each declared local variable in a class , regardless of the
number of concurrent activations of the method.
EXAMPLE
class A ;
task static incr();
int i; //static variable
$display(" i is %d ",i);
i++;
endtask
endclass
program main;
A a;
A b;
initial
begin
$display("Static lifetime - non static task with static variables");
a = new();
b = new();
a.incr();
b.incr();
a.incr();
b.incr();
a.incr();
$display("Static lifetime - Each call to task will use a single value of 'j' and
increment it");
end
endprogram
RESULT
EXAMPLE
class packet;
static int id;
//----static task using automatic fields ---//
static task packet_id();
int count; // by default static task fields are automatic
id=count; // writing in to static variable
$display("id=%d count=%d",id,count);
count++;
endtask
function new();
int pckt_type;
pckt_type++;
$display("pckt_type=%d",pckt_type);
endfunction
endclass
program stic_1;
packet jumbo,pause,taggd;
initial
begin
jumbo=new();
jumbo.packt_id();
pause=new();
pause.packt_id();
taggd=new();
taggd.packt_id();
end
endprogram
RESULTS
pckt_type= 1; id= 0; count= 0
pckt_type= 1; id= 0 ; count= 0
pckt_type= 1; id= 0; count= 0
EXAMPLE
class packet;
static int id,pckt_type;
//---static task with static field----//
static task packt_id();
static int count; //explicit declaration of fields as static
id=count; //writing in to static variable
$display("id=%d count=%d",id,count);
count++;
endtask
function new();
pckt_type++;
$display("pckt_type=%d",pckt_type);
endfunction
endclass
program stic_2;
packet jumbo,pause,taggd;
initial
begin
jumbo=new();
jumbo.packt_id();
pause=new();
pause.packt_id();
taggd=new();
taggd.packt_id();
end
endprogram
RESULTS
pckt_type= 1; id= 0 count= 0;
pckt_type= 2; id= 1 count= 1;
pckt_type= 3 ; id= 2 count= 2;
Search ✔
class E_1 extends B;
virtual task print();
$display(" CLASS E_1 ");
endtask
endclass
class E_2 extends B;
virtual task print();
$display(" CLASS E_2 ");
endtask
endclass
program main;
initial
begin
B b;
E_1 e1;
E_2 e2;
e1 = new();
$cast(b,e1);
b.print();
end
endprogram
RESULT
CLASS E_1
When called as a function, $cast attempts to assign the source expression to the
destination variable and returns 1 if the cast is legal. If the cast fails, the function
does not make the assignment and returns 0. When called as a function, no run-time
error occurs, and the destination variable is left unchanged. It is important to note
that $cast performs a run-time check. No type checking is done by the compiler,
except to check that the destination variable and source expression are singulars.
CLASS E_1
CLASS E_2
When used with object handles, $cast() checks the hierarchy tree (super and
subclasses) of the source_expr to see whether it contains the class of dest_handle. If
it does, $cast() does the assignment. Otherwise, the error is issued.
EXAMPLE
class Base;
endclass
class Exten extends Base;
endclass
program main;
initial
begin
Base B;
Exten E;
B = new();
if(!$cast(E,B))
$display(" Base class object B canot be assigned to Extended class
Handle.");
// Deallocate object B
B = null;
E = new();
if(!$cast(B,E))
$display(" Extended class object E canot be assigned to Base class
Handle.");
end
endprogram
RESULT
Search ✔
123
321
This works well if the fields are values, but may not be what you want for fields that
point to dynamically allocated memory. The pointer will be copied. but the memory it
points to will not be copied -- the field in both the original object and the copy will
then point to the same dynamically allocated memory, which is not usually what you
want. The assignment operator make shallow copies.
EXAMPLE:
class A;
int i;
endclass
class B;
A a;
endclass
program main;
initial
begin
B b1;
B b2;
b1 = new();
b1.a = new();
b1.a.i = 123;
b2 = new b1;
$display( b1.a.i );
$display( b2.a.i );
b1.a.i = 321;
$display( b1.a.i );
$display( b2.a.i );
end
endprogram
RESULT
123
123
321
321
In the above example, the varible i is changed to which is inside the object of . This
changes in seen in also because both the objects are pointing to same memory
location.
Deep Copy
A deep copy copies all fields, and makes copies of dynamically allocated memory
pointed to by the fields. To make a deep copy, you must write a copy constructor and
overload the assignment operator, otherwise the copy will point to the original, with
disasterous consequences.
EXAMPLE:
class A;
int i;
endclass
class B;
A a;
task copy(A a);
this.a = new a;
endtask
endclass
program main;
initial
begin
B b1;
B b2;
b1 = new();
b1.a = new();
b1.a.i = 123;
b2 = new b1;
b2.copy(b1.a);
$display( b1.a.i );
$display( b2.a.i );
b1.a.i = 321;
$display( b1.a.i );
$display( b2.a.i );
end
endprogram
RESULTS:
123
123
321
123
Clone
A clone method returns a new object whose initial state is a copy of the current state
of the object on which clone was invoked. Subsequent changes to the clone will not
affect the state of the original. Copying is usually performed by a clone() method
method of a class which is user defined. This method usually, in turn, calls the clone()
method of its parent class to obtain a copy, and then does any custom copying
procedures. Eventually this gets to the clone() method of Object (the uppermost
class), which creates a new instance of the same class as the object and copies all the
fields to the new instance (a "shallow copy"). After obtaining a copy from the parent
class, a class's own clone() method may then provide custom cloning capability, like
deep copying (i.e. duplicate some of the structures referred to by the object) .
One disadvantage is that the return type of clone() is Object, and needs to be
explicitly cast back into the appropriate type (technically a custom clone() method
could return another type of object; but that is generally inadvisable).
One advantage of using clone() is that since it is an overridable method, we can call
clone() on any object, and it will use the clone() method of its actual class, without
the calling code needing to know what that class is (which would be necessary with a
copy constructor).
EXAMPLE:
????
Search ✔
initial
Specman E begin
Interview Questions int bin = 123;
Base::print( Base::bin, bin ); // Base::bin and bin are different
end
endprogram
RESULT:
Enum is bin
Val is 123
EXAMPLE:
class Base;
typedef enum {bin,oct,dec,hex} radix;
endclass
class Ext extends Base;
typedef enum {dec,hex,bin,oct} radix;
task print();
$display(" Ext classs :: enum values %d %d %d %d ",bin,oct,dec,hex);
$display(" Base classs :: enum values %d %d %d %d
",Base::bin,Base::oct,Base::dec,Base::hex);
endtask
endclass
program main;
initial
begin
Ext e;
e = new();
e.print();
end
endprogram
RESULT:
In SystemVerilog, the class scope resolution operator applies to all static elements of
a class: static class properties, static methods, typedefs, enumerations, structures,
unions, and nested class declarations. Class scope resolved expressions can be read (in
expressions), written (in assignments or subroutines calls), or triggered off (in event
expressions). They can also be used as the name of a type or a method call.
Search ✔
Specman E
Interview Questions
Search ✔
OpenVera RESULT:
Constructs
Hi
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
EXAMPLE:
class Y ;
int i;
As you seen, there is a compilation error. To avoid this situation, typedef is used to
forward reference the class declaration and this circular dependency problem can be
avoided.
Search ✔
Specman E
Interview Questions
Search ✔
Specman E Method overloading is the practice of declaring the same method with different
signatures. The same method name will be used with different data type . This is Not
Interview Questions Supported by SystemVerilog as of 2008.
EXAMPLE:
task my_task(integer i) { ... }
task my_task(string s) { ... }
program test {
integer number = 10;
string name = "vera";
my_task(number);
my_task(name);
}
Search ✔
EXAMPLE
class Base;
integer a,b;
task always_task();
fork
forever
begin
@(a,b);
$display(" a is %d : b is %d at %t ",a,b,$time);
end
join_none
endtask
endclass
program main;
initial
begin
Base obj;
obj = new();
// start the always block.
fork
obj.always_task();
join_none
repeat(4)
begin
#({$random()}%20)
obj.a = $random();
#({$random()}%20)
obj.b = $random();
end
end
endprogram
RESULT
Search ✔
Specman E
Interview Questions
Search ✔
OpenVera RESULT:
Constructs
Switch TB 20 read_write = 0 ; data = 3230228097 ; address = 2223298057;
40 read_write = 1 ; data = 112818957 ; address = 1189058957;
RVM Switch TB 60 read_write = 1 ; data = 2302104082 ; address = 15983361;
RVM Ethernet sample 80 read_write = 1 ; data = 992211318 ; address = 512609597;
100 read_write = 1 ; data = 1177417612 ; address = 2097015289;
Specman E
Interview Questions $random system function returns a new 32-bit random number each time it is called.
The random number is a signed integer; it can be positive or negative.The following
example demonstrates random generation of signed numbers.
EXAMPLE:
module Tb();
integer address;
initial
begin
repeat(5)
#1 address = $random;
end
initial
$monitor("address = %0d;",address);
endmodule
RESULT:
address = 303379748;
address = -1064739199;
address = -2071669239;
address = -1309649309;
address = 112818957;
We have seen how to generate random numbers.But the numbers randge from - (2**32
-1) to 2 **32. Most of the time, the requirement is dont need this range. For example,
take a memory. The address starts from 0 to some 1k or 1m.Generating a random
address which DUT is not supporting is meaning less. In verilog there are no constructs
to constraint randomization. Following example demonstrated how to generate
random number between 0 to 10.Using % operation,the remainder of any number is
always between 0 to 10.
EXAMPLE:
module Tb();
integer add_1;
initial
begin
repeat(5)
begin
#1;
add_1 = $random % 10;
end
end
initial
$monitor("add_1 = %0d",add_1);
endmodule
RESULT:
add_1 = 8;
add_1 = 4294967287;
add_1 = 4294967295;
add_1 = 9;
add_1 = 9;
OOPS!...... The results are not what is expected.The reason is $random generates
negative numbers also. The following example demonstrates proper way of generating
a random number between 0 to 10. Concatenation operator returns only bitvector. Bit
vectors are unsigned, so the results are correct as we expected. Verilog also has
$unsigned systemtask to convert signed numbers to signed number.This can also be
used to meet the requirements. The following example shows the usage of
concatenation operator and $unsigned.
EXAMPLE:
module Tb();
integer add_2;
reg [31:0] add_1;
integer add_3;
initial
begin
repeat(5)
begin
#1;
add_1 = $random % 10;
add_2 = {$random} %10 ;
add_3 = $unsigned($random) %10 ;
end
end
initial
$monitor("add_3 = %0d;add_2 = %0d;add_1 = %0d",add_3,add_2,add_1);
endmodule
RESULT:
The above example shows the generation of numbers from 0 to N. Some specification
require the range to start from non Zero number. MIN + {$random} % (MAX - MIN ) will
generate random numbers between MIN and MAX.
EXAMPLE:
module Tb();
integer add;
initial
begin
repeat(5)
begin
#1;
add = 40 + {$random} % (50 - 40) ;
$display("add = %0d",add);
end
end
endmodule
RESULT:
add = 48
add = 47
add = 47
add = 47
add = 47
Now how to generate a random number between two ranges? The number should be
between MIN1 and MAX1 or MIN2 and MAX2. The following example show how to
EXAMPLE:
module Tb();
integer add;
initial
begin
repeat(5)
begin
#1;
if($random % 2)
add = 40 + {$random} % (50 - 40) ;
else
add = 90 + {$random} % (100 - 90) ;
$display("add = %0d",add);
end
end
endmodule
RESULT:
add = 97
add = 47
add = 47
add = 42
add = 49
All the random numbers generated above are 32 bit vectors, which is not always the
same requirement. For example, to generate a 5 bit and 45 bit vector random
number, the following method can be used.
EXAMPLE:
module Tb();
reg [4:0] add_1;
reg [44:0] add_2;
initial
begin
repeat(5)
begin
add_1 = $random ;
add_2 = {$random,$random};
$display("add_1 = %b,add_2 = %b ",add_1,add_2);
end
end
endmodule
RESULTS:
Some protocols require a random number which is multiple to some number. For
example, Ethernet packet is always in multiples of 8bits. Look at the following
example. It generates a random number which is multiple of 3 and 5.
$random * 3 will give random numbers which are multiples of 3. But if the number
after multiplication needs more than 32 bit to reprasent, then the results may be
wrong.
EXAMPLE:
module Tb();
integer num_1,num_2,tmp;
initial
begin
repeat(5)
begin
num_1 =( $random / 3)*3;
num_2 =( $random / 5)*5;
$display("num_1 = %d,num_2 = %d",num_1,num_2);
end
end
endmodule
RESULT:
All the above examples show that the random numbers are integers only. In verilog
there is no special construct to generate a random real number.The following method
shows generation of random real numbers.
EXAMPLE:
module Tb();
integer num_1,num_2,num_3;
real r_num;
initial
begin
repeat(5)
begin
#1;
num_1 = $random;
num_2 = $random;
num_3 = $random;
r_num = num_1 + ((10)**(-(num_2)))*(num_3);
$display("r_num = %e",r_num);
end
end
endmodule
RESULT:
r_num = -2.071669e+03
r_num = 2641.189059e+013
r_num = 976361.598336e+01
r_num = 57645.126096e+02
r_num = 24589.097015e+0
To generate random real number , system function $bitstoreal can also be used.
EXAMPLE:
module Tb();
real r_num;
initial
begin
repeat(5)
begin
#1;
r_num = $bitstoreal({$random,$random});
$display("r_num = %e",r_num);
end
end
endmodule
RESULTS:
r_num = 1.466745e-221
r_num = -6.841798e-287
r_num = 2.874848e-276
r_num = -3.516622e-64
r_num = 4.531144e-304
If you want more control over randomizing real numbers interms of sign, exponential
and mantissa, use $bitstoreal() as shown in example below. For positive numbers use
sgn = 0 and for negative numbers use sgn = 1 .
EXAMPLE:
module Tb();
reg sgn;
reg [10:0] exp;
reg [51:0] man;
real r_num;
initial
begin
repeat(5)
begin
sgn = $random;
exp = $random;
man = $random;
r_num = $bitstoreal({sgn,exp,man});
$display("r_num = %e",r_num);
end
end
endmodule
RESULTS:
r_num = 3.649952e+193
r_num = -1.414950e-73
r_num = -3.910319e-149
r_num = -4.280878e-196
r_num = -4.327791e+273
EXAMPLE:
module Tb();
integer num,i,j,index;
integer arr[9:0];
reg ind[9:0];
reg got;
initial
begin
index=0;
for(i=0;i<10;i=i+1)
begin
arr[i] = i;
ind[i] = 1;
end
for(j = 0;j<10 ;j=j+1)
begin
got = 0;
while(got == 0)
begin
index = { $random } % 10;
if(ind[index] == 1)
begin
ind[index] = 0;
got = 1;
num = arr[index];
end
end
$write("| num=%2d |",num);
end
end
endmodule
RESULT:
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
for(j = 0;j<4 ;j=j+1)
begin
seed = j;
$display(" seed is %d",seed);
for(i = 0;i < 10; i=i+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
end
$display(" ");
end
end
endmodule
RESULT:
seed is 0
| num= 8 || num= 7 || num= 7 || num= 7 || num= 7 || num= 7 || num= 5 || num= 2
|| num= 1 || num= 9 |
seed is 1
| num= 8 || num= 8 || num= 2 || num= 2 || num= 6 || num= 3 || num= 8 || num= 5
|| num= 5 || num= 5 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 3
| num= 8 || num= 2 || num= 2 || num= 3 || num= 8 || num= 6 || num= 1 || num= 4
|| num= 3 || num= 9 |
The $random function has its own implicit variable as seed when user is not giving
explicitly seed. The following example shows that seed = 0 and implicit seed are
having same sequence.It means that the imlicity taken seed is also 0.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
seed = 0;
for(j = 0;j<2 ;j=j+1)
begin
if(j ==0)
$display(" seed is %d",seed);
else
$display(" No seed is given ");
for(i = 0;i < 10; i=i+1)
begin
RESULT:
seed is 0
| num= 8 || num= 7 || num= 7 || num= 7 || num= 7 || num= 7 || num= 5 || num= 2
|| num= 1 || num= 9 |
No seed is given
| num= 8 || num= 7 || num= 7 || num= 7 || num= 7 || num= 7 || num= 5 || num= 2
|| num= 1 || num= 9 |
The system functions shall always return same series of values with same seed. This
facilitates debugging by making the operation of the system repeatable. The argument
for the seed parameter should be an integer variable that is initialized by the user and
only updated by the system function. This ensures the desired distribution is achieved.
In the following example, when ever the seed is changed to 2, the sequence 8-1-0-5-
0-8-6-7-11-6......... is followed. Check out in any tool you will see the same
sequence.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
for(j = 0;j<4 ;j=j+1)
begin
seed = 2;
$display(" seed is %d",seed);
for(i = 0;i < 10; i=i+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
end
$display(" ");
end
end
endmodule
RESULT:
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
Seed is inout port. Random number system function returns a random number and
also returns a random number to seed inout argument also. The results of the
following example demonstrates how seed value is getting changed.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
seed = 0;
RESULT:
From the above results we can make a table of seed values and return values of
$random. If a seed is taken from table, then rest of the sequence has to follow
sequence in table.
In the following example, the seed is 837833973, which is the 4 th seed from the
above table.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
seed = 837833973;
for(j = 0;j<10 ;j=j+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
$display(" seed is %d ",seed);
end
end
endmodule
RESULTS:
From the above example we can come to conclusion that $random is not giving a
random number. It is randomizing seed and returning corresponding number for that
seed.
The following example demonstrates how $random misses many seeds. I tried to
display the seeds between 0 to 20 in the chaining formed by initial seed of 0. Results
show that total possible seeds are 4294967295 , and number of seeds possible in seed
chain are 4030768279 , so we are missing some seeds. Look at the seeds between 0 to
20. Seed == 1 is missing.
EXAMPLE:
module Tb();
integer num,seed,j;
reg [0:31] i;
initial
begin
i = 0;
seed = 1;
while (seed != 0)
begin
if(i == 0)
seed = 0;
i = i + 1;
num = $random(seed);
if(seed < 20 && seed > 0)
$display(" seed is %d after values %d ",seed,i);
end
$display(" seed is zero after this number of random numbers %0d total numbers
available are %d",i,{32'hffff_ffff});
end
endmodule
RESULTS:
Now I tried to simulate with seed = 1 . It's interisting to know that some how the
sequence is able to enter this chaining which is formed with seed=0 and there is no
seed value 1 in this chaining and my simulation hanged. So aborted the simulation and
partial results show that the initial seed = 1 enters the chaing formed by seed 0.
EXAMPLE:
module Tb();
integer num,seed,j;
reg [0:31] i;
initial
begin
i = 0;
seed = 0;
while (seed != 1)
begin
if(i == 0)
seed = 1;
i = i + 1;
num = $random(seed);
if(seed < 20 && seed > 0)
$display(" seed is %d after values %d ",seed,i);
end
$display(" seed is one after this number of random numbers %0d total numbers
available are %d",i,{32'hffff_ffff});
end
endmodule
RESULTS:
Verilog also has other system functions to generate random numbers. Each of these
functions returns a pseudo-random number whose characteristics are described by the
function name.
Following are the Verilog random number genrator system functions:
$random
$dist_chi_square
$dist_erlang
$dist_exponential
$dist_normal
$dist_poisson
$dist_t
$dist_uniform
All parameters to the system functions are integer values. For the exponential,
poisson, chi-square ,t and erlang functions the parameters mean, degree of freedom,
and k_stage must be greater than 0.
The degree of freedom parameter used with the $dist_chi_square and $dist_t
functions is an integer input that helps determine the shape of the density function.
Larger numbers spread the returned values over a wider range.
EXAMPLE:
module Tb();
integer num_1,num_2,seed;
initial
begin
seed = 10;
repeat(5)
begin
#1;
num_1 = $dist_uniform(seed,20,25);
num_2 = $dist_uniform(seed,50,55);
$display("num_1 = %d,num_2 = %d",num_1,num_2);
end
end
endmodule
RESULTS:
num_1 = 20,num_2 = 50
num_1 = 23,num_2 = 55
num_1 = 22,num_2 = 54
num_1 = 25,num_2 = 51
num_1 = 23,num_2 = 55
As i discussed $random randomizes its seed, Lets see whether $dist_uniform is also
doing the same.
EXAMPLE:
module Tb();
integer num_1,num_2,seedd,seedr;
initial
begin
seedd = 10;
seedr = 10;
repeat(5)
begin
#1;
num_1 = $dist_uniform(seedd,20,25);
num_2 = 20 + ({$random(seedr)} % 6);
$display("num_1 = %d,num_2 = %d,seedd = %d seedr =
%d",num_1,num_2,seedd,seedr);
end
end
endmodule
RESULTS:
Look at the results... Its interesting to note that $random and $dist_uniform have
same seed sequence flow also.
EXAMPLE:
module Tb();
integer num,seed;
integer num_20,num_21,num_22,num_23,num_24,num_25;
initial
begin
seed = 10;
num_20 = 0;num_21 = 0;num_22 = 0;num_23 = 0;num_24 = 0;num_25 =0;
repeat(6000)
begin
num = $dist_uniform(seed,20,25);
if(num == 20 )
num_20 = num_20 + 1;
if(num == 21)
num_21 = num_21 + 1;
if(num == 22)
num_22 = num_22 + 1;
if(num == 23)
num_23 = num_23 + 1;
if(num == 24)
num_24 = num_24 + 1;
if(num == 25)
num_25 = num_25 + 1;
end
$display("num_20 = %0d;num_21 = %0d;num_22 = %0d;num_23 = %0d;num_24 =
%0d;num_25 = %0d",num_20,num_21,num_22,num_23,num_24,num_25);
end
endmodule
RESULTS:
EXAMPLE:
module Tb();
integer num;
integer num_20,num_21,num_22,num_23,num_24,num_25;
initial
begin
seed = 10;
num_20 = 0;num_21 = 0;num_22 = 0;num_23 = 0;num_24 = 0;num_25 =0;
repeat(6000)
begin
num = 20 +( {$random(seed) } %6 );
if(num == 20 )
num_20 = num_20 + 1;
if(num == 21)
num_21 = num_21 + 1;
if(num == 22)
num_22 = num_22 + 1;
if(num == 23)
num_23 = num_23 + 1;
if(num == 24)
num_24 = num_24 + 1;
if(num == 25)
num_25 = num_25 + 1;
end
EXAMPLE:
module Tb();
integer num_1,num_2,seedd,seedr;
initial
begin
seedd = 10;
seedr = 10;
repeat(5)
begin
#1;
num_1 = $dist_uniform(seedd,20,25);
num_2 = 20 + ({$random(seedr)} % 6);
$display("num_1 = %d,num_2 = %d",num_1,num_2);
end
end
endmodule
RESULTS:
num_1 = 20,num_2 = 22
num_1 = 20,num_2 = 20
num_1 = 23,num_2 = 22
num_1 = 25,num_2 = 21
num_1 = 22,num_2 = 23
Till now what we have seen is $random has uniform distribution over integer values. It
means that distribution should be uniform across all the bits in 32 bit vector also. The
following example shows that bits positions 2,3,4,11,12,13 have equal probability of
getting 0. For demonstration I showed some index only. Try out rest of them and see
that results is same for all the bits.
EXAMPLE:
module Tb();
integer num;
integer num_2,num_3,num_4,num_11,num_12,num_13;
initial
begin
num_2 = 0;num_3 = 0;num_4 = 0;num_11 = 0;num_12 = 0;num_13 =0;
repeat(6000)
begin
num = $random;
if(num[2] == 0 )
num_2 = num_2 + 1;
if(num[3] == 0)
num_3 = num_3 + 1;
if(num[4] == 0)
num_4 = num_4 + 1;
if(num[11] == 0)
num_11 = num_11 + 1;
if(num[12] == 0)
num_12 = num_12 + 1;
if(num[13] == 0)
num_13 = num_13 + 1;
end
$display("num_2 = %0d;num_3 = %0d;num_4 = %0d;num_11 = %0d;num_12 =
%0d;num_13 = %0d",num_2,num_3,num_4,num_11,num_12,num_13);
end
endmodule
RESULTS:
The distribution is uniform for system function $random. Suppose if the requirement
is to generate random numbers for more than one variable, and all the variables
should have uniform distribution, then use different seeds for each variable. Other
wise distribution is distributed on all the variables as overall variables which mightnot
be our requirement.. But for lower bits, the distribution is same as shown in example.
EXAMPLE:
module Tb();
integer seed;
reg [1:0] var_1,var_2,var3,var4;
integer num_2,num_3,num_1,num_0;
integer cou_2,cou_3,cou_1,cou_0;
initial
begin
seed = 10;
num_2 = 0;num_3= 0;num_1= 0;num_0= 0;
cou_2= 0;cou_3= 0;cou_1= 0;cou_0= 0;
repeat(40000)
begin
var_1 = $random;
var3 = $random;
var4 = $random;
var_2 = $random;
if(var_1 == 0 )
num_0 = num_0 + 1;
if(var_1 == 1 )
num_1 = num_1 + 1;
if(var_1 == 2 )
num_2 = num_2 + 1;
if(var_1 == 3 )
num_3 = num_3 + 1;
if(var_2 == 0 )
cou_0 = cou_0 + 1;
if(var_2 == 1 )
cou_1 = cou_1 + 1;
if(var_2 == 2 )
cou_2 = cou_2 + 1;
if(var_2 == 3 )
cou_3 = cou_3 + 1;
end
$display("num_2 = %0d;num_3= %0d;num_1= %0d;num_0=
%0d;",num_2,num_3,num_1,num_0);
$display("cou_2= %0d;cou_3= %0d;cou_1= %0d;cou_0=
%0d;",cou_2,cou_3,cou_1,cou_0);
end
endmodule
RESULTS:
Use system time as seed, so the same TB simulated at different times have different
random sequences and there is more probability of finding bugs. The following is C
code useful in PLI to get system time in to verilog.
#include <stdio.h>
#include <time.h>
char *get_time_string(int mode24);
int get_systime() {
time_t seconds;
seconds = time (NULL);
return seconds;
}
In Verilog 1995 standard every simulator has its own random number generation
algorithm. But in Verilog 2001 a standard is made that every simulator has to follow
same algorithm. So the same random number sequence can seen on different
simulators for same seed.
Don't expect that the same sequence is generated on all the simulators. They are
only following same algorithm. The reason is race condition. Look at following
example, both the statements_1 and statement_2 are scheduled to execute at same
simulation time. The order of execution is not not known. Some simulators take
statement_1 as the first statement to execute and some other statement_2. If the
TB is built without any race condition to $random function calls, then the same
random sequence can be generated on different simulators and a testbench without
a racecondition on $random calls is not easy to build.
Look at the following 2 examples. I just changed the order of statements, the results
are reversed.
@edes
EXAMPLE:new
module Tb();
initial
$display("staement 2 :::%d",$random);
initial
$display("staement 1 :::%d",$random);
endmodule
staement 2 ::: 303379748
staement 1 :::-1064739199
EXAMPLE:
module Tb();
initial
$display("staement 1 :::%d",$random);
initial
$display("staement 2 :::%d",$random);
endmodule
staement 1 ::: 303379748
staement 2 :::-1064739199
Search ✔
OpenVera In addition to the system function which are in verilog, SystemVerilog has $urandom()
Constructs and $urandom_range(). $urandom() and $urandom_range() returns a unsigned values.
Switch TB The following example demonstrates random generation of unsigned numbers.
RVM Switch TB
RVM Ethernet sample EXAMPLE:
module Tb();
integer unsigned address;
Specman E initial
begin
Interview Questions repeat(5)
begin
address = $urandom();
$display("address = %d;",address);
end
end
endmodule
RESULTS:
# address = 3468265955;
# address = 541037099;
# address = 3836988758;
# address = 3611785217;
# address = 978699393;
The seed is an optional argument that determines the sequence of random numbers
generated. The seed can be any integral expression. The random number generator
(RNG) shall generate the same sequence of random numbers every time the same seed
is used.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
for(j = 0;j<4 ;j=j+1)
begin
seed = 2;
$display(" seed is set %d",seed);
void'($urandom(seed));
for(i = 0;i < 10; i=i+1)
begin
num = $urandom() % 10;
$write("| num=%2d |",num);
end
$display(" ");
end
end
endmodule
RESULTS:
seed is set 2
| num= 1 || num= 2 || num= 7 || num= 2 || num= 1 || num= 7 || num= 4 || num= 2
|| num= 3 || num= 1 |
seed is set 2
| num= 1 || num= 2 || num= 7 || num= 2 || num= 1 || num= 7 || num= 4 || num= 2
|| num= 3 || num= 1 |
seed is set 2
| num= 1 || num= 2 || num= 7 || num= 2 || num= 1 || num= 7 || num= 4 || num= 2
|| num= 3 || num= 1 |
seed is set 2
| num= 1 || num= 2 || num= 7 || num= 2 || num= 1 || num= 7 || num= 4 || num= 2
|| num= 3 || num= 1 |
$Urandom_range
EXAMPLE:
module Tb();
integer num_1,num_2;
initial
begin
repeat(5)
begin
#1;
num_1 = $urandom_range(25,20);
num_2 = $urandom_range(55,50);
$display("num_1 = %0d,num_2 = %0d",num_1,num_2);
end
end
endmodule
RESULTS:
# num_1 = 25,num_2 = 55
# num_1 = 22,num_2 = 55
# num_1 = 23,num_2 = 52
# num_1 = 21,num_2 = 54
# num_1 = 25,num_2 = 54
If minval is omitted, the function shall return a value in the range of maxval ... 0.
EXAMPLE:
module Tb();
integer num_1,num_2;
initial
begin
repeat(5)
begin
#1;
num_1 = $urandom_range(3);
num_2 = $urandom_range(5);
$display("num_1 = %0d,num_2 = %0d",num_1,num_2);
end
end
endmodule
RESULTS:
num_1 = 3,num_2 = 5
num_1 = 2,num_2 = 5
num_1 = 1,num_2 = 2
num_1 = 3,num_2 = 4
num_1 = 1,num_2 = 4
If maxval is less than minval, the arguments are automatically reversed so that the
first argument is larger than the second argument.
EXAMPLE:
module Tb();
integer num_1,num_2;
initial
begin
repeat(5)
begin
#1;
num_1 = $urandom_range(20,25);
num_2 = $urandom_range(50,55);
RESULTS:
num_1 = 25,num_2 = 55
num_1 = 22,num_2 = 55
num_1 = 23,num_2 = 52
num_1 = 21,num_2 = 54
num_1 = 25,num_2 = 54
The scope randomize function, randomize(), enables users to randomize data in the
current scope.Variables which are passed as arguments are randomized and there is
no limit on the number of arguments.For simpler applications,randomize() function
leads to stright farward implimentation.This gives better control over the $random,as
it allows to add constraints using inline constraints and constraint solver gives valid
solution.Variables which are in the constraint block and not passed as arguments to
randomize() function are not randomized.In the following example Variable Var is
randomized and MIN is not randomized.
EXAMPLE:
module scope_3;
integer Var;
initial
begin
for ( int i = 0;i<6 ;i++)
if( randomize(Var))
$display(" Randomization sucsessfull : Var = %0d ",Var);
else
$display("Randomization failed");
$finish;
end
endmodule
RESULTS:
Scope randomize function gives better control over the $random, as it allows to add
constraints using inline constraints and constraint solver gives valid solution. Variables
which are in the constraint block and not passed as arguments to randomize() function
are not randomized. In the following example Variable Var is randomized and MIN is
not randomized.
EXAMPLE:
module scope_4;
integer Var;
integer MIN;
initial
begin
MIN = 50;
for ( int i = 0;i<100 ;i++)
if( randomize(Var) with { Var < 100 ; Var > MIN ;})
$display(" Randomization sucsessfull : Var = %0d Min = %0d",Var,MIN);
else
$display("Randomization failed");
$finish;
end
endmodule
RESULTS:
Randomizing Objects
EXAMPLE:
program Simple_pro_5;
class Simple;
rand integer Var;
endclass
Simple
obj;
initial
begin
obj = new();
repeat(5)
if(obj.randomize())
$display(" Randomization successful : Var = %0d ",obj.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
EXAMPLE:
class Rand_struct;
typedef struct {
randc int Var1;
int Var2;
} Struct_t;
rand Struct_t Str; // To randomize Var1 and Struct_t type has to declared as
rand
endclass
program stru_rand_6;
Rand_struct RS ;
initial
begin
RS = new();
repeat(10)
if(RS.randomize())
$display(" Var1 : %d",RS.Str.Var1);
end
endprogram
RESULTS:
# Var1 : -430761355
# Var1 : 424439941
# Var1 : -1129955555
# Var1 : 1781908941
# Var1 : -752252755
# Var1 : 922477361
# Var1 : -2115981855
# Var1 : 1551031961
# Var1 : -91393015
# Var1 : 262093271
Simillar to struct, the same can be achived using class by calling the randomize()
function on the object, which is created by using class.
EXAMPLE:
program class_rand_7;
class Class_t;
rand int Var1;
int Var2;
endclass
class Rand_class;
rand Class_t Cla; // To randomize Var1,Class_t type has to declared as rand
function new();
Cla = new();
endfunction
endclass
Rand_class RC = new();
initial
repeat(10)
if(RC.randomize())
$display(" Var1 : %0d Var2 : %0d",RC.Cla.Var1,RC.Cla.Var2);
endprogram
RESULTS:
SystemVerilog structs are static objects, where as class instances are dynamic
objects, declaring a class instance does not allocate memory space for object. Calling
built in new() function creates memory for object. Class have built in functions and
tasks, where as struct dont, this speeds up simulation time if structs are used. Check
your data structure, if they need simple encapsulation use struct otherwise if they
need object oriented mechanisms then choose class.
Rand Case :
You can use randcase to make a weighted choice between different items, without
having to create a class and instance. An items weight divided by the sum of all
weights gives the probability of taking that branch. More details are discussed in the
following units.
Rand Sequence :
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
RESULTS:
Randc Modifier :
Variables declared as randc are random cyclic that randomly iterates over all the
values in the range and no value is repeated with in an iteration until every possible
value has been assigned. But Iteration sequences are won't be same. Bit and
enumerated types can be randc variables. To reduce memory requirements,
implementations can impose a limit on maximum size of a randc variable, it should be
not be more than 8 bits.
EXAMPLE:
class rand_c;
randc bit [1:0] Var;
endclass
program rand_cp_10;
rand_c obj=new();
initial
for(int i=0;i<20;i++)
begin
void'(obj.randomize());
$write("%0d_",obj.Var);
if(i%4==3)
$display("");
end
endprogram
RESULTS:
# 0_3_1_2_
# 3_0_2_1_
# 0_3_1_2_
# 0_1_2_3_
# 3_0_2_1_
The permutation sequence for any given randc variable is recomputed whenever the
constraints changes on that variable or when none of the remaining values in the
permutation can satisfy the constraints.
EXAMPLE:
class rand_c;
randc bit [2:0] Var;
integer MIN = 4;
constraint C { Var < MIN ;}
endclass
program rand_cp_11;
rand_c obj=new();
initial
for(int i=0;i<20;i++)
begin
obj.MIN = 4;
if(i>12)
obj.MIN=7;
void'(obj.randomize());
if(i==12)
$display(" CONSTRAINT CHANGED ");
$write("%0d_",obj.Var);
if((i%4==3))
$display("");
end
endprogram
RESULTS:
0_2_3_1_
0_1_3_2_
3_2_0_1_
CONSTRAINT CHANGED
0_1_4_2_
6_5_3_0_
EXAMPLE:
class rand_c;
randc bit [1:0]Var;
endclass
program rand_cp_12;
rand_c obj=new();
initial
for(int i=0;i<20;i++)
begin
obj=new();
void'(obj.randomize());
$write("%0d_",obj.Var);
if(i%4==3)
$display("");
end
endprogram
RESULTS:
# 1_3_1_2_
# 3_2_2_1_
# 2_0_0_0_
# 3_3_1_0_
# 3_0_1_0_
Search ✔
EXAMPLE:
program Simple_pro_14;
class Simple;
rand integer Var;
integer MIN = 20 ;
constraint c { Var < 100 ; Var > MIN ; }
endclass
Simple
obj;
initial
begin
obj = new();
if(obj.randomize())
$display(" Randomization successful : Var = %0d ",obj.Var);
else
$display("Randomization failed: Var = %0d ",obj.Var);
obj.MIN = 200;
$display(" MIN is changed to fail the constraint");
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display(" Randomization failed : Var = %0d",obj.Var);
end
endprogram
RESULTS:
EXAMPLE:
program pre_post_15;
class simple;
function void pre_randomize;
$display(" PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" POST_RANDOMIZATION ");
endfunction
endclass
simple obj = new();
initial
void'(obj.randomize());
endprogram
RESULTS:
# PRE_RANDOMIZATION
# POST_RANDOMIZATION
EXAMPLE:
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" BASE POST_RANDOMIZATION ");
endfunction
endclass
class Extend_1 extends Base;
function void pre_randomize;
$display(" EXTEND_1 PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" EXTEND_1 POST_RANDOMIZATION ");
endfunction
endclass
class Extend_2 extends Base;
function void pre_randomize;
super.pre_randomize();
$display(" EXTEND_2 PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
super.post_randomize();
$display(" EXTEND_2 POST_RANDOMIZATION ");
endfunction
endclass
program pre_post_16;
Base B = new();
Extend_1 E1 = new();
Extend_2 E2 = new();
initial
begin
void'(B.randomize());
void'(E1.randomize());
void'(E2.randomize());
end
endprogram
In the extended class EXTEND_1, when overiding the builtin functions, parent class
functions are not called. In the extended class EXTEND_2, super.methods are called
which invokes the parent class methods also.
RESULTS:
# BASE PRE_RANDOMIZATION
# BASE POST_RANDOMIZATION
# EXTEND_1 PRE_RANDOMIZATION
# EXTEND_1 POST_RANDOMIZATION
# BASE PRE_RANDOMIZATION
# EXTEND_2 PRE_RANDOMIZATION
# BASE POST_RANDOMIZATION
# EXTEND_2 POST_RANDOMIZATION
because they are automatically called by the randomize() method, which is virtual,
they appear to behave as virtual methods. This example demonstrates that these
functions are not virtual but simulation results show that, it executed extended class
definition functions. Extended class object is created and assigned to base class
object. Calls to pre_randomize and post_randomize calls in object B ,executed the
extended class definitions.
EXAMPLE:
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION ");
endfunction
virtual function void post_randomize;
$display(" BASE POST_RANDOMIZATION ");
endfunction
endclass
class Extend extends Base;
function void pre_randomize;
$display(" EXTEND PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" EXTEND POST_RANDOMIZATION ");
endfunction
endclass
program pre_post_17;
Base B ;
Extend E = new();
initial
begin
B = E ;
void'(B.randomize());
void'(E.randomize());
end
endprogram
RESULTS:
In the above example compilation error is due to the declaration of post_randmoize()
function as virtual. By removing the virtual keyword for the post_randomize()
function, calling the randomize() function by parent and child class, both will execute
functions of child class only. Which is a virtual function behaviour.
EXAMPLE:
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" BASE POST_RANDOMIZATION ");
endfunction
endclass
class Extend extends Base;
function void pre_randomize;
$display(" EXTEND PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" EXTEND POST_RANDOMIZATION ");
endfunction
endclass
program pre_post_17;
Base B ;
Extend E = new();
initial
begin
B = E ;
void'(B.randomize());
void'(E.randomize());
end
endprogram
RESULTS:
# EXTEND PRE_RANDOMIZATION
# EXTEND POST_RANDOMIZATION
# EXTEND PRE_RANDOMIZATION
# EXTEND POST_RANDOMIZATION
EXAMPLE:
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" BASE POST_RANDOMIZATION ");
endfunction
endclass
class Extend extends Base;
endclass
program pre_post_19;
Extend E = new();
initial
void'(E.randomize());
endprogram
RESULTS:
# BASE PRE_RANDOMIZATION
# BASE POST_RANDOMIZATION
EXAMPLE:
class Base;
function void pre_randomize;
$display(" BASE PRE_RANDOMIZATION \n");
endfunction
function void post_randomize;
$display(" BASE POST_RANDOMIZATION \n");
endfunction
endclass
class Extend extends Base;
function void pre_randomize;
super.pre_randomize();
$display(" EXTENDED PRE_RANDOMIZATION \n");
endfunction
function void post_randomize;
$display(" EXTENDED POST_RANDOMIZATION \n");
endfunction
endclass
program pre_post;
Base B;
Extend E = new();
initial
begin
B = E;
if(B.randomize())
$display(" randomization done \n");
end
endprogram
RESULTS:
BASE PRE_RANDOMIZATION
EXTENDED PRE_RANDOMIZATION
EXTENDED POST_RANDOMIZATION
randomization done
Results show that, if extended class is having new definition, explicitly super.pre_ or
post_ has to be called.
super.pre_randomize() is called in extended class, but super.post_randomize() is not
called in above example. See the difference in results.
If a class A instance is in Class B,To randomize class A by calling the randomize
function of class B,Class A instance has to be declared as rand variable.
EXAMPLE:
class A;
rand integer Var;
endclass
class B;
rand A obj_1 = new() ;
A obj_2 = new();
endclass
program a_b_20;
B obj=new();
initial
begin
obj.obj_1.Var = 1;
obj.obj_2.Var = 1;
repeat(10)
begin
void'(obj.randomize());
$display(" Var1 = %d ,Var2 = %d ",obj.obj_1.Var,obj.obj_2.Var );
end
end
endprogram
RESULTS:
Look at the results. Variable of obj_2 is not randomized. Only variable of obj_1 which
is declared as rand is ranomized.
Upon calling the randomize method of B object which contains rand A object, First B
prerandomize is called, then A prerandomize method is called, then B is randomized,
if a solution was found, new values are assigned to the random A objects.If solution
was found, for each random object that is a class instance it's post_randomize method
is called. That means if randomization is successful next B postrandomize, next A
postrandomize functions are called. Upon calling B randomize function this is
sequence it follow.
EXAMPLE:
class A;
rand integer Var;
function void pre_randomize;
RESULTS:
# B PRE_RANDOMIZATION
# A PRE_RANDOMIZATION
# B POST_RANDOMIZATION
# A POST_RANDOMIZATION
EXAMPLE:
class A;
rand bit [2:0] Var;
constraint randge_c { Var > 2 ; Var < 2;}
function void pre_randomize;
$display(" A PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" A POST_RANDOMIZATION ");
endfunction
endclass
class B;
rand A obj_a;
function void pre_randomize;
$display(" B PRE_RANDOMIZATION ");
endfunction
function void post_randomize;
$display(" B POST_RANDOMIZATION ");
endfunction
function new();
obj_a = new();
endfunction
endclass
program pre_post_22;
B obj_b = new();
initial
void'(obj_b.randomize());
endprogram
RESULTS:
# B PRE_RANDOMIZATION
# A PRE_RANDOMIZATION
The random nature of variables declared as rand or randc can be turned on or off
dynamically. To change the status of variable which is declared as rand or randc to
state variable, built in rand_mode() method is used. State variables are not
randomized by randomize() mehod. By default all rand and randc variables are active.
When called as a task, the arguments to the rand_mode method determines the
operation to be performed. If the arguments is 0, then all the variables declared as
rand and randc will become non random i.e all random variables treated as state
variables. IF argument is 1, then all variables declares as rand and randc will be
randomized.
EXAMPLE:
class rand_mo;
rand integer Var1;
rand integer Var2;
endclass
program rand_mo_p_23;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.rand_mode(0); // Var1 and Var2 will be treated as State variables.
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.rand_mode(1); // // Var1 and Var2 will be treated as random
variables.
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
RESULTS:
If arguments are Variable name, then only that variable will be non random.
EXAMPLE:
class rand_mo;
rand integer Var1;
rand integer Var2;
endclass
program rand_mo_p_24;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var1.rand_mode(0); // Var1 will become State variable
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var2.rand_mode(0); // Var2 will also become State variable
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var1.rand_mode(1); // // Var1 will become random variable
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
RESULTS:
When rand_mode method is called as function, it returns the active status of the
specified random variable.
EXAMPLE:
class rand_mo;
rand integer Var1;
rand integer Var2;
endclass
program rand_mo_p_24;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var1.rand_mode(0);
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
if(obj.Var1.rand_mode())
$display(" Var1 is random");
else
$display(" Var1 is nonrandom");
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
RESULTS:
If you are changing the status of a variable, which is not existing it is compilation
error.
EXAMPLE:
class rand_mo;
rand integer Var1;
rand integer Var2;
endclass
program rand_mo_p_24;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var3.rand_mode(0);
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
if(obj.Var3.rand_mode())
$display(" Var3 is nonrandom");
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
A compiler error shall be issued if the specified variable does not exist within the
class hierarchy or eventhough it exists but not declared as rand or randc. The
following example illustrates the second case.
EXAMPLE:
class rand_mo;
rand integer Var1;
integer Var2;
endclass
program rand_mo_p_24;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var2.rand_mode(0);
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
if(obj.Var2.rand_mode())
$display(" Var1 is nonrandom");
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
In the above example, Var2 is state variable. If the random variable is an object
handle, only the mode of the object is changed, not the mode of random variables
within that object.
EXAMPLE:
class rand_var;
rand integer Var2;
endclass
class rand_mo;
rand integer Var1;
rand rand_var rv;
function new();
rv = new();
endfunction
endclass
program rand_mo_p_23;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.rv.Var2);
obj.rand_mode(0);
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.rv.Var2);
void'(obj.rv.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.rv.Var2);
end
endprogram
RESULTS:
EXAMPLE:
class A;
rand static integer Var1;
rand integer Var2;
endclass
program A_p_27;
A obj_1 = new;
A obj_2 = new;
initial
begin
obj_2.Var1.rand_mode(0);
obj_2.Var2.rand_mode(0);
repeat(2)
begin
void'(obj_1.randomize());
void'(obj_2.randomize());
$display("obj_1.Var1 : %d ,obj_1.Var2 : %d : obj_2.Var1 : %d ,obj_2.Var2 : %d
:",obj_1.Var1,obj_1.Var2,obj_2.Var1,obj_2.Var2);
end
end
endprogram
RESULTS:
Random variables declared as static are shared by all instances of the class in which
they are declared. Each time the randomize() method is called, the variable is
changed in every class instance.
All the variables(randc, rand and nonrandom variables) randomization nature can be
changed dynamically. Using rand_mode() rand and randc varibles changes its nature.
The random nature of variables which are not declared as rand or randc can also be
randomized dynamically. When the randomize method is called with no arguments, it
randomizes the variables which are declared as rand or randc,so that all of the
constraints are satisfied. When randomize is called with arguments, those arguments
designate the complete set of random variables within that object, all other variables
in the object are considered state variables.
EXAMPLE:
class CA;
rand byte x, y;
byte v, w;
constraint c1 { x < v && y > w ;}
endclass
program CA_p_28;
CA a = new;
initial
begin
a.x = 10;a.y = 10;a.v = 10;a.w = 10;
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize()); // random variables: x, y state variables: v, w
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize(x)); // random variables: x state variables: y, v, w
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize(v,w)); // random variables: v, w state variables: x, y
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize(w,x)); // random variables: w, x state variables: y, v
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
end
endprogram
RESULTS:
In above example x and y are rand variables, v and w are state variables. When
a.randomize() is called, all rand varibles are randomized and state variables are hold
the same value. When a.randomize(w) is called, only w is considered as rand variable
and all others as state varibles. Here w is in constraint block so it has to satisfy the
constraints. v,y and x also are state variables now, they also need to satisfy the
constraint else it fails.
Replacing the class variables, with its hierarchical result also should result same.
EXAMPLE:
program CA_p_29;
CA a = new;
initial
begin
a.x = 10;a.y = 10;a.v = 10;a.w = 10;
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize()); // random variables: x, y state variables: v, w
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize( a.x )); // random variables: x state variables: y, v, w
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize( a.v, a.w )); // random variables: v, w state variables: x, y
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
void'(a.randomize( a.w, a.x )); // random variables: w, x state variables: y, v
$display(" x : %3d y : %3d : v : %3d : w : %3d ",a.x,a.y,a.v,a.w);
end
endprogram
RESULTS:
If you are not interested to satisfy the constraints in constraint block, instead of
switching off the constraint block, just randomize the variables using scope
randomize() function. Scope randomize provide the ability to randomize class
variables also along with non class variables.
EXAMPLE:
program CA_p_30;
integer x,y,v,w;
initial
begin
x = 10;y = 10;v = 10;w = 10;
$display(" x : %3d y : %3d : v : %3d : w : %3d ",x,y,v,w);
randomize( x ); // random variables: x state variables: y, v, w
$display(" x : %3d y : %3d : v : %3d : w : %3d ",x,y,v,w);
randomize(v,w ); // random variables: v, w state variables: x, y
$display(" x : %3d y : %3d : v : %3d : w : %3d ",x,y,v,w);
randomize(w,x ); // random variables: w, x state variables: y, v
$display(" x : %3d y : %3d : v : %3d : w : %3d ",x,y,v,w);
end
endprogram
RESULTS:
Search ✔
Specman E EXAMPLE:
Interview Questions class Base;
rand integer Var;
integer MIN,MAX;
constraint randge_r { Var < MAX ; Var > MIN ;}
constraint checker_c{ MIN < MAX ;} // This checks that these dynamic variables are
valid
task set (integer MIN,integer MAX);
this.MIN = MIN;
this.MAX = MAX;
$display( " SET : MIN = %0d , MAX = %0d ",MIN,MAX);
endtask
endclass
program inhe_26;
Base obj;
initial
begin
obj = new();
obj.set(0,100) ;
for(int i=0 ; i < 5 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
obj.set(50,10) ;
for(int i=0 ; i < 5 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
Search ✔
Adding new constraints in the derived class, can change the solution space. Solver has
to solve both constraints defined in base class and derived class. In the example given
below, Constraint range_1 defines the range that Var is between 0 to 100.Constraint
range_2 limits the Var to be greater than 50 and solver has to solve both the
constraints and the solution space is between 50 to 100.
EXAMPLE:
class Base;
rand integer Var;
constraint range_1 { Var < 100 ; Var > 0 ;}
endclass
class Extended extends Base;
constraint range_2 { Var > 50 ;} // Adding new constraints in the Extended class
endclass
program inhe_32;
Extended obj;
initial
begin
obj = new();
for(int i=0 ; i < 20 ; i++)
if(obj.randomize())
$write(": Var = %0d :",obj.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
Overrighting Constraints
The randomize() task is virtual. Accordingly it treats the class constraints in a virtual
manner. When a named constraint is redefined in an extended class, the previous
definition is overridden and when casting extended class to base class does not change
the constraint set.
EXAMPLE:
class Base;
rand integer Var;
constraint range { Var < 100 ; Var > 0 ;}
endclass
class Extended extends Base;
constraint range { Var == 100 ;} // Overrighting the Base class constraints.
endclass
program inhe_33;
Extended obj_e;
Base
obj_b;
initial
begin
obj_e = new();
obj_b = obj_e;
for(int i=0 ; i < 7 ; i++)
if(obj_b.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj_b.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
When an extended object is casted to base object, all the constraints in extended
object are solved along with the constraints in base object.
EXAMPLE:
class Base;
rand integer Var;
constraint range_1 { Var < 100 ; Var > 0 ;}
endclass
class Extended extends Base;
constraint range_2 { Var > 50 ;}
endclass
program inhe_34;
Extended obj_e;
Base
obj_b;
initial
begin
obj_e = new();
obj_b = obj_e;
for(int i=0 ; i < 10 ; i++)
if(obj_b.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj_b.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
Search ✔
In the above example, by default only default_c constraints are considered. Using
inline constraint Var == 50 resulted value on variable Var based on both the default_c
OpenVera and inline constraints.
Constructs
Switch TB
The scope for variable names in a constraint block, from inner to outer, is
RVM Switch TB randomize()...with object class, automatic and local variables, task and function
RVM Ethernet sample arguments, class variables, and variables in the enclosing scope. The
randomize()...with class is brought into scope at the innermost nesting level. In the
f.randomize() with constraint block, x is a member of class Foo and hides the x in
program Bar. It also hides the x argument in the doit() task. y is a member of Bar. z is
Specman E a local argument.
Interview Questions
In the example below, the randomize()...with class is Foo.
EXAMPLE:
class Foo;
rand integer x;
endclass
program Bar_36;
Foo obj = new();
integer x;
integer y;
task doit(Foo f, integer x, integer z);
int result;
result = f.randomize() with {x < y + z;};
$display(":: obj.x : %d :: x : %d :: y : %d :: z : %d ::",obj.x,x,y,z);
endtask
initial
begin
x = 'd10;
repeat(5)
begin
y = $urandom % 10;
doit(obj,x ,'d12);
end
end
endprogram
RESULTS:
:: obj.x : -1538701546 :: x : 10 :: y : 5 :: z : 12 ::
:: obj.x : -1048494686 :: x : 10 :: y : 9 :: z : 12 ::
:: obj.x : -1122673684 :: x : 10 :: y : 8 :: z : 12 ::
:: obj.x : -2050360121 :: x : 10 :: y : 7 :: z : 12 ::
:: obj.x : -886228933 :: x : 10 :: y : 3 :: z : 12 ::
By seeing this output we can tell the variable which used in inline constraint is class
member x.
Search ✔
Specman E
Interview Questions
Search ✔
EXAMPLE:
Specman E class rand_mo;
Interview Questions rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
endclass
program rand_mo_p_38;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
RESULTS:
When it is called as function, it returns the active status of the specified constraint
block.
EXAMPLE:
class rand_mo;
rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
endclass
program rand_mo_p_38;
rand_mo obj = new();
initial
begin
void'(obj.randomize()); //By default all constraints are active.
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var_1.constraint_mode(0); //Both constraint Var_1 is are turned
off.
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
if (obj.Var_1.constraint_mode())
$display("Var_1 constraint si active");
else
$display("Var_1 constraint si inactive");
if (obj.Var_2.constraint_mode())
$display("Var_2 constraint si active");
else
$display("Var_2 constraint si inactive");
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
RESULTS:
If you are changing the status of a constraint block, which is not existing, then there
should be a compilation error else contact your Application engineer to file the bug.
EXAMPLE:
class rand_mo;
rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
endclass
program rand_mo_p_38;
rand_mo obj = new();
initial
begin
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
obj.Var_3.constraint_mode(0);
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
if(obj.Var_3.constraint_mode())
$display(" Vat_1 constraint block is off");
void'(obj.randomize());
$display(" Var1 : %d Var2 : %d ",obj.Var1,obj.Var2);
end
endprogram
Search ✔
//
OpenVera EXAMPLE:
Constructs class Base;
Switch TB rand integer Var;
`include "constraint.sv"
RVM Switch TB endclass
RVM Ethernet sample
program inhe_40;
Base obj;
initial
Specman E begin
Interview Questions obj = new();
for(int i=0 ; i < 100 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
end
endprogram
Constraint Hiding
In SV Std 1800-2005 LRM , its not mentioned any where that constraints can be
declared as local or protected. If they support to declare constraints as local, it would
be helpful not to switchoff the constraint block accedentally is it is not supposed to
be done. The constraint BNF explicitly excludes the local and protected modifiers.
The main reason for their exclusion is because constraints behave like virtual methods
that are called by the built-in randomize method. If a constraint were declared
local/protected it would still be visible to randomize and participate in the constraint
equations. The only limitation would be to call the constraint_mode on
local/protected constraints from certain methods, and this does not seem very useful
and probably create more confusion with regards to overridden methods.
Search ✔
...etc.
As in this example,a single object is created and randomized 100 times. Due to
this,pre_reandomize is called 100 times, which may not be preferred.
By assigning the values while declaration itself this can be avoided. Simpler way to
achieve the above logic.
EXAMPLE:
`define MAX_D 100
`define MIN_D 50
class Base;
rand integer Var;
integer MIN = `MIN_D;
integer MAX = `MAX_D;
constraint range { Var < MAX ; Var > MIN ;}
endclass
program inhe_43;
Base obj;
initial
begin
obj = new();
for(int i=0 ; i < 100 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
With the above approach also, dynamic controlability is lost. For dynamic
controllability, define a task, pass this values as arguments when ever the changed is
needed.
EXAMPLE:
class Base;
rand integer Var;
integer MIN = 10,MAX = 20; // Define default values,If function set is not
called,with this it will work
constraint randge { Var < MAX ; Var > MIN ;}
task set (integer MIN,integer MAX);
this.MIN = MIN;
this.MAX = MAX;
$display( " SET : MIN = %0d , MAX = %0d ",MIN,MAX);
endtask
endclass
program inhe_44;
Base obj;
initial
begin
obj = new();
obj.set(0,100) ;
for(int i=0 ; i < 5 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
obj.set(50,100) ;
for(int i=0 ; i < 5 ; i++)
if(obj.randomize())
$display(" Randomization sucsessfull : Var = %0d ",obj.Var);
else
$display("Randomization failed");
end
endprogram
RESULTS:
More simpler way to dynamically modifying the constraints is by modifying the data
members of class via object reference.
EXAMPLE:
class Base;
rand integer Var;
integer MIN = 20,MAX =30;
constraint randge { Var < MAX ; Var > MIN ;}
endclass
program inhe_45;
Base obj;
initial
begin
obj = new();
obj.MIN = 0;
obj.MAX = 100;
for(int i=0 ; i < 5 ; i++)
if(obj.randomize())
RESULTS:
Search ✔
Specman E
Interview Questions
Search ✔
If you want to define a range which is outside the set, use negation.
OpenVera
Constructs
Switch TB EXAMPLE:
class set_mem;
RVM Switch TB rand bit [0:2] Var;
RVM Ethernet sample constraint range { !( Var inside {0,1,5,6});}
function void post_randomize();
$write("%0d__",Var);
endfunction
Specman E endclass
Interview Questions
program set_mem_p_48;
set_mem obj=new();
initial
repeat(10)
void'(obj.randomize());
endprogram
RESULTS:
7__4__4__4__7__2__2__3__2__7__
Engineers often mistaken that set membership operator is used only in constraint
block. It can also be used in other scopes also.
class set_mem;
rand bit [0:2] Var;
endclass
program set_mem_p_48;
set_mem obj=new();
integer repet = 0;
initial
begin
obj.Var = 1;
repeat(10)
begin
void'(obj.randomize());
while ( obj.Var inside {[1:5]})
begin
$display("Var = %0d",obj.Var);
break;
end
end
end
endprogram
RESULTS:
# Var = 4
# Var = 5
# Var = 1
# Var = 1
# Var = 2
# Var = 2
NOTE: X and Z are allowed in set membership operator, but not in constraint block,
inside {....} is a statement which returns 0,1 or X .
Expressions are allowed in value set of inside operator.
rand integer y,x;
constraint c1 {x inside {3, 5,[y:2*y], z};}
If an expression in the list is an array then just use the array name in the constraint
block. Elements are traversed by descending into the array until reaching a singular
value.
int array [$] = '{3,4,5};
if ( ex inside {1, 2, array} )
Weighted Distribution
Var dist { 10 := 1; 20 := 2 ; 30 := 2 }
The probability of Var is equal to 10,20 and 30 is in the ratio of 1,2,2 respectively.
Var dist { 10 := 1; 20 := 2 ; [30:32] := 2 }
Var dist { 10 := 1; 20 := 2 ; [30:32] :/ 2 }
EXAMPLE:
class Dist;
rand integer Var;
constraint range { Var dist { [0:1] := 50 , [2:7] := 50 }; }
endclass
program Dist_p_49;
Dist obj;
integer count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7;
integer count_0_1 ,count_2_7 ;
initial
begin
obj=new();
count_0 = 0;count_1 = 0;count_2 = 0;count_3 = 0;
count_4 = 0;count_5 = 0;count_6 = 0;count_7 = 0;
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
if( obj.randomize())
begin
if( obj.Var == 0) count_0 ++;
else if( obj.Var == 1) count_1 ++;
else if( obj.Var == 2) count_2 ++;
else if( obj.Var == 3) count_3 ++;
else if( obj.Var == 4) count_4 ++;
else if( obj.Var == 5) count_5 ++;
else if( obj.Var == 6) count_6 ++;
else if( obj.Var == 7) count_7 ++;
if( obj.Var inside {0,1} ) count_0_1 ++;
else if( obj.Var inside {[2:7]} ) count_2_7 ++;
end
$display(" count_0 = %0d , count_1 = %0d, count_2 = %0d, count_3 = %0d, count_4 =
%0d, count_5 = %0d, count_6 = %0d, count_7= %0d
",count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7);
$display(" count_0_1 = %0d ;count_2_7 = %0d ",count_0_1,count_2_7);
$finish;
end
endprogram
RESULTS:
# count_0 = 1290 , count_1 = 1244, count_2 = 1286, count_3 = 1265, count_4 = 1230,
count_5 = 1243, count_6 = 1189, count_7= 1253
# count_0_1 = 2534 ;count_2_7 = 7466
EXAMPLE:
class Dist;
rand integer Var;
constraint range { Var dist { [0:1] :/ 50 , [2:7] :/ 50 }; }
endclass
program Dist_p_50;
Dist obj;
integer count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7;
integer count_0_1 ,count_2_7 ;
initial
begin
obj=new();
count_0 = 0;count_1 = 0;count_2 = 0;count_3 = 0;
count_4 = 0;count_5 = 0;count_6 = 0;count_7 = 0;
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
if( obj.randomize())
begin
if( obj.Var == 0) count_0 ++;
else if( obj.Var == 1) count_1 ++;
else if( obj.Var == 2) count_2 ++;
else if( obj.Var == 3) count_3 ++;
else if( obj.Var == 4) count_4 ++;
else if( obj.Var == 5) count_5 ++;
else if( obj.Var == 6) count_6 ++;
else if( obj.Var == 7) count_7 ++;
if( obj.Var inside {0,1} ) count_0_1 ++;
else if( obj.Var inside {[2:7]} ) count_2_7 ++;
end
$display(" count_0 = %0d , count_1 = %0d, count_2 = %0d, count_3 = %0d, count_4 =
%0d, count_5 = %0d, count_6 = %0d, count_7= %0d
",count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7);
$display(" count_0_1 = %0d ;count_2_7 = %0d ",count_0_1,count_2_7);
$finish;
end
endprogram
RESULTS:
# count_0 = 2496, count_1 = 2508, count_2 = 846, count_3 = 824, count_4 = 833,
count_5 = 862, count_6 = 820, count_7= 811
# count_0_1 = 5004 ;count_2_7 = 4996
Both the results show, how may times each value occured.
If there are constraints on some expressions that cause the distribution weights on
these expressions to be not satisfiable, implementations are only required to satisfy
the non dist constraints. Use dist only on a one variable in a set of constraint
expression variable.
In the following example, Even though probability of Var2 is equal to 0 to 1 is in ratio
of 50, 50 to satisfy other constraints, the dist is ignored.
EXAMPLE:
class Dist;
rand integer Var1,Var2;
constraint dist_c { Var2 dist { [0:1] := 50 , [2:7] := 50 }; }
constraint relation_c { Var1 < Var2; }
constraint range_c { Var2 inside {2,3,4};}
endclass
program Dist_p_51;
Dist obj;
integer count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7;
integer count_0_1 ,count_2_7 ;
initial
begin
obj=new();
count_0 = 0;count_1 = 0;count_2 = 0;count_3 = 0;
count_4 = 0;count_5 = 0;count_6 = 0;count_7 = 0;
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
if( obj.randomize())
begin
if( obj.Var2 == 0) count_0 ++;
else if( obj.Var2 == 1) count_1 ++;
else if( obj.Var2 == 2) count_2 ++;
else if( obj.Var2 == 3) count_3 ++;
else if( obj.Var2 == 4) count_4 ++;
else if( obj.Var2 == 5) count_5 ++;
else if( obj.Var2 == 6) count_6 ++;
else if( obj.Var2 == 7) count_7 ++;
if( obj.Var2 inside {0,1} ) count_0_1 ++;
else if( obj.Var2 inside {[2:7]} ) count_2_7 ++;
end
$display(" count_0 = %0d , count_1 = %0d, count_2 = %0d, count_3 = %0d, count_4 =
%0d, count_5 = %0d, count_6 = %0d, count_7= %0d
",count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7);
$display(" count_0_1 = %0d ;count_2_7 = %0d ",count_0_1,count_2_7);
$finish;
end
endprogram
RESULTS:
EXAMPLE:
class Dist;
rand integer Var;
constraint range { Var dist { [0:1] := 50 , [2:7] := 50 }; }
endclass
program Dist_p_52;
Dist obj;
integer count_0_1 ,count_2_7 ;
initial
begin
obj=new();
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
begin
obj = new();
if( obj.randomize())
if( obj.Var inside {0,1} ) count_0_1 ++;
else if( obj.Var inside {[2:7]} ) count_2_7 ++;
end
$display("count_0_1 : %0d : count_2_7 : %0d ",count_0_1,count_2_7);
end
endprogram
RESULTS:
The distribution is not followed if the variable is declared as randc as distribution may
require repetition and randc doesnot allow. In the below example try changing the
weights in distribution function, you will get always same results otherwise
compilation error.
EXAMPLE:
class Dist;
randc byte Var;
constraint range { Var dist { [0:1] := 50 , [2:7] := 50 }; }
endclass
program Dist_p_52;
Dist obj;
integer count_0_1 ,count_2_7 ;
initial
begin
obj=new();
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
begin
if( obj.randomize())
if( obj.Var inside {0,1} ) count_0_1 ++;
else if( obj.Var inside {[2:7]} ) count_2_7 ++;
end
$display("count_0_1 : %0d : count_2_7 : %0d ",count_0_1,count_2_7);
end
endprogram
To constraint enumerated values using dist, if they are less number, give weights
individually. If you want to give weights to enumerated values in groups, then give a
continues group. As enumeration is represented in integer, the discontinuation in the
declaration may not result properly.
EXAMPLE:
program enums_53;
typedef enum {V_SMALL,SMALL,MEDIUM,LARGE,V_LARGE} size_e;
class dist_c;
rand size_e size_d;
constraint size_dist{size_d
dist {[V_SMALL:MEDIUM] :/40,[LARGE:V_LARGE] :/ 60}; }
endclass
initial begin
dist_c obj;
obj=new;
for (int i=0; i<=10; i++)
begin
obj.randomize();
$display (" size_d = %0s ", obj.size_d);
end
end
endprogram
Implication
rand bit a;
rand bit [3:0] b;
constraint c { (a == 0) -> (b == 1); }
a is one and b is 4 bit, So there are total of 32 solutions. But due to constraint c
(when ever a is 0 b should be 1) 15 solutions are removed. So probability of a = 0 is
1/(32-15) = 1/17. If u observe the following program results count_0/count_1
approximately equal to 1/17.
EXAMPLE:
class impli;
rand bit a;
rand bit [3:0] b;
constraint c { (a == 0) -> (b == 1); }
endclass
program impli_p_54;
impli obj;
integer count_0 ,count_1 ;
initial
begin
obj=new();
count_0 = 0;count_1 = 0;
for(int i=0; i< 10000; i++)
begin
if( obj.randomize())
if( obj.a == 0 ) count_0 ++;
else count_1 ++;
end
$display(" count_0 = %0d;count_1 = %0d; ",count_0 ,count_1);
end
endprogram
RESULTS:
If..Else
EXAMPLE:
class if_else;
rand bit a;
rand bit [3:0] b;
constraint c { if(a == 0) (b == 1); }
endclass
program if_else_p_55;
if_else obj;
integer count_0 ,count_1 ;
initial
begin
obj=new();
count_0 = 0;count_1 = 0;
for(int i=0; i< 10000; i++)
begin
obj = new();
if( obj.randomize())
begin
Search ✔
RESULTS:
Too many explicit variable ordering may lead to circular dependency. The LRM says
that "Circular dependencies created by the implicit variable ordering shall result in an
error." and "circular dependency is not allowed". But it does not put restriction on
what to do if a explicit circular dependency exists. Check with your tool, if explicit
Circular dependency is existing, it may report warning,it may fail solver or proceed by
just ignoring the order.
EXAMPLE:
program Cir_Dip_p_58;
class Cir_Dep;
rand integer a,b,c;
constraint a_c { solve a before b ;}
constraint b_c { solve b before c ;}
constraint c_c { solve c before a ;}
endclass
Cir_Dip obj=new();
initial
void'(obj.randomize());
endprogram
RESULTS:
LRM says, if the outcome is same, solver can solve without following the rule. In the
following case, x has only one possible assignment (0), so x can be solved for before
y. The constraint solver can use this flexibility to speed up the solving process.
EXAMPLE:
class slove_before;
rand integer x,y;
constraint C {x == 0;
x < y;
solve y before x; }
endclass
program s_b_59;
slove_before obj ;
initial
begin
obj = new();
repeat(5)
if(obj.randomize())
$display(" x : %d :: y :%d ",obj.x,obj.y);
else
$display("Randomization failed ");
end
endprogram
RESULTS:
Functions
Functions are allowed in constraints. It will be useful in applications like constrain the
max packet size based on the bandwidth other parameters. Constraint statements are
more error pron. Functions in constraints are called before constraints are solved. The
return value of the function is used to solve the constraint and it is treated as state
variable. There is an implicit variable ordering when solving these constraints.
Function should not be declared as static and should not modify the constraints, for
example calling the rand_mode and constraint_mode methods.
EXAMPLE:
class B_61;
rand int x, y;
constraint C { x <= F(y); }
constraint D { y inside { 2, 4, 8 } ; }
endclass
Iterative Constraints
EXAMPLE:
class Eth_pkt_60;
rand byte Payload[] ;
constraint size_c { Payload.size() inside {[10:1500]}; }
constraint element_c { foreach ( Payload[ i ] ) Payload[ i ] inside {[50:100]}; }
function void post_randomize;
foreach(Payload[i])
$display( " Payload[ %0d ] :%d ",i,Payload[ i ] );
endfunction
endclass
program iterative_60;
Eth_pkt_60 obj;
initial
begin
obj = new();
if(obj.randomize())
$display(" RANDOMIZATION DONE ");
end
endprogram
RESULTS:
# Payload[ 0 ] : 87
# Payload[ 1 ] : 52
# Payload[ 2 ] : 70
# Payload[ 3 ] : 76
# Payload[ 4 ] : 71
# Payload[ 5 ] : 63
# Payload[ 6 ] : 62
# Payload[ 7 ] : 63
# Payload[ 8 ] : 66
# Payload[ 9 ] : 85
# Payload[ 10 ] : 95
# Payload[ 11 ] : 57
# Payload[ 12 ] : 78
Search ✔
RESULT:
constraint C { $countones(array) == 1 ;)
constraint C { Var == (1 << index) ;}
Instead declare an 5 bit variable index, randomize it and set the index bit to 1 in post
randomize.
EXAMPLE:
class expo_cons_64;
rand bit [0:4] index;
integer array; // No need to randomize array
function void post_randomize;
array = 'b0;
array[index]=1'b1;
endfunction
endclass
EXAMPLE:1
class constr;
rand int a,b,c,d;
constraint C { (a == 10)&&( b < 20 ) && (c > 30) && (d < 40) ;}
endclass
program constr_p_65;
constr obj;
initial
begin
obj=new();
repeat(10000)
void'(obj.randomize());
$finish(2);
end
endprogram
RESULT:
EXAMPLE:2
class constr;
rand int a,b,c,d;
constraint Ac {(a == 10);}
constraint Bc {(b < 20) ;}
constraint Cc {(c > 30) ;}
constraint Dc {(d < 40) ;}
endclass
program constr_p_66;
constr obj;
initial
begin
obj=new();
repeat(10000)
void'(obj.randomize());
$finish(2);
end
endprogram
RESULT:
EXAMPLE:3
class constr_67;
rand int a,b,c,d;
constraint Ac { (a == 10) ; ( b < 20 ) ; (c > 30) ; (d < 40) ;}
endclass
program constr_p_67;
constr_p_67 obj;
initial
begin
obj=new();
repeat(10000)
void'(obj.randomize());
$finish(2);
end
endprogram
RESULT:
Run all the above three examples with your simulator and check how your simulation
speed varies.
When iterative constraints are used on arrays, each element has a constraint on it. If
the constraints are simple enough to implement with out using constraint block,
simulation time may be saved. In the following example, there are two constraints
blocks, one for size other for each element. In reality there may be more constraint
blocks.
EXAMPLE:
class Eth_pkt;
rand byte Payload[] ;
constraint size_c { Payload.size() inside {[46:1500]}; }
constraint element_c { foreach ( Payload[ i ] ) Payload[ i ] inside {[50:100]}; }
endclass
program iterative_68;
Eth_pkt obj;
initial
begin
obj = new();
for(int i=0;i< 10000;i++)
begin
if(obj.randomize())
$display(" RANDOMIZATION DONE ");
end
$finish(2);
end
endprogram
RESULT:
The above logic can implemented using post_randomize. Check how these two
example with ur vendor tool and look at the simulation speed. You may find
difference.
EXAMPLE:
class Eth_pkt;
rand integer length;
byte Payload[] ;
constraint size_c { length inside {[46:1500]}; }
function void post_randomize;
Payload = new[length];
for(int i=0;i< length;i++)
Payload[ i ] = 50 + $urandom % 51 ;
endfunction
endclass
program iterative_69;
Eth_pkt obj;
initial
begin
obj = new();
for(int i=0;i< 10000;i++)
begin
if(obj.randomize())
$display(" RANDOMIZATION DONE ");
end
$finish(2);
end
endprogram
Search ✔
RESULTS:
Search ✔
OpenVera
Constructs The production main is defined in terms of three nonterminals: one, two and three.
Switch TB Productions one,two and three are terminals. When the main is chosen, it will select
the sequence one, two and three in order.
RVM Switch TB
RVM Ethernet sample
Random Productions:
A single production can contain multiple production lists separated by the | symbol.
Specman E Production lists separated by a | imply a set of choices, which the generator will
Interview Questions make at random.
EXAMPLE:
module rs();
initial
repeat(8)
randsequence( main )
main : one | two | three ;
one : {$display("one");};
two : {$display("two");};
three: {$display("three");};
endsequence
endmodule
RESULTS:
# three
# three
# three
# three
# one
# three
# two
# two
Results show that one, two and three are selected randomly.
EXAMPLE:
module rs();
integer one_1,two_2,three_3;
initial
begin
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(6000)
randsequence( main )
main : one := 1| two := 2| three := 3;
one : {one_1++;};
two : {two_2++;};
three: {three_3++;};
endsequence
$display(" one %0d two %0d three %0d",one_1,two_2,three_3);
end
endmodule
RESULTS:
If..Else
EXAMPLE:
module rs();
integer one_1,two_2,three_3;
reg on;
initial
begin
on = 0;
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(2500)
randsequence( main )
main : one three;
one : {if(on) one_1++; else two_2 ++; };
three: {three_3++;};
endsequence
$display(" one %0d two %0d three %0d",one_1,two_2,three_3);
end
endmodule
RESULTS:
Case
EXAMPLE:
module rs();
integer one_1,two_2,three_3;
initial
begin
one_1 = 0;
two_2 = 0;
three_3 = 0;
for(int i = 0 ;i < 6 ;i++)
begin
randsequence( main )
main : case(i%3)
0 : one;
1 : two;
default: def;
endcase;
one : {$display("one");};
two : {$display("two");};
def : {$display("default");};
endsequence
end
end
endmodule
RESULTS:
one
two
default
one
two
default
EXAMPLE:
module rs();
integer one_1,two_2,three_3;
initial
begin
one_1 = 0;
two_2 = 0;
three_3 = 0;
repeat(6000)
randsequence( main )
main : one | repeat(2) two | repeat (3) three ;
one : one_1++;
two : two_2++;
three: three_3++;
endsequence
$display(" one %d two %d three %d",one_1,two_2,three_3);
end
endmodule
RESULTS:
Rand Join
The rand join production control is used to randomly interleave two or more
production sequences while maintaining the relative order of each sequence.
EXAMPLE:
module rs();
initial
for(int i = 0;i < 24;i++) begin
randsequence( main )
main : rand join S1 S2 ;
S1 : A B ;
S2 : C D ;
A : $write("A");
B : $write("B");
C : $write("C");
D : $write("D");
endsequence
if(i%4 == 3 )
$display("");
end
endmodule
RESULTS:
ABCD
A C BD
A C DB
C D AB
C A BD
C A DB
Note that B always comes after A and D comes after C. The optional expression
following the rand join keywords must be a real number in the range 0.0 to 1.0. The
value of this expression represents the degree to which the length of the sequences to
be interleaved affects the probability of selecting a sequence. A sequences length is
the number of productions not yet interleaved at a given time. If the expression is
0.0, the shortest sequences are given higher priority. If the expression is 1.0, the
longest sequences are given priority.
EXAMPLE:
module rs();
initial
for(int i = 0;i < 24;i++) begin
randsequence( main )
main : rand join (0.0) S1 S2 ;
S1 : A B ;
S2 : C D ;
A : $write("A");
B : $write("B");
C : $write("C");
D : $write("D");
endsequence
if(i%4 == 3 )
$display("");
end
endmodule
RESULTS:
A BCD
C DAB
A CBD
A CDB
C ABD
C ADB
EXAMPLE:
module rs();
initial
for(int i = 0;i < 24;i++) begin
randsequence( main )
main : rand join (1.0) S1 S2 ;
S1 : A B ;
S2 : C D ;
A : $write("A");
B : $write("B");
C : $write("C");
D : $write("D");
endsequence
if(i%4 == 3 )
$display("");
end
endmodule
RESULTS:
A CBD
A CDB
C ADB
C ADB
A BCD
C DAB
C ABD
Break
The break statement terminates the sequence generation. When a break statement is
executed from within a production code block, it forces a jump out the randsequence
block.
EXAMPLE:
randsequence()
WRITE : SETUP DATA ;
SETUP : { if( fifo_length >= max_length ) break; } COMMAND ;
DATA : ...
endsequence
When the example above executes the break statement within the SETUP production,
the COMMAND production is not generated, and execution continues on the line
labeled next_statement.
Return
The return statement aborts the generation of the current production. When a return
statement is executed from within a production code block, the current production is
aborted. Sequence generation continues with the next production following the
aborted production.
EXAMPLE:
randsequence()
TOP : P1 P2 ;
P1 : A B C ;
P2 : A { if( flag == 1 ) return; } B C ;
A : { $display( A ); } ;
B : { if( flag == 2 ) return; $display( B ); } ;
C : { $display( C ); } ;
endsequence
Depending on the value of variable flag, the example above displays the following:
flag == 0 ==> A B C A B C
flag == 1 ==> A B C A
flag == 2 ==> A C A C
When flag == 1, production P2 is aborted in the middle, after generating A. When flag
== 2, production B is aborted twice (once as part of P1 and once as part of P2), but
each time, generation continues with the next
production, C.
EXAMPLE:
randsequence( main )
main : first second gen ;
first : add | dec ;
second : pop | push ;
add : gen("add") ;
dec : gen("dec") ;
pop : gen("pop") ;
push : gen("push") ;
gen( string s = "done" ) : { $display( s ); } ;
endsequence
Search ✔
program Ran_Stb_p_75;
Ran_Stb_1 obj_1 = new();
initial
repeat(10)
begin
void'(obj_1.randomize());
$display(" Ran_Stb_1.Var : %0d ",obj_1.Var);
end
endprogram
RESULTS:
# Ran_Stb_1.Var : 4
# Ran_Stb_1.Var : 5
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 0
# Ran_Stb_1.Var : 2
# Ran_Stb_1.Var : 2
# Ran_Stb_1.Var : 7
# Ran_Stb_1.Var : 6
# Ran_Stb_1.Var : 0
EXAMPLE:
class Ran_Stb_1;
rand bit [2:0] Var;
endclass
class Ran_Stb_2;
rand bit [2:0] Var;
endclass
program Ran_Stb_p_76;
Ran_Stb_1 obj_1 = new();
Ran_Stb_2 obj_2 = new();
initial
repeat(10)
begin
void'(obj_1.randomize());
$display(" Ran_Stb_1.Var : %0d ",obj_1.Var);
end
endprogram
New object obj_2 is added after all the objects. Look at the simulation results,they
are same as the above.
RESULTS:
# Ran_Stb_1.Var : 4
# Ran_Stb_1.Var : 5
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 0
# Ran_Stb_1.Var : 2
# Ran_Stb_1.Var : 2
# Ran_Stb_1.Var : 7
# Ran_Stb_1.Var : 6
# Ran_Stb_1.Var : 0
If a new thread is added, make sure that it is added after all the threads.
EXAMPLE:
class Ran_Stb_1;
rand bit [2:0] Var;
endclass
class Ran_Stb_2;
rand bit [2:0] Var;
endclass
program Ran_Stb_p_77;
Ran_Stb_1 obj_1 = new();
Ran_Stb_2 obj_2 = new();
initial
begin
repeat(5)
begin
void'(obj_1.randomize());
$display(" Ran_Stb_1.Var : %0d ",obj_1.Var);
end
repeat(5)
begin
void'(obj_2.randomize());
$display(" Ran_Stb_2.Var : %0d ",obj_2.Var);
end
end
endprogram
The results show clearly that Random values in obj_1 are same as previous program
simulation.
RESULTS:
# Ran_Stb_1.Var : 4
# Ran_Stb_1.Var : 5
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 0
# Ran_Stb_2.Var : 3
# Ran_Stb_2.Var : 3
# Ran_Stb_2.Var : 6
# Ran_Stb_2.Var : 1
# Ran_Stb_2.Var : 1
Order of the randomize call to different objects doesnot effect the RNG generation.
EXAMPLE:
class Ran_Stb_1;
rand bit [2:0] Var;
endclass
class Ran_Stb_2;
rand bit [2:0] Var;
endclass
program Ran_Stb_p_78;
Ran_Stb_1 obj_1 = new();
Ran_Stb_2 obj_2 = new();
initial
begin
repeat(5)
begin
void'(obj_2.randomize());
$display(" Ran_Stb_2.Var : %0d ",obj_2.Var);
end
repeat(5)
begin
void'(obj_1.randomize());
$display(" Ran_Stb_1.Var : %0d ",obj_1.Var);
end
end
endprogram
RESULTS:
# Ran_Stb_2.Var : 3
# Ran_Stb_2.Var : 3
# Ran_Stb_2.Var : 6
# Ran_Stb_2.Var : 1
# Ran_Stb_2.Var : 1
# Ran_Stb_1.Var : 4
# Ran_Stb_1.Var : 5
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 0
Adding a constraint in one class, will only effect the stimuls of that object only.
EXAMPLE:
class Ran_Stb_1;
rand bit [2:0] Var;
constraint C { Var < 4 ;}
endclass
class Ran_Stb_2;
rand bit [2:0] Var;
endclass
program Ran_Stb_p_79;
Ran_Stb_1 obj_1 = new();
Ran_Stb_2 obj_2 = new();
initial
repeat(5)
begin
void'(obj_1.randomize());
void'(obj_2.randomize());
$display(" Ran_Stb_1.Var : %0d :: Ran_Stb_2.Var : %0d ",obj_1.Var,obj_2.Var);
end
endprogram
RESULTS:
# Ran_Stb_1.Var : 0 :: Ran_Stb_2.Var : 3
# Ran_Stb_1.Var : 1 :: Ran_Stb_2.Var : 3
# Ran_Stb_1.Var : 1 :: Ran_Stb_2.Var : 6
# Ran_Stb_1.Var : 1 :: Ran_Stb_2.Var : 1
# Ran_Stb_1.Var : 0 :: Ran_Stb_2.Var : 1
Srandom
When an object or thread is created, its RNG is seeded using the next value from the
RNG of the thread that creates the object. This process is called hierarchical object
seeding. Sometimes it is desirable to manually seed an objects RNG using the
srandom() method. This can be done either in a class method or external to the class
definition. Example to demonstrate seeding in objects.
EXAMPLE:
class Rand_seed;
rand integer Var;
function new (int seed);
srandom(seed);
$display(" SEED is initised to %0d ",seed);
endfunction
function void post_randomize();
$display(": %0d :",Var);
endfunction
endclass
program Rand_seed_p_80;
Rand_seed rs;
initial
begin
rs = new(20);
repeat(5)
void'(rs.randomize());
rs = new(1);
repeat(5)
void'(rs.randomize());
rs = new(20);
repeat(5)
void'(rs.randomize());
end
endprogram
RESULTS:
# SEED is initised to 20
# : 1238041889 :
# : 1426811443 :
# : 220507023 :
# : -388868248 :
# : -1494908082 :
# SEED is initised to 1
# : 1910312675 :
# : 632781593 :
# : -453486143 :
# : 671009059 :
# : -967095385 :
# SEED is initised to 20
# : 1238041889 :
# : 1426811443 :
# : 220507023 :
# : -388868248 :
# : -1494908082 :
Simulation results show that same sequence is repeated when the same seed is used
for initialization.
EXAMPLE:
integer x, y, z;
fork //set a seed at the start of a thread
begin process::self.srandom(100); x = $urandom; end
//set a seed during a thread
begin y = $urandom; process::self.srandom(200); end
// draw 2 values from the thread RNG
begin z = $urandom + $urandom ; end
join
IEEE 2005 SystemVerilog LRM does not specify whether scope randomization function
is random stable or not.
From LRM
13.13 Random stability
The RNG is localized to threads and objects. Because the sequence of random values
returned by a thread or object is independent of the RNG in other threads or objects,
this property is called random stability.
Search ✔
EXAMPLE:
Specman E class Eth_pkt;
Interview Questions rand byte Payload[] ;
rand byte size;
bit dummy = 1;
constraint dummy_c { dummy == randomize_size();}
constraint size_c { size inside {[10:100]};}
constraint order_c1 {solve size before dummy;}
constraint order_c2 {solve dummy before Payload;}
function bit randomize_size();
Payload = new[size];
In the above example, constraint order_c1 {solve size before dummy;} makes sure
that size is randomized before function ranomize_size() is called.
If constraints are dependent on the sum of the elements of the dynamic array. The
interesting elements are the new random variables which are created by current
randomization call. If you are not using any techinique to get the right size after
randomization sum() returns the sum of all the array elements .
EXAMPLE:
class dynamic_array_89;
rand byte size;
rand byte data[];
constraint size_c { data.size() == size; size >= 0; }
constraint sum_c { data.sum() < 1000;}
endclass
Do manually in a function and use it or just use { data.sum() with (item.index < size)
1000;}There is one more bug in the above code.The sum() method returns a single
value of the same type as the array element type.So the sum returns only 8 bits in
this case.So a.sum() is allways less than 255 which is less than 1000 and allways the
constraint is satisfied which is not what is expected.
EXAMPLE:
program summ;
dynamic_array obj = new();
integer sum;
initial
begin
sum =0;
void'(obj.randomize());
for(int i=0;i< obj.size ;i++)
sum= sum+obj.data[i];
$display(" Sum is %d ",sum);
end
endprogram
Using y.sum with (item + 32'b0) will result in a 32 bit proper sum.
EXAMPLE:
class dynamic_array;
rand integer size;
rand reg [7:0] data[];
constraint sum_c { data.sum() == data[0];}
constraint size_c { data.size() == size; size >1000 ;size < 2000; }
endclass
program summ;
dynamic_array obj = new();
integer sum;
initial
repeat(10)
begin
sum =0;
void'(obj.randomize());
for(int i=0;i< obj.size ;i++)
begin
sum= sum+obj.data[i];
end
$display(" Sum is %d obj.sum() %d",obj.data[0],obj.data.sum());
end
endprogram
EXAMPLE:
class cls;
rand integer Var;
endclass
class arr_obj;
rand cls objcls [0:2];
endclass
program arr_obj_p_91;
arr_obj obj = new() ;
int i;
initial
begin
if(obj.randomize())
begin
$display(" Randomization is done ");
for(i=0;i<3;i++)
if(obj.objcls[i] == null )
$display( " obj.objcls == null ");
else
$display(" obj.objcls.Var : %d ", obj.objcls[i].Var );
end
else
$display(" Randomization failed ");
end
endprogram
RESULTS:
# Randomization is done
# obj.objcls == null
# obj.objcls == null
# obj.objcls == null
In the following, objects are created during the creation of arr_obj. This can also be
done in pre_randomize. When dynamic arrays of objects are created, similar approach
has to be taken and size of the dynamic array has to be decided before the new() is
called, which makes no sense using the dynamic array of objects.
EXAMPLE:
class cls;
rand integer Var;
endclass
class arr_obj;
rand cls objcls [0:2];
function new();
foreach(objcls[i])
objcls[i]=new();
endfunction
endclass
program arr_obj_p_91;
arr_obj obj = new() ;
int i;
initial
begin
if(obj.randomize())
begin
$display(" Randomization is done ");
for(i=0;i<3;i++)
if(obj.objcls[i] == null )
$display( " obj.objcls == null ");
else
$display(" obj.objcls.Var : %d ", obj.objcls[i].Var );
end
else
$display(" Randomization failed ");
end
endprogram
RESULTS:
Randomization is done
obj.objcls.Var : 733126180
obj.objcls.Var : -119008195
obj.objcls.Var : 342785185
EXAMPLE:
class cls;
rand integer Var;
endclass
class q_cls;
rand cls obj[$];
rand bit [2:0] length;
function void pre_randomize();
length = $urandom % 20 ; // Compute the length of queue.
obj = {} ; // Delet all the elements in the queue or .delet can be
used
repeat(length)
begin
cls obj_loc;
obj_loc = new(); // Creat new object.
obj.Push_back(obj_loc) ; // insert it into queue.
end
endfunction
endclass
program q_obj_p_93;
q_cls obj = new();
initial
begin
if(obj.randomize())
begin
$display( "Randomization done");
$write( " Length of q : %0d :::",obj.length);
for(int i ;i< obj.length;i++)
begin
cls obj_temp;
obj_temp = obj.obj.Pop_front();
$write(" : %0d : ",obj_temp.Var);
end
end
else
$display( "Randomization failed");
end
endprogram
RESULT:
Randomization done
Length of q : 6 ::: : 1474208060 : : -1098913923 : : 816460770 : : 41501707 : : -
1179418145 : : -212817600 :
Some application like linked list needs to generate an array of random values which
are unique. foreach provides the solution,but the simples and the best solution is
assign all the elements in arrat with its index and use shuffel inside a task.shuffle()
randomizes the order of the elements in the array.Constraint solver is not used
hear,so the preformance is better.
EXAMPLE:
class List;
integer Pointer[5] ;
task randomize_unique;
foreach ( Pointer[ i ] )
Pointer[ i ] = i;
Pointer.shuffle();
endtask
endclass
program Unique_rand_94;
List obj;
initial
begin
obj = new();
obj.randomize_unique();
for(int i=0;i< 5;i++)
begin
$display(" Pointer[%0d] = %d ",i,obj.Pointer[i]);
end
end
endprogram
RESULT:
Pointer[0] = 2
Pointer[1] = 1
Pointer[2] = 3
Pointer[3] = 0
Pointer[4] = 4
Using foreach in global constraints in the following way wont work currently. as the .
operator(dot) is not supported in foreach in LRM currently.
EXAMPLE:
class parent;
rand byte a[0:9];
endclass
class child_96;
rand parent P;
rand byte a[0:9];
constraint Not_supported { foreach(P.a[i]) P.a[i] == a[i];}
endclass
Search ✔
VMM Ethernet sample In the Example 1, while sorting the elements of array in ascending order, if next is Report a Bug or Comment
null i.e for last element randomization fails. on This section - Your
input is what keeps
Verilog Testbench.in improving
EXAMPLE:2 with time!
Verification class SList_98;
Verilog Switch TB rand int n;
rand Slist_98 next;
Basic Constructs constraint sort { if( next != null ) n < next.n; }
endclass
OpenVera
Constructs In Example 2, Even if next is null, constraint wont be generated so randomization will
never fail.
Switch TB
RVM Switch TB
EXAMPLE:3
RVM Ethernet sample class D;
int x;
endclass
Specman E class C;
rand int x, y;
Interview Questions D a, b;
constraint c1 { (x < y || a.x > b.x || a.x == 5 ) -> x+y == 10; }
endclass
In Example 3, the predicate subexpressions are (x < y), (a.x > b.x), and (a.x == 5),
which are all
connected by disjunction. Some possible cases are as follows:
error.
The unconditional constraint (x+y == 10) is generated.
Case 2: a is null.
This always results in error, irrespective of the other conditions.
EXAMPLE:4
class D;
int x;
endclass
class C;
rand int x, y;
D a, b;
constraint c1 { (x < y && a.x > b.x && a.x == 5 ) -> x+y == 10; }
endclass
In Example 4, the predicate subexpressions are (x < y), (a.x > b.x), and (a.x == 5),
which are all
connected by conjunction. Some possible cases are as follows:
Case 2: a is null
This always results in error, irrespective of the other conditions.
EXAMPLE:5
class D;
int x;
endclass
class C;
rand int x, y;
D a, b;
constraint c1 { (x < y && (a.x > b.x || a.x ==5)) -> x+y == 10; }
endclass
In Example 5, the predicate subexpressions are (x < y) and (a.x > b.x || a.x == 5),
which are connected
by disjunction. Some possible cases are as follows:
Case 3: a is null
This always results in error, irrespective of the other conditions.
EXAMPLE:6
class A_108;
rand integer arr[];
constraint c { foreach( arr[i]) arr[i] == arr[i+1] ;}
endclass
Search ✔
RESULTS:
Var = 2147483646 is not less -10, but the solver solved it using ((Var + 10) <= 0) i.e
((2147483646 + 10) <= 0) which is true
To solve this use the inside operator.
constraint randge { Var inside {[-10000:-10]};}
Make sure that constraint expression are not mixed up with signed and unsigned
variables.
# Ran_Stb_1.Var : 4
# Ran_Stb_1.Var : 5
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 1
# Ran_Stb_1.Var : 0
# Ran_Stb_1.Var : 2
# Ran_Stb_1.Var : 2
# Ran_Stb_1.Var : 7
# Ran_Stb_1.Var : 6
# Ran_Stb_1.Var : 0
Constraining Non Integral Data Types:
EXAMPLE:
class cls;
rand integer Var;
endclass
class real_c;
real r;
rand integer i;
rand integer j;
function void post_randomize;
r = $bitstoreal({i,j});
$display("%e ",r);
endfunction
endclass
program real_p_111;
real_c obj = new();
initial
repeat(5)
void'(obj.randomize());
endprogram
RESULT:
2.507685e-280
-1.188526e-07
9.658227e-297
-2.912335e+247
2.689449e+219
Saving Memory
In packet protocol application like PCI Express, the packets which are driven to the
DUV has to be manipulated and stored to compare with the actual packet which is
coming from DUV. If the packet size is large and number of packets are huge, it
occupies more momery. In verilog in this case the whole packet need to be stored.
HVL has more advantages w.r.t this case. We can store high level information like
packet size, CRC error, header. But functional verification needs to store the payload
for checking that the payload did not get corrupted. Major part of the storage taken
by the payload itself. If we can avoid storing the payload, we can save lot of storage
space.
The following technique assigns predictable random values to payload fields. Only the
start of the payload need to be stored.
EXAMPLE:
integer pkt_length;
byte payload[0:MAX];
task gen_payload(integer seed ,integer length);
integer temp_seed;
temp_seed = seed;
for(int i=0;i< length;i++)
begin
temp_seed = $random(temp_seed);
payload[i] = temp_seed;
end
endtask
This is the task which checks whether payload is recived didnot get corrupted.
EXAMPLE:
task check_payload(integer seed,integer length);
integer temp_seed;
temp_seed = seed;
for(int i=0;i< length;i++)
begin
temp_seed = $random(temp_seed);
if(payload[i] != temp_seed)
$display(" ERROR :: DATA MISMATCH ");
end
endtask
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
NCSIM
QUESTASIM
Compilation command
vlog work library_name filename.sv
Simulation Command:
vsim library_name.module_top_name
Case 2) Sometimes in modelsim.ini file UCDB File name will be commented in that
case we have to save UCDB File explicitly after vsim command
Coverage save filename.ucdb
Once u are ready with UCDB File u need to generate coverage report from ucdb file
To generate only Functional coverage report
vcover cvg myreport.txt outfilename.ucdb
After running the above program, the coverage report will show,
VARIABLE : cover_point_y
Expected : 8
Covered : 3
Percent: 37.50.
Search ✔
5)Ref variable
Verilog
Example:
Verification covergroup (ref int r_v) cg;
Verilog Switch TB cover_ref: coverpoint r_v;
endgroup
Basic Constructs
covergroup cg;
Specman E coverpoint cp_varib iff(!reset); // filter condition
endgroup
Interview Questions
In the preceding example, cover point varible "cp_varib" is covered only if the value
reset is low.
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Bin[0] for 0 and 1
Specman E Bin[1] for 2 and 3
Interview Questions Bin[2] for 4 and 5
Bin[3] for 6 and 7
Varible Y is assigned values 3,5 and 6. Values 3,5 and 6 belongs to bins bin[1],bin[2]
and bin[3] respectively. Bin[0] is not covered.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 4
Covered : 3
Percent: 75.00
Uncovered bins
------------------
auto[0:1]
Covered bins
------------------
auto[2:3]
auto[4:5]
auto[6:7]
typedef enum { A,B,C,D } alpha;
program main;
alpha y;
alpha values[$]= '{A,B,C};
covergroup cg;
cover_point_y : coverpoint y;
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
In The above example, the variable "y" is enum data type and it can have 4 enum
members A,B,C and D. Variable Y is assigned only 3 Enum members A,B and C.
Coverage report:
---------------------
VARIABLE : cover_point_y
Expected : 4
Covered : 3
Percent: 75.00
Uncovered bins
--------------------
auto_D
Covered bins
--------------------
auto_C
auto_B
auto_A
Search ✔
Coverage report:
-------------------
OpenVera VARIABLE : cover_point_y
Constructs Expected : 4
Switch TB Covered : 3
Percent: 75.00
RVM Switch TB
RVM Ethernet sample Uncovered bins
--------------------
a
Specman E Covered bins
Interview Questions --------------------
b
c
d
Array Of Bins
To create a separate bin for each value (an array of bins) the square brackets, [],
must follow the bin name.
program main;
bit [0:2] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg;
cover_point_y : coverpoint y {
bins a[] = {[0:7]};
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
In the above example, bin a is array of 8 bins and each bin associates to one number
between 0 to 7.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 8
Covered : 3
Percent: 37.50
Uncovered bins
-------------------
a_0
a_1
a_2
a_4
a_7
Covered bins
-------------------
a_3
a_5
a_6
To create a fixed number of bins for a set of values, a number can be specified inside
the square brackets.
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg;
cover_point_y : coverpoint y {
bins a[4] = {[0:7]};
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
In the above example, variable y is 4 bit width vector. Total possible values for this
vector are 16.
But in the cover point bins, we have giving the interested range as 0 to 7. So the
coverage report is calculated over the range 0 to 7 only. In this example, we have
shown the number bins to be fixed to size 4.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 4
Covered : 3
Percent: 75.00
Uncovered bins
-------------------
a[0:1]
Covered bins
------------------
a[2:3]
a[4:5]
a[6:7]
Default Bin
The default specification defines a bin that is associated with none of the defined
value bins. The default bin catches the values of the coverage point that do not lie
within any of the defined bins. However, the coverage calculation for a coverage
point shall not take into account the coverage captured by the default bin.
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg;
cover_point_y : coverpoint y {
bins a[2] = {[0:4]};
bins d = default;
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
In the above example, we have specified only 2 bins to cover values from 0 to 4. Rest
of values are covered in default bin <93>d<94> which is not using in calculating the
coverage percentage.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 2
Covered : 1
Percent: 50.00
Uncovered bins
------------------
a[0:1]
Covered bins
----------------
a[2:4]
Default bin
-----------------
d
Search ✔
Specman E
Interview Questions In the above example, 2 bins are created for covering the transition of point "y" from
3 to 4 and other for 5 to 6. The variable y is given the values and only the transition
5 to 6 is occurring.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 2
Covered : 1
Percent: 50.00
Uncovered bins
------------------
tran_34
Covered bins
----------------
tran_56
Sequence Of Transitions
In this case, value1 is followed by value3, followed by value4 and followed by value5.
A sequence can be
of any arbitrary length.
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg;
cover_point_y : coverpoint y {
bins tran_345 = (3=>4>=5);
bins tran_356 = (3=>5=>6);
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
In the above example, 2 bins re created for covering the transition of point "y" from 3
to 4 to 5 and other for 3 to 5 to 6. The variable y is given the values and only the
transition 3 to 5 to 6 is occurring.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 2
Covered : 1
Percent: 50.00
Uncovered bins
------------------
tran_345
Covered bins
-----------------
tran_356
Set Of Transitions
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg;
cover_point_y : coverpoint y {
bins trans[] = (3,4=>5,6);
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
In the above example, bin trans creates 4 bin for covering 3=>5,4=>5,3=>6 and 4=>6.
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 4
Covered : 1
Percent: 25.00
Uncovered bins
------------------
tran_34_to_56:3->6
tran_34_to_56:4->5
tran_34_to_56:4->6
Covered bins
----------------
tran_34_to_56:3->5
Consecutive Repetitions
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,3,3,4,4};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3 = (3[*5]);
bins trans_4 = (4[*2]);
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 2
Covered : 1
Percent: 50.00
Uncovered bins
------------------
trans_3
Covered bins
----------------
trans_4
Range Of Repetition
program main;
bit [0:3] y;
bit [0:2] values[$]= '{4,5,3,3,3,3,6,7};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3[] = (3[*3:5]);
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 3
Covered : 1
Percent: 33.33
Uncovered bins
------------------
tran_3:3[*3]
tran_3:3[*5]
Covered bins
----------------
tran_3:3[*4]
Goto Repetition
The goto repetition is specified using: trans_item [-> repeat_range]. The required
number of occurrences of a particular value is specified by the repeat_range. Any
number of sample points can occur before the first occurrence of the specified value
and any number of sample points can occur between each occurrence of the specified
value. The transition following the goto repetition must immediately follow the last
occurrence of the repetition.
For example:
3 [-> 3]
is the same as
...=>3...=>3...=>3
where the dots (...) represent any transition that does not contain the value 3.
program main;
bit [0:3] y;
bit [0:2] values[$]= '{1,6,3,6,3,6,3,5};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3 = (1=>3[->3]=>5);
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 1
Covered : 1
Percent: 100.00
For example:
3 [= 2]
is same as
...=>3...=>3
program main;
bit [0:3] y;
bit [0:2] values[$]= '{1,6,3,6,3,6,5};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3 = (1=>3[=2]=>5);
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 1
Covered : 1
Percent: 100.00
Search ✔
wildcard bins T0_3 = (2'b0x => 2'b1x);
The count of transition bin T0_3 is incremented for the following transitions (as if by
(0,1=>2,3)):
00 => 10 , 00 => 11, 01 => 10 , 01 => 11
program main;
reg [0:1] y;
reg [0:1] values[$]= '{ 2'b00,2'b01,2'b10,2'b11};
covergroup cg;
cover_point_y : coverpoint y {
wildcard bins trans = (2'b0X => 2'b1X );
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Coverage report:
--------------------
VARIABLE : cover_point_y
Expected : 1
Covered : 1
Percent: 100.00
Covered bin
---------------
trans
Number of times trans hit : 1 (01 => 10)
Search ✔
Covered bins
----------------
auto[6]
auto[7]
Search ✔
Result:
Verilog ------------
Verification ** ERROR **
Illegal state bin ib of coverpoint cover_point_y in
Verilog Switch TB covergroup cg got hit with value 0x7
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Verification In the above program, y has can have 4 values 0,1,2 and 3 and similarly z can have 4
values 0,1,2 and 3. The cross product of the y and z will be 16 values
Verilog Switch TB (00),(01),(02),(03),(10),(11)........(y,z)......(3,2)(3,3) .
Basic Constructs Only combinations (11) and (32) are generated.
int i,j;
covergroup ct;
coverpoint i { bins i[] = { [0:1] }; }
coverpoint j { bins j[] = { [0:1] }; }
x1: cross i,j;
x2: cross i,j {
bins i_zero = binsof(i) intersect { 0 };
}
endgroup
Search ✔
OpenVera Description :
Specifies a name for the covergroup instance. If unspecified, a unique name for each
Constructs instance is automatically generated by the tool.
Switch TB
RVM Switch TB
Comment
RVM Ethernet sample
Syntax :comment=string
default value: ""
Specman E
Description :
Interview Questions A comment that appears with a covergroup instance or with a coverpoint or cross of
the covergroup instance. The comment is saved in the coverage database and included
in the coverage report.
At_least
Syntax :at_least=number
default value: 1
Description :
Minimum number of hits for each bin. A bin with a hit count that is less than number
is not considered covered.
Detect_overlap
Syntax :detect_overlap=Boolean
default value: 0
Description :
When true, a warning is issued if there is an overlap between the range list (or
transition list) of two bins of a coverpoint.
Auto_bin_max
Syntax :auto_bin_max=number
default value: 64
Description :
Maximum number of automatically created bins when no bins are explicitly defined
for a coverpoint.
Cross_num_print_missing
Syntax :cross_num_print_missing=number
default value: 0
Description :
Number of missing (not covered) cross product bins that shall be saved to the
coverage database and printed in the coverage report.
Per_instance
Syntax :per_instance=Boolean
default value: 0
Description :
Each instance contributes to the overall coverage information for the covergroup
type. When true, coverage information for this covergroup instance shall be saved in
the coverage database and included in the coverage report. When false,
implementations are not required to save instance-specific information.
Get_inst_coverage
Syntax :get_inst_coverage=Boolean
default value: 0
Description :
Only applies when the merge_instances type option is set . Enables the tracking of
per instance coverage with the get_inst_coverage built-in method. When false, the
value returned by get_inst_coverage shall equal the value returned by get_coverage
Search ✔
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Cover Sequence Results
Verification
Verilog Switch TB Results of coverage for a sequence shall include:
Number of times attempted
Basic Constructs
Number of times matched (each attempt can generate multiple matches)
In addition, statement_or_null gets executed for every match. If there are multiple
OpenVera matches at the same time, the statement gets executed multiple times, one for each
Constructs match.
Switch TB
It is recommended to cover sequences and not properties and its easy to convert a
RVM Switch TB property into a sequence if required.
RVM Ethernet sample
Coverage property can be declared in
Cover groups can reference data sets where as cover property references a temporal
expression.
Cover groups are most useful at a higher level of abstractions where as cover property
makes sense to use when we want to work at low level signals.
We can mix cover group and cover property to gain the OO and temporal advantages.
Using properties for temporal expressions and trigger the cover group.
Search ✔
Assertions can be used to capture the information about various level of properties.
Verilog conceptual : can be used to verify systemlevel properties which are more
Verification architectural level.
design : These expresses unit level properties.
Verilog Switch TB programming: More specified at RTL level.
Basic Constructs 1)conditional: It checks the some conditinal to be true using boolean expressions.
2)sequence : Checks whether the properties arr true using temporal expression.
3)signal : Checks on signal types.
a)x detection :Can be used to detect unconnected ports or undriven signal.
OpenVera b)encoding types: Checks whether the encoding is violated.
Constructs 1)onehot
Switch TB 2)gray code
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB In SV, a new region is added before Active region called preponed. So sampling for
SVA is done in preponed region. No assignments are not done in preponed region.
RVM Ethernet sample Signals are stable from previous timeslot and they are occurring before active and
NBA ,so the race condition is avoided by this new preponed region. Look at the
diagram, regions which are in light cyan color are for SVA.
Specman E
IN preponed region only sampling is done , the evaluation of these sampled values are
Interview Questions done in another region called observed region. Observed region occurs after NBA
region. Even though the assignments are done in active ,inactive,NBA region, these
updates are not used in observed region. Only signals sample in preponed region are
used in observed region. Observed region occurs before reactive region where the
testbench executes.
But in immediate assertions, the updated values in previous regions of current time
slot are used in observed region.
Search ✔
Verilog
Verification
Verilog Switch TB
EXAMPLE:
Basic Constructs time t;
always @(posedge clk)
if (state == REQ)
OpenVera assert (req1 || req2);
else begin
Constructs
t = $time;
Switch TB #5 $error("assert failed at time %0t",t);
RVM Switch TB end
Specman E
Interview Questions
Search ✔
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB These layering concept allows to build hierarchical constructs so its easy to maintain
them.
RVM Ethernet sample
Specman E
Boolean Expressions:
Interview Questions
Boolean expression doesn't consume time. The result of the expression is 1,0,x & z. If
the result is 1, then the expression is true , else if the expression is 0,x or z , it is
false. Concurrent assertions use boolean expressions along with temporal expressions.
Immediate assertions use only boolean expressions.
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Zero Delay:
OpenVera
Constructs The delay ##0 indicates that the beginning of the second sequence is at the same
Switch TB clock tick as the end of the first sequence. This can also be archived using boolean
expressions && .
RVM Switch TB
RVM Ethernet sample EXAMPLE:
sig1 ##0 sig2
Specman E This specifies that sig1 shall be true on the current clock tick, and sig2 shall be true
Interview Questions on the same clock tick.
A ##[n:m] followed by a range specifies the delay from the current clock tick to the
beginning of the sequence that follows.
EXAMPLE:
req ##[2:5] ack
This specifies that ack shall be true ,2-5 cycles after req. It creates multiple
subsequence threads. This resulst in multiple hits or fails.
Sub sequences created by range delay in above expressions:
req ##2 ack
req ##3 ack
req ##4 ack
req ##5 ack
EXAMPLE:
req##[4:$] ack;
Repetation Operators:
required to fall within a finite range. If specified by exact count, then the number of
iterations is defined by a non-negative integer constant expression. If required to fall
within a finite range, then the minimum number of iterations is defined by a non-
negative integer constant expression; and the maximum number of iterations either is
defined by a non-negative integer constant expression or is $, indicating a finite, but
unbounded, maximum.
Consecutive Repetition:
EXAMPLE:
REQ[*4]
This example specifies that ack shell come after req comes 4 times consecutively.
Goto Repetition :
Goto repetition specifies finitely many iterative matches of the operand boolean
expression, with a delay of one or more clock ticks from one match of the operand to
the next successive match and no match of the operand strictly in between. The
overall repetition sequence matches at the last iterative match of the operand.
EXAMPLE:
req[->3]##1 ack
This example specifies that ack shell come after req comes 3 times with no gap
between thw last req and ack.
Nonconsecutive Repetition:
EXAMPLE:
req[=3]##1 ack
This example specifies that ack shell come after req comes 4 times with gap between
thw last req and ack.
Sequence And :
Sequence must start and can end at the any time. Match is done after last sequence is
ended.
EXAMPLE:
Seq1 and seq2
Sequence Or:
Sequence must start at the same time and can end at any time. Match is done at both
the sequences ends.
EXAMPLE:
seq1 or seq2
Sequence Intersect:
sequences must start at the same time and end at same tine. Match is done at the end
time.
EXAMPLE:
Seq1 intersect seq2
Sequence Within
EXAMPLE:
Seq1 within seq2
Sequence First_match:
EXAMPLE:
first_match(seq1)
Sequence Throughout
EXAMPLE:
A throughout seq1
Sequence Ended:
The end point of a sequence is reached whenever the ending clock tick of a match of
the sequence is reached, regardless of the starting lock tick of the match. The
reaching of the end point can be tested by using the method ended.
EXAMPLE:
sequence e1;
@(posedge sysclk) $rose(ready) ##1 proc1 ##1 proc2 ;
endsequence
sequence rule;
@(posedge sysclk) reset ##1 inst ##1 e1.ended ##1 branch_back;
endsequence
Operator precedence and associativity are listed in the following Table . The highest
precedence is listed first.
Search ✔
EXAMPLE:
a ||-> b
Search ✔
The environment must be constrained so that the properties that are assumed shall
hold. Like an assert property, an assumed property must be checked and reported if
OpenVera it fails to hold. There is no requirement on the tools to report successes of the
Constructs assumed properties.
Switch TB
RVM Switch TB EXAMPLE:
RVM Ethernet sample a1:assume property ( @(posedge clk) req dist {0:=40, 1:=60} ) ;
property proto ;
@(posedge clk) req |-> req[*1:$] ##0 ack;
endproperty
Specman E
Interview Questions Cover Statement:
To monitor sequences and other behavioral aspects of the design for coverage, the
same syntax is used with the cover statement. The tools can gather information about
the evaluation and report the results at the end of simulation. When the property for
the cover statement is successful, the pass statements can specify a coverage
function, such as monitoring all paths for a sequence. The pass statement shall not
include any concurrent assert, assume, or cover statement.
Coverage results are divided into two categories: coverage for properties and
coverage for sequences.
Expect Statement:
EXAMPLE:
program tst;
initial begin
# 200ms;
expect( @(posedge clk) a ##1 b ##1 c ) else $error( "expect failed" );
ABC: ...
end
endprogram
Binding:
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Functions implemented in C that can be called from SystemVerilog and can in turn
OpenVera call exported tasks; such functions are referred to as imported tasks.
Constructs
Switch TB Dpi-C Foreign Language Layer
RVM Switch TB
The foreign language layer of the interface (which is transparent to SystemVerilog)
RVM Ethernet sample shall specify how actual arguments are passed, how they can be accessed from the
foreign code, how SystemVerilog-specific data types (such as logic and packed) are
represented, and how they are translated to and from some predefined C-like types.
Specman E
Interview Questions
Search ✔
initial
begin
Verilog string_sv2c();
Verification end
Verilog Switch TB
In C code:
Basic Constructs Step3: Define the Imported function
void string_sv2c(){
OpenVera printf(" C: Hellow from C ");
}
Constructs
Switch TB
RVM Switch TB Full Example:
CODE: C_file
#include "svdpi.h"
void string_sv2c(){
printf(" C: Hellow from C ");
}
RESULTS
C: Hellow from C
Standard C Functions
EXAMPLE:
import "DPI" function chandle malloc(int size);
import "DPI" function void free(chandle ptr);
Search ✔
EXAMPLE:
Verilog import "DPI-C" \begin = function void \init[2] (); // "begin" is a linkage name
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Full Example:
OpenVera
Constructs
CODE: SV_file.sv
Switch TB program main;
RVM Switch TB
export "DPI-C" function export_func;
RVM Ethernet sample import "DPI-C" function void import_func();
function void export_func();
Specman E $display("SV: Hello from SV ");
endfunction
Interview Questions
initial
begin
import_func();
end
endprogram
CODE: C_file.c
#include "stdio.h"
#include "vc_hdrs.h"
#include "svdpi.h"
extern void export_func(void);
void import_func()
{
export_func();
}
RESULTS:
CODE:SV_file.sv
program main;
export "DPI-C" task export_task;
import "DPI-C" context task import_task();
task export_task();
$display("SV: Entered the export function . wait for some time : %0d
",$time);
#100;
$display("SV: After waiting %0d",$time);
endtask
initial
begin
$display("SV: Before calling import function %0d",$time);
import_task();
$display("SV: After calling import function %0d",$time);
end
endprogram
CODE: C_file.c
extern void export_task();
void import_task()
{
printf(" C: Before calling export function\n");
export_task();
printf(" C: After calling export function\n");
}
RESULTS
Search ✔
#include "svdpi.h"
#include "stdio.h"
extern void export_func(void);
void import_func()
{
printf(" C: Im called fronm Scope :: %s \n\n
",svGetNameFromScope(svGetScope() ));
export_func();
}
RESULTS
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Passing Logic Datatype
Interview Questions
The DPI defines the canonical representation of packed 2-state (type svBitVecVal) and
4-state arrays (type svBitVecVal). svLogicVecVal is fully equivalent to type
s_vpi_vecval, which is used to represent 4-state logic in VPI.
CODE:SV_file.sv
program main;
logic a;
import "DPI" function void show(logic a);
initial begin
a = 1'b0;
show(a);
a = 1'b1;
show(a);
a = 1'bX;
show(a);
a = 1'bZ;
show(a);
end
endprogram
CODE: C_file.v
#include <stdio.h>
#include <svdpi.h>
void show(svLogic a){
if(a == 0)
printf(" a is 0 \n");
else if(a == 1)
printf(" a is 1 \n");
else if(a == 2)
printf(" a is x \n");
else if(a == 3)
printf(" a is z \n");
}
RESULTS
a is 0
a is 1
a is z
a is x
Search ✔
#include <stdio.h>
#include <svdpi.h>
void pass_array(const svOpenArrayHandle dyn_arr ) {
int i;
printf("Array Left %d, Array Right %d
\n\n", svLeft(dyn_arr,1), svRight(dyn_arr, 1) );
for (i= svRight(dyn_arr,1); i <= svLeft(dyn_arr,1); i++) {
printf("C: %d %d \n", i, *(int*)svGetArrElemPtr1(dyn_arr, i) );
}
printf("\n\n");
}
RESULTS:
SV:fxd_arr_1 3 303379748
SV:fxd_arr_1 4 -1064739199
SV:fxd_arr_1 5 -2071669239
SV:fxd_arr_1 6 -1309649309
SV:fxd_arr_1 7 112818957
SV:fxd_arr_1 8 1189058957
Passing fxd_arr_1 to C
C: 3 303379748
C: 4 -1064739199
C: 5 -2071669239
C: 6 -1309649309
C: 7 112818957
C: 8 1189058957
Passing fxd_arr_2 to C
C: 1 -1295874971
C: 2 -1992863214
C: 3 15983361
C: 4 114806029
C: 5 992211318
C: 6 512609597
C: 7 1993627629
C: 8 1177417612
C: 9 2097015289
C: 10 -482925370
C: 11 -487095099
C: 12 -720121174
Packed Arrays
CODE:SV_file.sv
program main;
import "DPI-C" function void get_nums(output logic [15:0] nums[10]);
logic [15:0] nums[10];
initial begin
get_nums(nums);
foreach (nums[i]) $display(i,nums[i]);
end
endprogram
CODE:C_file.c
#include "svdpi.h"
void fib(svLogicVecVal nums[10]) {
int i;
for (i=0; i<10; i++) {
nums[i] = i ;
}
}
RESULTS:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
logic [2:3][1:3][2:0] b [1:10][31:0];
logic [17:0] b [0:9][0:31];
svLow() shall return the minimum of left index and right index of the dimension.
svHigh() shall return the maximum of left index and right index of the dimension.
svIncrement() shall return 1 if left index is greater than or equal to right index and
-1 if left index is less than right index.
CODE: SV_file.sv
program main;
int fxd_arr_1[8:3];
int fxd_arr_2[1:13];
import "DPI-C" context function void pass_array(input int dyn_arr[] );
initial
begin
$display("\n Passing fxd_arr_1 to C \n");
pass_array( fxd_arr_1 );
$display("\n Passing fxd_arr_2 to C \n");
pass_array( fxd_arr_2 );
end
endprogram
CODE: C_file.c
#include <stdio.h>
#include <svdpi.h>
void pass_array(const svOpenArrayHandle dyn_arr ) {
printf("Array Pointer is %x \n", svGetArrayPtr(dyn_arr) );
printf(" Lower index %d \n", svLow(dyn_arr,1));
printf(" Higher index %d \n", svHigh(dyn_arr, 1) );
printf(" Left index %d \n", svLeft(dyn_arr,1), svRight(dyn_arr, 1) );
printf(" Right index %d \n", svRight(dyn_arr, 1) );
printf(" Length of array %d \n", svLength(dyn_arr,1) );
printf(" Incremental %d \n",svIncrement(dyn_arr,1));
printf("Dimentions of Array %d \n", svDimensions(dyn_arr ));
printf("Size of Array in bytes %d \n", svSizeOfArray(dyn_arr) );
}
RESULTS:
Passing fxd_arr_1 to C
Passing fxd_arr_2 to C
Search ✔
import "DPI-C" function void import_func();
typedef struct packed{
int a;
int b;
byte c;
} SV_struct;
function void export_func(input int arr[3]);
SV_struct s_data;
s_data.a = arr[0];
s_data.b = arr[1];
s_data.c = arr[2];
$display("SV: s_data.a = %0d", s_data.a );
$display("SV: s_data.b = %0d", s_data.b );
$display("SV: s_data.c = %0d \n", s_data.c );
endfunction
initial
begin
import_func();
end
endprogram
RESULTS:
C : s_data.a = 51
C : s_data.b = 242
C : s_data.c = 35
SV: s_data.a = 51
SV: s_data.b = 242
SV: s_data.c = 35
CODE: C_file.c
#include "svdpi.h"
typedef struct {int p; int q} PkdStru;
void send2c(const svOpenArrayHandle dyn_arr)
{
int i;
PkdStru Sele;
printf("\n \n Array Left %d, Array Right %d
\n\n", svLeft(dyn_arr,1), svRight(dyn_arr, 1) );
for (i= svLeft(dyn_arr,1); i <= svRight(dyn_arr,1); i++) {
Sele = *(PkdStru*)svGetArrElemPtr1(dyn_arr, i);
printf("C : %d : [%d,%d]\n",i, Sele.q,Sele.p );
}
printf("\n\n");
}
CODE: SV_file.sv
program open_array_struct ();
typedef struct packed { int p; int q; } PkdStru;
import "DPI-C" function void send2c (input PkdStru arr []);
foreach (arr_data[i]) begin
arr_data[i] = {$random,$random};
$display("SV: %0d : [%0d,%0d]",i,arr_data[i].p,arr_data[i].q);
end
send2c(arr_data);
end
endprogram
RESULTS:
SV: 0 : [303379748,-1064739199]
SV: 1 : [-2071669239,-1309649309]
SV: 2 : [112818957,1189058957]
SV: 3 : [-1295874971,-1992863214]
SV: 4 : [15983361,114806029]
Array Left 0, Array Right 4
C : 0 : [303379748,-1064739199]
C : 1 : [-2071669239,-1309649309]
C : 2 : [112818957,1189058957]
C : 3 : [-1295874971,-1992863214]
C : 4 : [15983361,114806029]
CODE:SV_file
module m;
typedef bit [2:0] A;
typedef union packed { A a; S s; } U;
U u;
A a;
// Import function takes three arguments
import "DPI-C" function void foo8(input A fa, input U fu);
initial begin
a = 3'b100;
u.a = 3'b100;
foo8(a, u);
end
endmodule
CODE:C_file
#include "svdpi.h"
void foo8(
const svBitVecVal* fa,
const svBitVecVal* fu)
{
printf("fa is %d, fu is %d\n", *fa, *fu);
}
Search ✔
int string_sv2c(const char* str){
printf(" C: %s",str);
return 0;
}
RESULTS
From the Data type mapping table, a SystemVerilog "String" is mapped to "const char*"
in C. In the Following example, string "HELLO: This string is created in C" is assigned
to a string and passed as return value to function import "string_c2sv" and this import
function is called in SystemVerilog.
CODE: SV_file.v
program main;
string str;
import "DPI-C" context function string string_c2sv();
initial
begin
str = string_c2sv();
$display(" SV: %s ",str);
end
endprogram
CODE: C_file.c
#include "svdpi.h"
const char* string_c2sv(void) {
char* str;
str = " HELLO: This string is created in C ";
return str;
}
RESULTS:
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
The architect based on the MRD specification, develops the overall architecture of the
Specman E chip. This is a very high level plan. Architecture Specification includes functional
descriptions of each module, Properties and weights.
Interview Questions
Design Specification
The designers and architects sit together to come up with detailed design documents.
Design strategies, design partitions, type of memories to use, etc.
Verification Plan
engineer goes through all the above documents and prepares verification plan to
verify the design.
Rtl Design
RTL stands for Register Transfer Level. The designer starts implementing the RTL
design in HDL like verilog or VHDL.
Functional Verification
The verification engineers starts developing TestBench and verifies whether the DUT
works according to specification or not.
Synthesis
Physical Design
Physical design process includes logic partitioning, floor planning, global routing,
detailed routing, compaction, and performance-driven layout. PD team transforms net
list representation of a system into layout representation.
Timing Analysis
Tapeout
This is the final stage of the design cycle of integrated circuits. Once all the checks
are done, the design is ready to be sent to Foundry.
Search ✔
Specman E
Interview Questions
Search ✔
Search ✔
Specman E
Interview Questions
Search ✔
Interview Questions
To test all possible scenarios which are known to us, it is not an easy task.
Development time increases exponentially as the number of scenarios increases and
maintain them is nightmare. Instead of listing out all the possible scenarios, pickup
some randomly and check the DUT.
NOTE TO NO VOICE ENGINEERS:
Generally tendency of any novice engineer is to see the outputs in the waveform
viewer. Waveform viewers are for debugging designs, not for testbench. Most of the
operation in TestBench executes in zero time, where waveform viewer will not be
helpful. All the examples in the book outputs messages to terminal for analyzing its
behavior.
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Search ✔
Constraint random verification also reduces manual effort and code for individual
Specman E
tests. As the scenarios are generated automatically by the TestBench, the number of
Interview Questions test case files gets reduced. In Directed verification, some of the tests share similar
logic, if the engineer has to change the logic which is common to certain group of
tests, then he has to edit all the test case files and it is time consuming. But in
Constraint random verification, the number of tests case files will be very less, so
changes will be mostly in environment and minimal.
Directed verification with a fairly simple TestBench, verification engineers can start
finding bugs in simulation almost immediately even before the TestBench is fully
completed. With a constrained-random verification environment, there is an up-front
cost that must be invested before the first test can be run. Constraint-based
generators can be easily converted into checkers if required.
The main disadvantage of constraint random verification is we never know how well
the DUT is verified. If verification engineer can get the information about the logic in
DUT which is not verified, he can further constraint the randomization or write
directed testcases to exercise the unverified logic.
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
Search ✔
Specman E
Interview Questions
Search ✔
Search ✔
TUTORIALS MAKE YOUR GOAL 100 PERCENT CODE COVERAGE NOTHING LESS Index
Asic Design
SystemVerilog Bottle Neck In Asic Flow
Verification Never set your goal to anything less than 100% code coverage. Anything less than 100% Functional Verification
is a slippery slope. If you set your goal to 98% , may be the most important feature Need
Constructs like reset of the system may be in the untested part of2%. If the verification engineer Testbench
Interface sets the code coverage goal to 95% to facilitate the 5% the unused untestable legacy Linear Testbench
code, there are chances that the unused legacy code gets executed and the 5% holes Linear Random
OOPS Testbench
may be in the important code. 100% code coverage provides advantages not only in
Randomization reducing the bug count but also in making it easier to make significant changes to How To Check The
existing code base to remove uncover able areas like the unused legacy blocks in RTL Results
Functional Coverage Self Checking Testbenchs
code.
Assertion How To Get Scenarios
Dont Be Fooled By The Code Coverage Report Which We Never Thought
DPI How To Check Whether
UVM Tutorial Highly covered code isn't necessarily free of defects, although it's certainly less likely The Testbench Has
to contain them. By definition, code coverage is limited to the design code. It doesn't Satisfactorily Exercised
VMM Tutorial The Design
know anything about what design supposed to do. Even If a feature is not
OVM Tutorial implemented in design, code coverage can report 100% coverage. It is also impossible Types Of Code Coverage
to determine whether we tested all possible values of a feature using code coverage. Statement Coverage
Easy Labs : SV
For example, randomization may not generate packets with all possible lengths, this Block Coverage
Easy Labs : UVM cannot be reported by code coverage.. Code coverage is unable to tell much about Conditional Coverage
how well you have covered your logic -- only whether you've executed each line/block Branch Coverage
Easy Labs : OVM
etc at least once. Code coverage does not provide information about your test bench Path Coverage
Easy Labs : VMM randomization quality and it does not report what caused the line execution/state Toggle Coverage
AVM Switch TB transition etc. Analysis of code coverage require knowledge of design to find which Fsm Coverage
features are not verified which is time consuming and out of scope of verification Make Your Goal 100
VMM Ethernet sample engineer. If the analysis is done at higher level of abstraction, it would be easier for Percent Code Coverage
the test writer to identify the missed serious which is not possible by code Nothing Less
coverage. So if the code coverage is less than 100%, it means there is more work to Functional Coverage
Verilog do, if it is 100%, it doesn't mean that the verification is complete. Coverage Driven
Constraint Random
Verification
Verification Architecture
Verilog Switch TB When To Stop Testing? Phases Of Verification
Ones Counter Example
Basic Constructs
Verification Plan
It's getting harder to figure out when to stop testing as the complexity of the protocol
is increasing. In directed test environment, for each point mentioned in test plan, Report a Bug or Comment
OpenVera there will be a separate test case file. So if there are 100 points in test plan, then the on This section - Your
Constructs engineer has to write 100 test case files. After writing and executing the 100 test input is what keeps
case files, we can say that "all the points in test plan are verified" and we can stop Testbench.in improving
Switch TB
testing. with time!
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
RVM Ethernet sample SystemVerilog provides 2 ways to mention coverage. Cover group which is uses
information from transactor, monitor and checker. Assertion coverage which is uses
temporal language which can be outside or inside RTL code.
Covergroup:
Specman E
Interview Questions There are three types of cover group points:
1. item functional coverage point
2. cross functional coverage point
3. transitional functional coverage point
Item
"Item" is used to capture the information about the sclare value. A range of
interested values can also be observed.
For example, consider a packet protocol. The packet has a address field with possible
values of A0,A1 and data which can be 4 to 10 bytes. At the end of packet parity is
also attached for integrity checking.
The following table identifies these coverage points for the above packet:
Coverage engine collects item values are during simulation and reports.
Reports consists how many times
Packets with length 4,5,6,7,8,9,10 are generated.
Packets with good parity, bad parity are generated.
Packets with address A0, A1 are generated.
Cross
"cross" is used to examine the cross product of two or more item coverage points.
Example: verify DUT by sending both good parity and bad parity packets with all the
address.
Cross_ ADD_Par Item_ADD,Item_Par
Transitional
Assertion Coverage:
Assertion coverage looks for the desired behavior in RTL. It uses assertion language
which is in temporal nature. It has direct access to design variables and designer can
add many points in RTL which he wants the verification engineer to cover.
Example: Verify by sending back-to-back packets.
Search ✔
Specman E
Stimulus
Interview Questions Stimulus generator
Transactor
Driver
Monitor
Assertion monitor
Checker
Scoreboard
Coverage
Utilities
Tests
Stimulus:
Stimulus Generator
The generator component generates stimulus which are sent to DUT by driver.
Stimulus generation is modeled to generate the stimulus based on the specification.
For simple memory stimulus generator generates read, write operations, address and
data to be stored in the address if its write operation. Scenarios like generate
alternate read/write operations are specified in scenario generator. SystemVerilog
provided construct to control the random generation distribution and
order. Constraints defined in stimulus are combinatioural in nature where as
constraints defined in stimulus generators are sequential in nature.
Stimulus generation can be directed or directed random or automatic and user should
have proper controllability from test case. It should also consider the generation of
stimulus which depends on the state of the DUT for example, Generating read cycle as
soon as interrupt is seen. Error injection is a mechanism in which the DUT is verified
by sending error input stimulus. Generally it is also taken care in this module.
Generally generator should be able to generate every possible scenario and the user
should be able to control the generation from directed and directed random testcases.
Transactor
Transactor does the high level operations like burst-operations into individual
commands, sub-layer protocol in layered protocol like PciExpress Transaction layer
over PciExpress Data Link Layer, TCP/IP over Ethernet etc. It also handles the DUT
configuration operations. This layer also provides necessary information to coverage
model about the stimulus generated. Stimulus generated in generator is high level like
Packet is with good crc, length is 5 and da is 8<92>h0. This high level stimulus is
converted into low level data using packing. This low level data is just a array of bits
or bytes. Packing is an operation in which the high level stimulus values scalars,
strings, array elements and struct are concatenated in the specified manner.
Driver
The drivers translate the operations produced by the generator into the actual inputs
for the design under verification. Generators create inputs at a high level of
abstraction namely, as transactions like read write operation. The drivers convert this
input into actual design inputs, as defined in the specification of the designs
interface. If the generator generates read operation, then read task is called, in that,
the DUT input pin "read_write" is asserted.
Monitor
Monitor reports the protocol violation and identifies all the transactions. Monitors are
two types, Passive and active. Passive monitors do not drive any signals. Active
monitors can drive the DUT signals. Sometimes this is also refered as
receiver. Monitor converts the state of the design and its outputs to a transaction
abstraction level so it can be stored in a 'score-boards' database to be checked later
on. Monitor converts the pin level activities in to high level.
Assertions are used to check time based protocols, also known as temporal checks.
Assertions are a necessary compliment to transaction based testing as they describe
the pin level, cycle by cycle, protocols of the design. Assertions are also used for
functional coverage.
Data Checker
The monitor only monitors the interface protocol. It doesn't check the whether the
data is same as expected data or not, as interface has nothing to do with the date.
Checker converts the low level data to high level data and validated the data. This
operation of converting low level data to high level data is called Unpacking which is
reverse of packing operation. For example, if data is collected from all the commands
of the burst operation and then the data is converted in to raw data , and all the sub
fields information are extracted from the data and compared against the expected
values. The comparison state is sent to scoreboard.
Scoreboard
Coverage
This component has all the coverage related to the functional coverage groups.
Utilities
Utilities are set of global tasks which are not related to any protocol. So this module
can be reused across projects without any modification to code. Tasks such as global
timeout, printing messages control, seeding control, test pass/fail conditions, error
counters etc. The tasks defined in utilities are used by all other components of the
TestBench.
Environment:
Environment contains the instances of all the verification component and Component
connectivity is also done. Steps required for execution of each component is done in
this.
Tests
Tests contain the code to control the TestBench features. Tests can communicate with
all the TestBench components. Once the TestBench is in place, the verification
engineer now needs to focus on writing tests to verify that the device behaves
according to specification.
Search ✔
Building Testbench
Specman E
Interview Questions
In this phase, the verification environment is developed. Each verification component
can be developed one by one or if more than one engineer is working it can be
developed parallel. Writing the coverage module can be done at any time. It is
preffered to write down the coverage module first as it gives some idea of the
verification progress.
Writing Tests
After the TestBench is built and integrated to DUT, it's time for validating the
DUT. Initially in CDV, the test are ran randomly till some 70 % of coverage is reached
or no improvement in the coverage for 1 day simulation. By analyzing the coverage
reports, new tests are written to cover the holes. In these tests, randomization is
directed to cover the holes. Then finally, the hard to reach scenarios, called as corner
cases have to be written in directed verification fashion. Of course, debugging is
done in parallel and DUT fixes are done.
Once you have achieved certain level of functional coverage, integrate the code
coverage. For doing code coverage, the code coverage tools have option to switch it
on. And then do the simulation, the tool will provide the report.
Analyze Coverage
Finally analyze both functional coverage and code coverage reports and take
necessary steps to achieve coverage goals. Run simulation again with a different
seed, all the while collecting functional coverage information.
Search ✔
Block Diagram:
TOP
|-- Clock generator
|-- Dut Instance
|-- Interface
|-- Assertion block instance ( assertion coverage)
|-- Testcase instance
|-- Environment
|-- Driver
| |-- Stimulus
| |-- Covergroup
|-- Monitor
|-- Scoreboard
Testbench Components:
Stimulus
class stimulus;
rand bit value;
constraint distribution {value dist { 0 := 1 , 1 := 1 }; }
endclass
Driver
This driver consists of reset and drive method. Reset method resets the DUT and drive
method generates the stimulus and sends it to DUT. Driver also calculates the
expected DUT output and stores in scoreboard. Coverage is also sampled in this
component. Feature 1 and 2 which are mentioned in Testplan are covered in this
cover group.
class driver;
stimulus sti;
Scoreboard sb;
covergroup cov;
Feature_1: coverpoint sb.store ;
Feature_2 : coverpoint sb.store { bins trans = ( 15 => 0) ;}
endgroup
virtual intf_cnt intf;
function new(virtual intf_cnt intf,scoreboard sb);
this.intf = intf;
this.sb = sb;
cov = new();
endfunction
task reset(); // Reset method
intf.data = 0;
@ (negedge intf.clk);
intf.reset = 1;
@ (negedge intf.clk);
intf.reset = 0;
@ (negedge intf.clk);
intf.reset = 1;
endtask
task drive(input integer iteration);
repeat(iteration)
begin
sti = new();
@ (negedge intf.clk);
if(sti.randomize()) // Generate stimulus
intf.data = sti.value; // Drive to DUT
sb.store = sb.store + sti.value;// Cal exp value and store in Scoreboard
if(sti.value)
cov.sample();
end
endtask
endclass
Monitor
The monitor collects the DUT output and then gets the expected value from the score
board and compares them.
class monitor;
scoreboard sb;
virtual intf_cnt intf;
function new(virtual intf_cnt intf,scoreboard sb);
this.intf = intf;
this.sb = sb;
endfunction
task check();
forever
@ (negedge intf.clk)
if(sb.store != intf.count) // Get expected value from scoreboard and
compare with DUT output
$display(" * ERROR * DUT count is %b :: SB count is %b
", intf.count,sb.store );
else
$display(" DUT count is %b :: SB count is %b ", intf.count,sb.store );
endtask
endclass
Assertion Coverage
module assertion_cov(intf_cnt intf);
Feature_3 : cover property (@(posedge intf.clk) (intf.count !=0) |-> intf.reset
== 0 );
endmodule
Scoreboard
class scoreboard;
bit [0:3] store;
endclass
Environment:
class environment;
driver drvr;
scoreboard sb;
monitor mntr;
virtual intf_cnt intf;
function new(virtual intf_cnt intf);
this.intf = intf;
sb = new();
drvr = new(intf,sb);
mntr = new(intf,sb);
fork
mntr.check();
join_none
endfunction
endclass
Top:
The interface is declared and the test bench and DUT instances are taken. Testbench
and DUT are connected using interfaces. Clock is also generated and connects it to
DUT and testbench.
interface intf_cnt(input clk);
wire clk;
wire reset;
wire data;
wire [0:3] count;
endinterface
module top();
reg clk = 0;
initial // clock generator
forever #5 clk = ~clk;
// DUT/assertion monitor/testcase instances
intf_cnt intf(clk);
ones_counter DUT(clk,intf.reset,intf.data,intf.count);
testcase test(intf);
assertion_cov acov(intf);
endmodule
Tests:
This is a simple test case. It does reset and then send 10 input values.
program testcase(intf_cnt intf);
environment env = new(intf);
initial
begin
env.drvr.reset();
env.drvr.drive(10);
end
endprogram
SCORE ASSERT GROUP
9.38 0.00 18.75
program testcase(intf_cnt intf);
environment env = new(intf);
initial
begin
env.drvr.reset();
env.drvr.drive(100);
env.drvr.reset();
env.drvr.drive(100);
end
endprogram
ones_counter.tar
Browse the code in ones_counter.tar
Search ✔
Specman E
Interview Questions
Overview
This section contains description of the project, what specification is followed, what
languages and methodology are used. Information related to the HW blocks, SW
blocks and HW/SW interaction is outlined.
Feature Extraction
This section contains list of all the features to be verified. Generally each feature is
associated with
The "Unique name ID" should be descriptive in nature to understand the nature of the
feature and should be unique. For example, <module name>_<sub module>_<feature
number>_<feature name>
This section contains details of man power required and schedule for each phase of
the verification. Information about the tools which are used for simulation, debugger
and bug tracking are listed.
Verification Environment
Details about each level (block, sub-system, system) and phases (RTL, gate) of
verification are mentioned.
1. Unique name ID
2. Stimulus to be generated for driving into the DUT
3. Configuration/constraints Information
Checker Plan
This section will explain the expected result checking's in the TestBench. This can be
done in monitor/checker.
Coverage Plan
The coverage section explains the functional coverage of the features. A functional
coverage plan should be built to help implement coverage points in the verification
environment. Genarally it would be better if the coverage block is brocken based on
the design logical blocks. It will list the various Coverage groups and assertion.
1. Coverage Group
2. Coverage Description
3. Coverage name
4. Unique name ID (Defined in feature plan)
5. Cover point (Items/cross/transition/assertion)
6. Coverage goal
This section contains the details of reusable components and the description about
their usage.
Search ✔
Specman E
Interview Questions
Search ✔
Verilog NOTE: uvm_env and uvm_test are also extended from uvm_component.
Verification A typical uvm verification environment:
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
monitor. If the agent is active, subtypes should contain all three subcomponents. If
the agent is passive, subtypes should contain only the monitor.
UVM phases
UVM Components execute their behavior in strictly ordered, pre-defined phases. Each
phase is defined by its own virtual method, which derived components can override to
incorporate component-specific behavior. By default , these methods do nothing.
--> virtual function void build()
--> virtual function void connect()
--> virtual function void end_of_elaboration()
--> virtual function void start_of_simulation()
--> virtual task run()
In this phase , Main body of the test is executed where all threads are forked off.
--> virtual function void extract()
--> virtual function void check()
In this phase, check the results of the extracted information such as un responded
requests in scoreboard, read statistics registers etc.
--> virtual function void report()
Uvm_test
Lets implement environment for the following topology. I will describe the
implementation of environment , testcase and top module. Agent, monitor and driver
are implemented similar to environment.
class env extends uvm_env;
2)Declare the utility macro. This utility macro provides the implementation of create()
and get_type_name() methods and all the requirements needed for factory.
`uvm_component_utils(env)
agent ag1;
agent ag2;
4)Define the constructor. In the constructor, call the super methods and pass the
parent object. Parent is the object in which environment is instantiated.
function void build();
super.build();
uvm_report_info(get_full_name(),"Build", UVM_LOW);
ag1 = agent::type_id::create("ag1",this);
ag2 = agent::type_id::create("ag2",this);
endfunction
6)Define
connect(),end_of_elaboration(),start_of_simulation(),run(),extract(),check(),report()
methods.
Just print a message from these methods, as we dont have any logic in this example
to define.
function void connect();
uvm_report_info(get_full_name(),"Connect", UVM_LOW);
endfunction
class env extends uvm_env;
`uvm_component_utils(env)
agent ag1;
agent ag2;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build();
uvm_report_info(get_full_name(),"Build", UVM_LOW);
ag1 = agent::type_id::create("ag1",this);
ag2 = agent::type_id::create("ag2",this);
endfunction
function void connect();
uvm_report_info(get_full_name(),"Connect", UVM_LOW);
endfunction
function void end_of_elaboration();
uvm_report_info(get_full_name(),"End_of_elaboration", UVM_LOW);
endfunction
function void start_of_simulation();
uvm_report_info(get_full_name(),"Start_of_simulation", UVM_LOW);
endfunction
task run();
uvm_report_info(get_full_name(),"Run", UVM_LOW);
endtask
function void extract();
uvm_report_info(get_full_name(),"Extract", UVM_LOW);
endfunction
function void check();
uvm_report_info(get_full_name(),"Check", UVM_LOW);
endfunction
function void report();
uvm_report_info(get_full_name(),"Report", UVM_LOW);
endfunction
endclass
class test1 extends uvm_test;
`uvm_component_utils(test1)
env t_env;
3)Define constructor method. In the constructor, call the super method and construct
the environment object.
function new (string name="test1", uvm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
4)Define the end_of_elaboration method. In this method, call the print() method. This
print() method will print the topology of the test.
function void end_of_elaboration();
uvm_report_info(get_full_name(),"End_of_elaboration", UVM_LOW);
print();
endfunction
task run ();
#1000;
global_stop_request();
endtask : run
class test1 extends uvm_test;
`uvm_component_utils(test1)
env t_env;
function new (string name="test1", uvm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
function void end_of_elaboration();
uvm_report_info(get_full_name(),"End_of_elaboration", UVM_LOW);
print();
endfunction
task run ();
#1000;
global_stop_request();
endtask : run
endclass
Top Module:
To start the testbench, run_test() method must be called from initial block.
Run_test() mthod Phases all components through all registered phases.
module top;
initial
run_test();
endmodule
uvm_phases.tar
Browse the code in uvm_phases.tar
Log file:
uvm_test_top.t_env.ag1.drv[uvm_test_top.t_env.ag1.drv]Start_of_simulation
uvm_test_top.t_env.ag1.mon[uvm_test_top.t_env.ag1.mon]Start_of_simulation
uvm_test_top.t_env.ag1[uvm_test_top.t_env.ag1]Start_of_simulation
uvm_test_top.t_env.ag2.drv[uvm_test_top.t_env.ag2.drv]Start_of_simulation
uvm_test_top.t_env.ag2.mon[uvm_test_top.t_env.ag2.mon]Start_of_simulatio
..
..
..
..
1)Build method was called in top-down fashion. Look at the following part of message.
2)Connect method was called in bottopm up fashion. Look at the below part of log
file,
Search ✔
Basic Constructs verbosity -- the verbosity of the message, indicating its relative importance. If this
number is less than or equal to the effective verbosity level, then the report is issued,
subject to the configured action and file descriptor settings.
OpenVera
Constructs filename/line -- If required to print filename and line number from where the
message is issued, use macros, `__FILE__ and `__LINE__.
Switch TB
RVM Switch TB
Actions:
RVM Ethernet sample
These methods associate the specified action or actions with reports of the given
severity, id, or severity-id pair.
Specman E
Following are the actions defined:
Interview Questions
UVM_NO_ACTION -- Do nothing
UVM_DISPLAY -- Display report to standard output
UVM_LOG -- Write to a file
UVM_COUNT -- Count up to a max_quit_count value before exiting
UVM_EXIT -- Terminates simulation immediately
UVM_CALL_HOOK -- Callback the hook method .
Configuration:
Using these methods, user can set the verbosity levels and set actions.
function void set_report_verbosity_level
(int verbosity_level)
function void set_report_severity_action
(uvm_severity severity,uvm_action action)
function void set_report_id_action
(string id,uvm_action action)
function void set_report_severity_id_action
(uvm_severity severity,string id,uvm_action action)
Example
`include "uvm.svh"
import uvm_pkg::*;
class rpting extends uvm_component;
`uvm_component_utils(rpting)
function new(string name,uvm_component parent);
super.new(name, parent);
endfunction
task run();
uvm_report_info(get_full_name(),
"Info Message : Verbo lvl - UVM_NONE ",UVM_NONE,`__FILE__,`__LINE__);
uvm_report_info(get_full_name(),
"Info Message : Verbo lvl - UVM_LOW ",UVM_LOW);
uvm_report_info(get_full_name(),
"Info Message : Verbo lvl - 150 ",150);
uvm_report_info(get_full_name(),
"Info Message : Verbo lvl - UVM_MEDIUM",UVM_MEDIUM);
uvm_report_warning(get_full_name(),
"Warning Messgae from rpting",UVM_LOW);
uvm_report_error(get_full_name(),
"Error Message from rpting \n\n",UVM_LOW);
endtask
endclass
module top;
rpting rpt1;
rpting rpt2;
rpting rpt3;
initial begin
rpt1 = new("rpt1",null);
rpt2 = new("rpt2",null);
rpt3 = new("rpt3",null);
rpt1.set_report_verbosity_level(UVM_MEDIUM);
rpt2.set_report_verbosity_level(UVM_LOW);
rpt3.set_report_verbosity_level(UVM_NONE);
run_test();
end
endmodule
uvm_reporting.tar
Browse the code in uvm_reporting.tar
Log file:
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
User should define these methods in the transaction using do_<method_name> and
call them using <method_name>. Following table shows calling methods and user-
defined hook do_<method_name> methods. Clone and create methods, does not
use hook methods concepts.
Shorthand Macros:
Using the field automation concept of uvm, all the above defines methods can be
defined automatically.
To use these field automation macros, first declare all the data fields, then place the
field automation macros between the `uvm_object_utils_begin and
`uvm_object_utils_end macros.
class Packet extends uvm_transaction;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] length;
rand bit [7:0] data[];
rand byte fcs;
`uvm_object_utils_begin(Packet)
`uvm_field_int(da, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(sa, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(length, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_array_int(data, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(fcs, UVM_ALL_ON|UVM_NOPACK)
`uvm_object_utils_end
endclass.
For most of the data types in systemverilog, uvm defined corresponding field
automation macros. Following table shows all the field automation macros.
Each `uvm_field_* macro has at least two arguments: ARG and FLAG.
ARG is the instance name of the variable and FLAG is used to control the field usage in
core utilities operation.
By default, FLAG is set to UVM_ALL_ON. All these flags can be ored. Using NO_* flags,
can turn of particular field usage in a paerticuler method. NO_* flags takes
precedency over other flags.
Example of Flags:
`uvm_field_int(da, UVM_ALL_ON|UVM_NOPACK)
The above macro will use the field "da" in all utilities methods except Packing and
unpacking methods.
In the following example, all the utility methods are defined using field automation
macros except Packing and unpacking methods. Packing and unpacking methods are
done in do_pack() amd do_unpack() method.
`include "uvm.svh"
import uvm_pkg::*;
class Packet extends uvm_transaction;
rand fcs_kind_t fcs_kind;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 6]};}
constraint length_c { length == data.size; }
function new(string name = "");
super.new(name);
endfunction : new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
///// method to calculate the fcs /////
virtual function byte cal_fcs;
integer i;
byte result ;
result = 0;
result = result ^ da;
result = result ^ sa;
result = result ^ length;
for (i = 0;i< data.size;i++)
result = result ^ data[i];
result = fcs ^ result;
return result;
endfunction : cal_fcs
`uvm_object_utils_begin(Packet)
`uvm_field_int(da, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(sa, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(length, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_array_int(data, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(fcs, UVM_ALL_ON|UVM_NOPACK)
`uvm_object_utils_end
function void do_pack(uvm_packer packer);
super.do_pack(packer);
packer.pack_field_int(da,$bits(da));
packer.pack_field_int(sa,$bits(sa));
packer.pack_field_int(length,$bits(length));
foreach(data[i])
packer.pack_field_int(data[i],8);
packer.pack_field_int(fcs,$bits(fcs));
endfunction : do_pack
function void do_unpack(uvm_packer packer);
int sz;
super.do_pack(packer);
da = packer.unpack_field_int($bits(da));
sa = packer.unpack_field_int($bits(sa));
length = packer.unpack_field_int($bits(length));
data.delete();
data = new[length];
foreach(data[i])
data[i] = packer.unpack_field_int(8);
fcs = packer.unpack_field_int($bits(fcs));
endfunction : do_unpack
endclass : Packet
/////////////////////////////////////////////////////////
//// Test to check the packet implementation ////
/////////////////////////////////////////////////////////
module test;
initial
repeat(10)
if(pkt1.randomize)
begin
$display(" Randomization Sucessesfull.");
pkt1.print();
uvm_default_packer.use_metadata = 1;
void'(pkt1.pack_bytes(pkdbytes));
$display("Size of pkd bits %d",pkdbytes.size());
pkt2.unpack_bytes(pkdbytes);
pkt2.print();
if(pkt2.compare(pkt1))
$display(" Packing,Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***
\n \n");
end
else
$display(" *** Randomization Failed ***");
endmodule
uvm_transaction.tar
Browse the code in uvm_transaction.tar
Log report:
Randomization Sucessesfull.
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
pkt1 Packet - pkt1@3
da integral 8 'h1d
sa integral 8 'h26
length integral 8 'h5
data da(integral) 5 -
[0] integral 8 'hb1
[1] integral 8 'h3f
[2] integral 8 'h9e
[3] integral 8 'h38
[4] integral 8 'h8d
fcs integral 8 'h9b
-------------------------------------------------------------------
---
Size of pkd bits 9
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
pkt2 Packet - pkt2@5
da integral 8 'h1d
sa integral 8 'h26
length integral 8 'h5
data da(integral) 5 -
[0] integral 8 'hb1
[1] integral 8 'h3f
[2] integral 8 'h9e
[3] integral 8 'h38
[4] integral 8 'h8d
fcs integral 8 'h9b
-------------------------------------------------------------------
---
Packing,Unpacking and compare worked
Search ✔
function void set_config_object (string inst_name,
Verilog string field_name,
Verification uvm_object value, bit clone = 1)
Verilog Switch TB
Basic Constructs Arguments description:
Specman E
Interview Questions "*" matches zero or more characters
"?" matches exactly one character
Some examples:
"ab?" -All the lower level components which start with "ab" , then followed by one
more character.
Example: "abc","abb","abx" ....
"?bc" -All the lower level components which start with any one character ,then
followed by "c".
Example: "abc","xbc","bbc" ....
"a?c" -All the lower level components which start with "a" , then followed by one
more character and then followed by "c".
Example: "abc","aac","axc" …..
Automatic Configuration:
To use the atomic configuration, all the configurable fields should be defined using
uvm component field macros and uvm component utilities macros.
Example:
Following example is from link
UVM_TESTBENCH
2 Configurable fields, a integer and a string are defined in env, agent, monitor and
driver classes. Topology of the environment using these classes is
Similar to driver class, all other components env, agent and monitor are define.
class driver extends uvm_driver;
integer int_cfg;
string str_cfg;
`uvm_component_utils_begin(driver)
`uvm_field_int(int_cfg, UVM_DEFAULT)
`uvm_field_string(str_cfg, UVM_DEFAULT)
`uvm_component_utils_end
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build();
super.build();
endfunction
endclass
Testcase:
//t_env.ag1.drv.int_cfg
//t_env.ag1.mon.int_cfg
set_config_int("*.ag1.*","int_cfg",32);
//t_env.ag2.drv
set_config_int("t_env.ag2.drv","int_cfg",32);
//t_env.ag2.mon
set_config_int("t_env.ag2.mon","int_cfg",32);
//t_env.ag1.mon.str_cfg
//t_env.ag2.mon.str_cfg
//t_env.ag1.drv.str_cfg
//t_env.ag2.drv.str_cfg
set_config_string("*.ag?.*","str_cfg","pars");
//t_env.str_cfg
set_config_string("t_env","str_cfg","abcd");
uvm_configuration_1.tar
Browse the code in uvm_configuration_1.tar
From the above log report of th example, we can see the variables int_cfg and str_cfg
of all the components and they are as per the configuration setting from the testcase.
Manual Configurations:
Using get_config_* methods, user can get the required data if the data is available in
the table.
Following are the method to get configure data of type integer , string and object of
uvm_object based class respectively.
function bit get_config_int (string field_name,
inout uvm_bitstream_t value)
function bit get_config_string (string field_name,
inout string value)
function bit get_config_object (string field_name,
inout uvm_object value,
input bit clone = 1)
If a entry is found in the table with "field_name" then data will be updated to "value"
argument . If entry is not found, then the function returns "0". So when these
methods are called, check the return value.
Example:
Driver class code:
class driver extends uvm_driver;
integer int_cfg;
string str_cfg;
`uvm_component_utils(driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build();
super.build();
void'(get_config_int("int_cfg",int_cfg));
void'(get_config_string("str_cfg",str_cfg));
uvm_report_info(get_full_name(),
$psprintf("int_cfg %0d : str_cfg %0s ",int_cfg,str_cfg),UVM_LOW);
endfunction
endclass
Download the source code
uvm_configuration_2.tar
Browse the code in uvm_configuration_2.tar
Log file
UVM_INFO @ 0: uvm_test_top.t_env
int_cfg x : str_cfg abcd
UVM_INFO @ 0: uvm_test_top.t_env.ag1
int_cfg x : str_cfg
UVM_INFO @ 0: uvm_test_top.t_env.ag1.drv
int_cfg 32 : str_cfg pars
UVM_INFO @ 0: uvm_test_top.t_env.ag1.mon
int_cfg 32 : str_cfg pars
UVM_INFO @ 0: uvm_test_top.t_env.ag2
int_cfg x : str_cfg
UVM_INFO @ 0: uvm_test_top.t_env.ag2.drv
int_cfg 32 : str_cfg pars
UVM_INFO @ 0: uvm_test_top.t_env.ag2.mon
int_cfg 32 : str_cfg pars
print_config_settings
function void print_config_settings
( string field = "",
uvm_component comp = null,
bit recurse = 0 )
print_config_matches
static bit print_config_matches = 0
Setting this static variable causes get_config_* to print info about matching
configuration settings as they are being applied. These two members will be helpful
to know while debugging.
uvm_configuration_3.tar
Browse the code in uvm_configuration_3.tar
Log file
When print_config_settings method is called
uvm_test_top.t_env.ag1.drv
uvm_test_top.*.ag1.* int_cfg int 32
uvm_test_top.t_env.ag1.drv.rsp_port
uvm_test_top.*.ag?.* str_cfg string pars
uvm_test_top.t_env.ag1.drv.rsp_port
uvm_test_top.*.ag1.* int_cfg int 32
uvm_test_top.t_env.ag1.drv.sqr_pull_port
uvm_test_top.*.ag?.* str_cfg string pars
uvm_test_top.t_env.ag1.drv.sqr_pull_port
uvm_test_top.*.ag1.* int_cfg int 32
Search ✔
Using the uvm fatroy, it is very easy to solve the above two requirements. Only classs
Verilog extended from uvm_object and uvm_component are supported for this.
Verification
There are three basic steps to be followed for using uvm factory.
Verilog Switch TB
Basic Constructs 1) Registration
2) Construction
3) Overriding
OpenVera
Constructs
The factory makes it is possible to override the type of uvm component /object or
instance of a uvm component/object in2 ways. They are based on uvm
Switch TB component/object type or uvm compoenent/object name.
RVM Switch TB
Registration:
RVM Ethernet sample
While defining a class , its type has to be registered with the uvm factory. To do this
job easier, uvm has predefined macros.
Specman E
Interview Questions `uvm_component_utils(class_type_name)
`uvm_component_param_utils(class_type_name #(params))
`uvm_object_utils(class_type_name)
`uvm_object_param_utils(class_type_name #(params))
For uvm_*_param_utils are used for parameterized classes and other two macros for
non-parameterized class. Registration is required for name-based overriding , it is
not required for type-based overriding.
class packet extends uvm_object;
`uvm_object_utils(packet)
endclass
class packet #(type T=int, int mode=0) extends uvm_object;
`uvm_object_param_utils(packet #(T,mode))
endclass
class driver extends uvm_component;
`uvm_component_utils(driver)
endclass
class monitor #(type T=int, int mode=0) extends uvm_component;
`uvm_component_param_utils(driver#(T,mode))
endclass
Construction:
To construct a uvm based component or uvm based objects, static method create()
should be used. This function constructs the appropriate object based on the
overrides and constructs the object and returns it. So while constructing the uvm
based components or uvm based objects , do not use new() constructor.
Syntax :
static function T create(string name,
uvm_component parent,
string context = " ")
EXAMPLE:
class_type object_name;
object_name = clss_type::type_id::creat("object_name",this);
For uvm_object based classes, doesnt need the parent handle as second argument.
Overriding:
If required, user could override the registered classes or objects. User can override
based of name string or class-type.
function void set_inst_override_by_type
(uvm_object_wrapper original_type,
uvm_object_wrapper override_type,
string full_inst_path )
The above method is used to override the object instances of "original_type" with
"override_type" . "override_type" is extended from"original_type".
function void set_inst_override_by_name
(string original_type_name,
string override_type_name,
string full_inst_path )
Original_type_name and override_type_name are the class names which are registered
in the factory. All the instances of objects with name "Original_type_name" will be
overriden with objects of name "override_type_name" using
set_inst_override_by_name() method.
function void set_type_override_by_type
(uvm_object_wrapper original_type,
uvm_object_wrapper override_type,
bit replace = 1 )
function void set_type_override_by_name
(string original_type_name,
string override_type_name,
bit replace = 1)
When multiple overrides are done , then using the argument "replace" , we can
control whether to override the previous override or not. If argument "replace" is 1,
then previous overrides will be replaced otherwise, previous overrides will remain.
print() method, prints the state of the uvm_factory, registered types, instance
overrides, and type overrides.
Now we will see a complete example. This example is based on the environment build
in topic UVM TESTBENCH . Refer to that section for more information about this
example.
Lets look at the 3 steps which I discussed above using the example defined in UVM
TESTBENCH
1) Registration
2) Construction
In file agant.sv file, monitor and driver are constructed using create() method.
mon = monitor::type_id::create("mon",this);
drv = driver::type_id::create("drv",this);
In this example, there is one driver class and one monitor class. In this testcase , By
extending driver class , we will define driver_2 class and by extending monitor class,
we will define monitor_2 class.
To know about the overrides which are done, call factory.print() method of factory
class.
class driver_2 extends driver;
`uvm_component_utils(driver_2)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class monitor_2 extends monitor;
`uvm_component_utils(monitor_2)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class test_factory extends uvm_test;
`uvm_component_utils(test_factory)
env t_env;
function new (string name="test1", uvm_component parent=null);
super.new (name, parent);
factory.set_type_override_by_type(driver::get_type(),driver_2::get_type(),"*");
factory.set_type_override_by_name("monitor","monitor_2","*");
factory.print();
t_env = new("t_env",this);
endfunction : new
function void end_of_elaboration();
uvm_report_info(get_full_name(),"End_of_elaboration", UVM_LOW);
print();
endfunction : end_of_elaboration
task run ();
#1000;
global_stop_request();
endtask : run
endclass
uvm_factory.tar
Browse the code in uvm_factory.tar
Command to simulate
Command to run the example with the testcase which is defined above:
VCS Users : make vcs
Questa Users: make questa
Method factory.print() displayed all the overrides as shown below in the log file.
In the below text printed by print_topology() method ,we can see overridden driver
and monitor.
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
uvm_test_top test_factory - uvm_test_top@2
t_env env - t_env@4
ag1 agent - ag1@6
drv driver_2 - drv@12
rsp_port uvm_analysis_port - rsp_port@16
sqr_pull_port uvm_seq_item_pull_+ - sqr_pull_port@14
mon monitor_2 - mon@10
ag2 agent - ag2@8
drv driver_2 - drv@20
rsp_port uvm_analysis_port - rsp_port@24
sqr_pull_port uvm_seq_item_pull_+ - sqr_pull_port@22
mon monitor_2 - mon@18
-------------------------------------------------------------------
---
In the below text printed by print_topology() method ,with testcase test1 which does
note have overrides.
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
uvm_test_top test1 - uvm_test_top@2
t_env env - t_env@4
ag1 agent - ag1@6
drv driver - drv@12
rsp_port uvm_analysis_port - rsp_port@16
sqr_pull_port uvm_seq_item_pull_+ - sqr_pull_port@14
mon monitor - mon@10
ag2 agent - ag2@8
drv driver - drv@20
rsp_port uvm_analysis_port - rsp_port@24
sqr_pull_port uvm_seq_item_pull_+ - sqr_pull_port@22
mon monitor - mon@18
-------------------------------------------------------------------
---
Search ✔
uvm_sequence_item :
Verilog User has to define a transaction by extending
uvm_sequence_item. uvm_sequence_item class provides the basic functionality for
Verification objects, both sequence items and sequences, to operate in the sequence mechanism.
Verilog Switch TB For more information about uvm_sequence_item Refer to link
Basic Constructs
UVM_TRANSACTION
uvm_sequence:
OpenVera User should extend uvm_sequence class and define the construction of sequence of
Constructs transactions. These transactions can be directed, constrained randomized or fully
randomized. The uvm_sequence class provides the interfaces necessary in order to
Switch TB
create streams of sequence items and/or other sequences.
RVM Switch TB
RVM Ethernet sample
virtual class uvm_sequence #(
type REQ = uvm_sequence_item,
type RSP = REQ
Specman E )
Interview Questions
uvm_sequencer:
uvm_sequencer is responsible for the coordination between sequence and driver.
Sequencer sends the transaction to driver and gets the response from the driver. The
response transaction from the driver is optional. When multiple sequences are running
in parallel, then sequencer is responsible for arbitrating between the parallel
sequences. There are two types of sequencers : uvm_sequencer and
uvm_push_sequencer
class uvm_sequencer #(
type REQ = uvm_sequence_item,
type RSP = REQ
)
class uvm_push_sequencer #(
type REQ = uvm_sequence_item,
type RSP = REQ
)
uvm driver:
User should extend uvm_driver class to define driver component. uvm driver is a
component that initiate requests for new transactions and drives it to lower level
components. There are two types of drivers: uvm_driver and uvm_push_driver.
class uvm_driver #(
type REQ = uvm_sequence_item,
type RSP = REQ
)
class uvm_push_driver #(
type REQ = uvm_sequence_item,
type RSP = REQ
)
The above image shows how a transaction from a sequence is sent to driver and the
response from the driver is sent to sequencer. There are multiple methods called
during this operation.
6) The transaction which is sent from sequence , in the driver this transaction is
available as "seq_item_port.get_next_item(req)" method argument. Then driver can
drive this transaction to bus or lower level.
After this step, again the steps 1 to 7 are repeated five times.
If a response from driver is not required, then steps 5,6,7 can be skipped and
item_done() method from driver should be called as shown in above image.
Simple Example
Sequence Item
class instruction extends uvm_sequence_item;
typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_t;
rand inst_t inst;
`uvm_object_utils_begin(instruction)
`uvm_field_enum(inst_t,inst, UVM_ALL_ON)
`uvm_object_utils_end
function new (string name = "instruction");
super.new(name);
endfunction
`uvm_object_utils_begin(instruction)
`uvm_field_enum(inst_t,inst, UVM_ALL_ON)
`uvm_object_utils_end
function new (string name = "instruction");
super.new(name);
endfunction
endclass
Sequence
function new(string name="operation_addition");
super.new(name);
endfunction
`uvm_sequence_utils(operation_addition, instruction_sequencer)
4)
In the body() method, first call wait_for_grant(), then construct a transaction and set
the instruction enum to PUSH_A . Then send the transaction to driver using
send_request() method. Then call the wait_for_item_done() method. Repeat the
above steps for other instructions PUSH_B, ADD and POP_C.
For construction of a transaction, we will use the create() method.
virtual task body();
req = instruction::type_id::create("req");
wait_for_grant();
assert(req.randomize() with {
inst == instruction::PUSH_A;
});
send_request(req);
wait_for_item_done();
//get_response(res); This is optional. Not using in this example.
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::PUSH_B;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::ADD;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::POP_C;
send_request(req);
wait_for_item_done();
//get_response(res);
endtask
Sequence code
instruction req;
function new(string name="operation_addition");
super.new(name);
endfunction
`uvm_sequence_utils(operation_addition, instruction_sequencer)
virtual task body();
req = instruction::type_id::create("req");
wait_for_grant();
assert(req.randomize() with {
inst == instruction::PUSH_A;
});
send_request(req);
wait_for_item_done();
//get_response(res); This is optional. Not using in this example.
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::PUSH_B;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::ADD;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::POP_C;
send_request(req);
wait_for_item_done();
//get_response(res);
endtask
endclass
Sequencer:
function new (string name, uvm_component parent);
super.new(name, parent);
`uvm_update_sequence_lib_and_item(instruction)
endfunction
3) Place the uvm_sequencer_utils macro. This macro registers the sequencer for
factory overrides.
`uvm_sequencer_utils(instruction_sequencer)
Sequencer Code;
class instruction_sequencer extends uvm_sequencer #(instruction);
function new (string name, uvm_component parent);
super.new(name, parent);
`uvm_update_sequence_lib_and_item(instruction)
endfunction
`uvm_sequencer_utils(instruction_sequencer)
endclass
Driver:
Seq_item_port methods:
1) Define a driver which takes the instruction from the sequencer and does the
processing. In this example we will just print the instruction type and wait for some
delay.
`uvm_component_utils(instruction_driver)
3) Define Constructor method.
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction
4) Define the run() method. Run() method is executed in the "run phase". In this
methods, transactions are taken from the sequencer and drive them on to dut
interface or to other components.
Driver class has a port "seq_item_port". Using the method
seq_item_port.get_next_item(), get the transaction from the sequencer and process
it. Once the processing is done, using the item_done() method, indicate to the
sequencer that the request is completed. In this example, after taking the
transaction, we will print the transaction and wait for 10 units time.
task run ();
while(1) begin
seq_item_port.get_next_item(req);
$display("%0d: Driving Instruction %s",$time,req.inst.name());
#10;
seq_item_port.item_done();
end
endtask
endclass
// Constructor
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction
task run ();
forever begin
seq_item_port.get_next_item(req);
$display("%0d: Driving Instruction %s",$time,req.inst.name());
#10;
// rsp.set_id_info(req); These two steps are required only if
// seq_item_port.put(esp); responce needs to be sent back to sequence
seq_item_port.item_done();
end
endtask
endclass
Deriver and sequencer are connected using TLM. uvm_driver has seq_item_port which
is used to get the transaction from uvm sequencer. This port is connected to
uvm_sequencer seq_item_export Using
"<driver>.seq_item_port.connect(<sequencer>.seq_item_export);" driver and
sequencer can be connected. Simillarly "res_port" of driver which is used to send
response from driver to sequencer is connected to "res_export" of the sequencer using
""<driver>.res_port.connect(<sequencer>.res_export);".
Testcase:
This testcase is used only for the demo purpose of this tutorial session. Actually, the
sequencer and the driver and instantiated and their ports are connected in a agent
component and used. Lets implement a testcase
sequencer = new("sequencer", null);
sequencer.build();
driver = new("driver", null);
driver.build();
2)
Connect the seq_item_export to the drivers seq_item_port.
driver.seq_item_port.connect(sequencer.seq_item_export);
set_config_string("sequencer", "default_sequence", "operation_addition");
sequencer.start_default_sequence();
Testcase Code:
module test;
instruction_sequencer sequencer;
instruction_driver driver;
initial begin
set_config_string("sequencer", "default_sequence", "operation_addition");
sequencer = new("sequencer", null);
sequencer.build();
driver = new("driver", null);
driver.build();
driver.seq_item_port.connect(sequencer.seq_item_export);
sequencer.print();
fork
begin
run_test();
sequencer.start_default_sequence();
end
#2000 global_stop_request();
join
end
endmodule
uvm_basic_sequence.tar
Browse the code in uvm_basic_sequence.tar
Command to simulate
From the above log , we can see that transactions are generates as we defined in uvm
sequence.
Search ✔
Verilog
Verification uvm_random_sequence :
Verilog Switch TB
This sequence randomly selects and executes a sequence from the sequencer
Basic Constructs sequence library, excluding uvm_random_sequence itself, and
uvm_exhaustive_sequence. From the above image, from sequence id 2 to till the last
sequence, all the sequences are executed randomly. If the "count" variable of the
OpenVera sequencer is set to 0, then non of the sequence is executed. If the "count" variable of
Constructs the sequencer is set to -1, then some random number of sequences from 0 to
"max_random_count" are executed. By default "max_random_count" is set to
Switch TB 10. "Count" and "max_random_count" can be changed using set_config_int().
RVM Switch TB
The sequencer when automatically started executes the sequence which is point by
RVM Ethernet sample default_sequence. By default default_sequence variable points to
uvm_random_sequence.
Specman E uvm_exhaustive_sequence:
Interview Questions This sequence randomly selects and executes each sequence from the sequencers
sequence library once in a randc style, excluding itself and uvm_random_sequence.
uvm_simple_sequence:
The print() method of the sequencer in that example printed the following
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
sequencer instruction_sequen+ - sequencer@2
rsp_export uvm_analysis_export - rsp_export@4
seq_item_export uvm_seq_item_pull_+ - seq_item_export@28
default_sequence string 18 operation_addition
count integral 32 -1
max_random_count integral 32 'd10
sequences array 4 -
[0] string 19 uvm_random_sequence
[1] string 23 uvm_exhaustive_sequ+
[2] string 19 uvm_simple_sequence
[3] string 18 operation_addition
max_random_depth integral 32 'd4
num_last_reqs integral 32 'd1
num_last_rsps integral 32 'd1
-------------------------------------------------------------------
---
Lets look at a example: In the attached example, in file sequence.sv file, there are 4
seuqneces, they are operation_addition, operation_subtraction,
operation_multiplication.
uvm_sequence_1.tar
Browse the code in uvm_sequence_1.tar
Log File
0: Driving Instruction PUSH_B
From the above log , we can see that all the 3 user defined sequences and predefined
uvm_simple_sequence are executed.
All these steps have be automated using "sequence action macros". There are some
more additional steps added in these macros. Following are the steps defined with the
"sequence action macro".
Pre_do(), mid_do() and post_do() are callback methods which are in uvm sequence. If
user is interested , he can use these methods. For example, in mid_do() method, user
can print the transaction or the randomized transaction can be fined tuned. These
methods should not be clled by user directly.
Syntax:
virtual task pre_do(bit is_item)
virtual function void mid_do(uvm_sequence_item this_item)
virtual function void post_do(uvm_sequence_item this_item)
Pre_do() is a task , if the method consumes simulation cycles, the behavior may be
unexpected.
Lets look at a example: We will define a sequence using `uvm_do macro. This macro
has all the above defined phases.
1)Define the body method using the `uvm_do() macro. Before and after this macro,
just call messages.
virtual task body();
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : Before uvm_do macro ",UVM_LOW);
`uvm_do(req);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : After uvm_do macro ",UVM_LOW);
endtask
2)Define pre_do() method. Lets just print a message from this method.
virtual task pre_do(bit is_item);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : PRE_DO ",UVM_LOW);
endtask
3)Define mid_do() method. Lets just print a message from this method.
virtual function void mid_do(uvm_sequence_item this_item);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : MID_DO ",UVM_LOW);
endfunction
4)Define post_do() method. Lets just print a message from this method.
virtual function void post_do(uvm_sequence_item this_item);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : POST_DO ",UVM_LOW);
endfunction
instruction req;
function new(string name="demo_uvm_do");
super.new(name);
endfunction
`uvm_sequence_utils(demo_uvm_do, instruction_sequencer)
virtual task pre_do(bit is_item);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : PRE_DO ",UVM_LOW);
endtask
virtual function void mid_do(uvm_sequence_item this_item);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : MID_DO ",UVM_LOW);
endfunction
virtual function void post_do(uvm_sequence_item this_item);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : POST_DO ",UVM_LOW);
endfunction
virtual task body();
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : Before uvm_do macro ",UVM_LOW);
`uvm_do(req);
uvm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : After uvm_do macro ",UVM_LOW);
endtask
endclass
uvm_sequence_2.tar
Browse the code in uvm_sequence_2.tar
UVM_INFO@0:reporter[sequencer.demo_uvm_do]
Seuqnce Action Macro Phase : Before uvm_do macro
UVM_INFO@0:reporter[sequencer.demo_uvm_do]
Seuqnce Action Macro Phase : PRE_DO
UVM_INFO@0:reporter[sequencer.demo_uvm_do]
Seuqnce Action Macro Phase : MID_DO
0: Driving Instruction MUL
UVM_INFO@10:reporter[sequencer.demo_uvm_do]
Seuqnce Action Macro Phase : POST_DO
UVM_INFO@10:reporter[sequencer.demo_uvm_do]
Seuqnce Action Macro Phase : After uvm_do macro
The above log file shows the messages from pre_do,mid_do and post_do methods.
These macros are used to start sequences and sequence items that were either
registered with a <`uvm-sequence_utils> macro or whose associated sequencer was
already set using the <set_sequencer> method.
`uvm_create(item/sequence)
This action creates the item or sequence using the factory. Only the create phase will
be executed.
`uvm_do(item/sequence)
This is the same as `uvm_do except that the constraint block in the 2nd argument is
applied to the item or sequence in a randomize with statement before execution.
`uvm_send(item/sequence)
Create phase and randomize phases are skipped, rest all the phases will be executed.
Using `uvm_create, create phase can be executed. Essentially, an `uvm_do without
the create or randomization.
`uvm_rand_send(item/sequence)
Only create phase is skipped. rest of all the phases will be executed. User should use
`uvm_create to create the sequence or item.
Only create phase is skipped. rest of all the phases will be executed. User should use
`uvm_create to create the sequence or item. Constraint block will be applied which
randomization.
`uvm_do_pri(item/sequence, priority )
This is the same as `uvm_do except that the sequence item or sequence is executed
with the priority specified in the argument.
This is the same as `uvm_do_pri except that the given constraint block is applied to
the item or sequence in a randomize with statement before execution.
`uvm_send_pri(item/sequence,priority)
This is the same as `uvm_send except that the sequence item or sequence is executed
with the priority specified in the argument.
`uvm_rand_send_pri(item/sequence,priority)
This is the same as `uvm_rand_send except that the sequence item or sequence is
executed with the priority specified in the argument.
`uvm_rand_send_pri_with(item/sequence,priority,constraint block)
This is the same as `uvm_rand_send_pri except that the given constraint block is
applied to the item or sequence in a randomize with statement before execution.
`uvm_create_on(item/sequence,sequencer)
This is the same as `uvm_create except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
`uvm_do_on(item/sequence,sequencer)
This is the same as `uvm_do except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
`uvm_do_on_pri(item/sequence,sequencer, priority)
This is the same as `uvm_do_pri except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
This is the same as `uvm_do_with except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument. The user must supply brackets around the constraints.
`uvm_do_on_pri_with(item/sequence,sequencer,priority,constraint block)
This is the same as `uvm_do_pri_with except that it also sets the parent sequence to
the sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
virtual task body();
uvm_report_info(get_full_name(),
"Executing Sequence Action Macro uvm_do",UVM_LOW);
`uvm_do(req)
endtask
virtual task body();
uvm_report_info(get_full_name(),
"Executing Sequence Action Macro uvm_do_with ",UVM_LOW);
`uvm_do_with(req,{ inst == ADD; })
endtask
virtual task body();
uvm_report_info(get_full_name(),
"Executing Sequence Action Macro uvm_create and uvm_send",UVM_LOW);
`uvm_create(req)
req.inst = instruction::PUSH_B;
`uvm_send(req)
endtask
virtual task body();
uvm_report_info(get_full_name(),
"Executing Sequence Action Macro uvm_create and
uvm_rand_send",UVM_LOW);
`uvm_create(req)
`uvm_rand_send(req)
endtask
uvm_sequence_3.tar
Browse the code in uvm_sequence_3.tar
0: Driving Instruction PUSH_B
UVM_INFO@10:reporter[***]Executing Sequence Action Macro uvm_do_with
10: Driving Instruction ADD
UVM_INFO@20:reporter[***]Executing Sequence Action Macro uvm_create and
uvm_send
20: Driving Instruction PUSH_B
UVM_INFO@30:reporter[***]Executing Sequence Action Macro uvm_do
30: Driving Instruction DIV
UVM_INFO@40:reporter[***]Executing Sequence Action Macro uvm_create and
uvm_rand_send
40: Driving Instruction MUL
Search ✔
Verilog virtual task pre_body();
Verification uvm_report_info(get_full_name()," pre_body() callback ",UVM_LOW);
endtask
Verilog Switch TB
Basic Constructs virtual task post_body();
uvm_report_info(get_full_name()," post_body() callback ",UVM_LOW);
endtask
OpenVera virtual task body();
Constructs uvm_report_info(get_full_name(),
Switch TB "body() method: Before uvm_do macro ",UVM_LOW);
`uvm_do(req);
RVM Switch TB uvm_report_info(get_full_name(),
RVM Ethernet sample "body() method: After uvm_do macro ",UVM_LOW);
endtask
endclass
Specman E
Interview Questions
Download the example
uvm_sequence_4.tar
Browse the code in uvm_sequence_4.tar
Hierarchical Sequences
Sequential Sequences
Sequence 1 code:
virtual task body();
repeat(4) begin
`uvm_do_with(req, { inst == PUSH_A; });
end
endtask
Sequence 2 code:
virtual task body();
repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
endtask
seq_a s_a;
seq_b s_b;
function new(string name="sequential_sequence");
super.new(name);
endfunction
`uvm_sequence_utils(sequential_sequence, instruction_sequencer)
virtual task body();
`uvm_do(s_a);
`uvm_do(s_b);
endtask
endclass
uvm_sequence_5.tar
Browse the code in uvm_sequence_5.tar
0: Driving Instruction PUSH_A
10: Driving Instruction PUSH_A
20: Driving Instruction PUSH_A
30: Driving Instruction PUSH_A
40: Driving Instruction PUSH_B
50: Driving Instruction PUSH_B
60: Driving Instruction PUSH_B
70: Driving Instruction PUSH_B
If you observe the above log, you can see sequence seq_a is executed first and then
sequene seq_b is executed.
Parallelsequences
To executes child sequences Parallel, child sequence start() method should be called
parallel using fork/join in body method.
seq_a s_a;
seq_b s_b;
function new(string name="parallel_sequence");
super.new(name);
endfunction
`uvm_sequence_utils(parallel_sequence, instruction_sequencer)
virtual task body();
fork
`uvm_do(s_a)
`uvm_do(s_b)
join
endtask
endclass
uvm_sequence_6.tar
Browse the code in uvm_sequence_6.tar
Search ✔
Verilog
Verification
To set the arbitaration, use the set_arbitration() method of the sequencer. By default
Verilog Switch TB , the arbitration algorithms is set to SEQ_ARB_FIFO.
Basic Constructs
function void set_arbitration(SEQ_ARB_TYPE val)
Sequence code 3:
virtual task body();
repeat(3) begin
`uvm_do_with(req, { inst == SUB; });
end
endtask
In the body method, before starting child sequences, set the arbitration using
set_arbitration(). In this code, im setting it to SEQ_ARB_RANDOM.
seq_add add;
seq_sub sub;
seq_mul mul;
function new(string name="parallel_sequence");
super.new(name);
endfunction
`uvm_sequence_utils(parallel_sequence, instruction_sequencer)
virtual task body();
m_sequencer.set_arbitration(SEQ_ARB_RANDOM);
fork
`uvm_do(add)
`uvm_do(sub)
`uvm_do(mul)
join
endtask
endclass
uvm_sequence_7.tar
Browse the code in uvm_sequence_7.tar
0: Driving Instruction MUL
10: Driving Instruction SUB
20: Driving Instruction MUL
30: Driving Instruction SUB
40: Driving Instruction MUL
50: Driving Instruction ADD
60: Driving Instruction ADD
70: Driving Instruction SUB
80: Driving Instruction ADD
0: Driving Instruction ADD
10: Driving Instruction SUB
20: Driving Instruction MUL
30: Driving Instruction ADD
40: Driving Instruction SUB
50: Driving Instruction MUL
60: Driving Instruction ADD
70: Driving Instruction SUB
80: Driving Instruction MUL
If you observe the first log report, all the transaction of the sequences are generated
in random order. In the second log file, the transactions are given equal priority and
are in fifo order.
There are two ways to set the priority of a sequence. One is using the start method of
the sequence and other using the set_priority() method of the sequence. By default,
the priority of a sequence is 100. Higher numbers indicate higher priority.
virtual task start (uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
integer this_priority = 100,
bit call_pre_post = 1)
function void set_priority (int value)
In the below example, start() method is used to override the default priority value.
Code :
seq_add add;
seq_sub sub;
seq_mul mul;
function new(string name="parallel_sequence");
super.new(name);
endfunction
`uvm_sequence_utils(parallel_sequence, instruction_sequencer)
virtual task body();
m_sequencer.set_arbitration(SEQ_ARB_WEIGHTED);
add = new("add");
sub = new("sub");
mul = new("mul");
fork
sub.start(m_sequencer,this,400);
add.start(m_sequencer,this,300);
mul.start(m_sequencer,this,200);
join
endtask
endclass
uvm_sequence_8.tar
Browse the code in uvm_sequence_8.tar
0: Driving Instruction MUL
10: Driving Instruction ADD
Search ✔
rand integer num_inst ;
OpenVera instruction req;
Constructs
Switch TB constraint num_c { num_inst inside { 3,5,7 }; };
RVM Switch TB `uvm_sequence_utils_begin(seq_mul,instruction_sequencer)
RVM Ethernet sample `uvm_field_int(num_inst, UVM_ALL_ON)
`uvm_sequence_utils_end
function new(string name="seq_mul");
Specman E super.new(name);
Interview Questions endfunction
virtual task body();
uvm_report_info(get_full_name(),
$psprintf("Num of transactions %d",num_inst),UVM_LOW);
repeat(num_inst) begin
`uvm_do_with(req, { inst == MUL; });
end
endtask
endclass
uvm_sequence_9.tar
Browse the code in uvm_sequence_9.tar
Log
set_config_* can be used only for the components not for the sequences.
By using configuration you can change the variables inside components only not in
sequences.
Sequence has handle name called p_sequencer which is pointing the Sequencer on
which it is running.
Sequencer is a component , so get_config_* methods are implemented for it.
So from the sequence, using the sequencer get_config_* methods, sequence members
can be updated if the variable is configured.
When using set_config_* , path to the variable should be sequencer name, as we are
using the sequencer get_config_* method.
Sequence:
integer num_inst = 4;
instruction req;
`uvm_sequence_utils_begin(seq_mul,instruction_sequencer)
`uvm_field_int(num_inst, UVM_ALL_ON)
`uvm_sequence_utils_end
function new(string name="seq_mul");
super.new(name);
endfunction
virtual task body();
void'(p_sequencer.get_config_int("num_inst",num_inst));
uvm_report_info(get_full_name(),
$psprintf("Num of transactions %d",num_inst),UVM_LOW);
repeat(num_inst) begin
`uvm_do_with(req, { inst == MUL; });
end
endtask
endclass
Testcase:
From the testcase, using the set_config_int() method, configure the num_inst to 3.
The instance path argument should be the sequencer path name.
module test;
instruction_sequencer sequencer;
instruction_driver driver;
initial begin
set_config_string("sequencer", "default_sequence", "seq_mul");
set_config_int("sequencer", "num_inst",3);
sequencer = new("sequencer", null);
sequencer.build();
driver = new("driver", null);
driver.build();
driver.seq_item_port.connect(sequencer.seq_item_export);
sequencer.print();
fork
begin
run_test();
sequencer.start_default_sequence();
end
#3000 global_stop_request();
join
end
endmodule
uvm_sequence_10.tar
Browse the code in uvm_sequence_10.tar
Log
Search ✔
Sequence 1 code:
OpenVera
virtual task body();
Constructs repeat(4) begin
Switch TB `uvm_do_with(req, { inst == PUSH_A; });
end
RVM Switch TB
endtask
RVM Ethernet sample
Sequence 2 code:
virtual task body();
repeat(4) begin
Specman E
`uvm_do_with(req, { inst == POP_C; });
Interview Questions end
endtask
Sequence 3 code:
In this sequence , call the lock() method to get the exclusive access to driver.
After completing all the transaction driving, then call the unclock() method.
virtual task body();
lock();
repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
unlock();
endtask
virtual task body();
fork
`uvm_do(s_a)
`uvm_do(s_b)
`uvm_do(s_c)
join
endtask
uvm_sequence_11.tar
Browse the code in uvm_sequence_11.tar
Log file:
0: Driving Instruction PUSH_A
10: Driving Instruction POP_C
20: Driving Instruction PUSH_A
30: Driving Instruction PUSH_B
40: Driving Instruction PUSH_B
50: Driving Instruction PUSH_B
60: Driving Instruction PUSH_B
70: Driving Instruction POP_C
80: Driving Instruction PUSH_A
90: Driving Instruction POP_C
100: Driving Instruction PUSH_A
110: Driving Instruction POP_C
From the above log file, we can observe that , when seq_b sequence got the access,
then transactions from seq_a and seq_c are not generated.
Lock() will be arbitrated before giving the access. To get the exclusive access without
arbitration, grab() method should be used.
Grab-Ungrab
grab() method requests a lock on the specified sequencer. A grab() request is put in
front of the arbitration queue. It will be arbitrated before any other requests. A
grab() is granted when no other grabs or locks are blocking this sequence.
Ungrab() method removes any locks or grabs obtained by this sequence on the
specified sequencer.
If no argument is supplied, then current default sequencer is chosen.
Example:
virtual task body();
#25;
grab();
repeat(4) begin
`uvm_do_with(req, { inst == PUSH_B; });
end
ungrab();
endtask
uvm_sequence_12.tar
Browse the code in uvm_sequence_12.tar
0: Driving Instruction PUSH_A
10: Driving Instruction POP_C
20: Driving Instruction PUSH_A
30: Driving Instruction PUSH_B
40: Driving Instruction PUSH_B
50: Driving Instruction PUSH_B
60: Driving Instruction PUSH_B
70: Driving Instruction POP_C
80: Driving Instruction PUSH_A
90: Driving Instruction POP_C
100: Driving Instruction PUSH_A
110: Driving Instruction POP_C
Search ✔
Specman E
Interview Questions
In the above environment, methods are used to transfer the data between
components. So, this gives a better control and data transfer is done at high level.
The disadvantage is, components are using hierarchal paths which do not allow the
reusability.
TLM interfaces:
UVM has TLM interfaces which provide the advantages which we saw in the above two
data transfer styles.
Data is transferred at high level. Transactions which are developed by extending the
uvm_sequence_item can be transferred between components using method calls.
These methods are not hierarchal fixed, so that components can be reused.
Putting:
Producer transfers a value to Consumer.
Getting:
Consumer requires a data value from producer.
Peeking:
Copies data from a producer without consuming the data.
Broadcasting:
Transaction is broadcasted to none or one or multiple consumers.
Methods
BLOCKING:
virtual task put(input T1 t)
virtual task get(output T2 t)
virtual task peek(output T2 t)
NON-BLOCKIN:
virtual function bit try_put(input T1 t)
virtual function bit can_put()
virtual function bit try_get(output T2 t)
virtual function bit can_get()
virtual function bit try_peek(output T2 t)
virtual function bit can_peek()
BLOCKING TRANSPORT:
virtual task transport(input T1 req,output T2 rsp)
NON-BLOCKING TRANSPORT:
virtual function bit nb_transport(input T1 req,output T2 rsp)
ANALYSIS:
virtual function void write(input T1 t)
Tlm Terminology :
Producer:
A component which generates a transaction.
Consumer:
A component which consumes the transaction.
Initiator:
A component which initiates process.
Target:
A component which responded to initiator.
Blocking:
A blocking interface conveys transactions in blocking fashion; its methods do not
return until the transaction has been successfully sent or retrieved. Its methods are
defined as tasks.
Non-blocking:
A non-blocking interface attempts to convey a transaction without consuming
simulation time. Its methods are declared as functions. Because delivery may fail
(e.g. the target component is busy and can not accept the request), the methods may
return with failed status.
Combined:
Interfaces:
The UVM provides ports, exports and implementation and analysis ports for connecting
your components via the TLM interfaces. Port, Export, implementation terminology
applies to control flow not to data flow.
Port:
Interface that requires an implementation is port.
Import:
Interface that provides an implementation is import ot implementation port.
Export:
Interface used to route transaction interfaces to other layers of the hierarchy.
Analysis:
Interface used to distribute transactions to passive components.
Direction:
Unidirectional:
Data transfer is done in a single direction and flow of control is in either or both
direction.
Bidirectional:
Data transfer is done in both directions and flow of control is in either or both
directions.
Examples:
A read operation is a bidirectional.
A write operation is unidirectional.
Transaction
class instruction extends uvm_sequence_item;
typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_t;
rand inst_t inst;
`uvm_object_utils_begin(instruction)
`uvm_field_enum(inst_t,inst, UVM_ALL_ON)
`uvm_object_utils_end
function new (string name = "instruction");
super.new(name);
endfunction
endclass
Producer:
class producer extends uvm_component;
endclass : producer
uvm_blocking_put_port#(instruction) put_port;
function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);
endfunction
task run;
for(int i = 0; i < 10; i++)
begin
instruction ints;
#10;
ints = new();
if(ints.randomize()) begin
`uvm_info("producer", $sformatf("sending
%s",ints.inst.name()), UVM_MEDIUM)
put_port.put(ints);
end
end
endtask
uvm_blocking_put_port#(instruction) put_port;
function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);
endfunction
task run;
for(int i = 0; i < 10; i++)
begin
instruction ints;
#10;
ints = new();
if(ints.randomize()) begin
`uvm_info("producer", $sformatf("sending
%s",ints.inst.name()), UVM_MEDIUM)
put_port.put(ints);
end
end
endtask
endclass : producer
Consumer:
class consumer extends uvm_component;
endclass : consumer
uvm_blocking_put_imp#(instruction,consumer) put_port;
function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);
endfunction
task put(instruction t);
`uvm_info("consumer", $sformatf("receiving %s",t.inst.name()), UVM_MEDIUM)
endtask
uvm_blocking_put_imp#(instruction,consumer) put_port;
function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);
endfunction
task put(instruction t);
`uvm_info("consumer", $sformatf("receiving %s",t.inst.name()), UVM_MEDIUM)
//push the transaction into queue or array
//or drive the transaction to next level
//or drive to interface
endtask
endclass : consumer
In the env class, take the instance of producer and consumer components.
In the connect method, connect the producer put_port to consumer put_port using
p.put_port.connect(c.put_port);
endmodule
uvm_tlm_1.tar
Browse the code in uvm_tlm_1.tar
Log
uvm_tlm_2.tar
Browse the code in uvm_tlm_2.tar
uvm_blocking_put_port #(T)
uvm_nonblocking_put_port #(T)
uvm_put_port #(T)
uvm_blocking_get_port #(T)
uvm_nonblocking_get_port #(T)
uvm_get_port #(T)
uvm_blocking_peek_port #(T)
uvm_nonblocking_peek_port #(T)
uvm_peek_port #(T)
uvm_blocking_get_peek_port #(T)
uvm_nonblocking_get_peek_port #(T)
uvm_get_peek_port #(T)
uvm_analysis_port #(T)
uvm_transport_port #(REQ,RSP)
uvm_blocking_transport_port #(REQ,RSP)
uvm_nonblocking_transport_port #(REQ,RSP)
uvm_master_port #(REQ,RSP)
uvm_blocking_master_port #(REQ,RSP)
uvm_nonblocking_master_port #(REQ,RSP)
uvm_slave_port #(REQ,RSP)
uvm_blocking_slave_port #(REQ,RSP)
uvm_nonblocking_slave_port #(REQ,RSP)
uvm_put_export #(T)
uvm_blocking_put_export #(T)
uvm_nonblocking_put_export #(T)
uvm_get_export #(T)
uvm_blocking_get_export #(T)
uvm_nonblocking_get_export #(T)
uvm_peek_export #(T)
uvm_blocking_peek_export #(T)
uvm_nonblocking_peek_export #(T)
uvm_get_peek_export #(T)
uvm_blocking_get_peek_export #(T)
uvm_nonblocking_get_peek_export #(T)
uvm_analysis_export #(T)
uvm_transport_export #(REQ,RSP)
uvm_nonblocking_transport_export #(REQ,RSP)
uvm_master_export #(REQ,RSP)
uvm_blocking_master_export #(REQ,RSP)
uvm_nonblocking_master_export #(REQ,RSP)
uvm_slave_export #(REQ,RSP)
uvm_blocking_slave_export #(REQ,RSP)
uvm_nonblocking_slave_export #(REQ,RSP)
uvm_put_imp #(T,IMP)
uvm_blocking_put_imp #(T,IMP)
uvm_nonblocking_put_imp #(T,IMP)
uvm_get_imp #(T,IMP)
uvm_blocking_get_imp #(T,IMP)
uvm_nonblocking_get_imp #(T,IMP)
uvm_peek_imp #(T,IMP)
uvm_blocking_peek_imp #(T,IMP)
uvm_nonblocking_peek_imp #(T,IMP)
uvm_get_peek_imp #(T,IMP)
uvm_blocking_get_peek_imp #(T,IMP)
uvm_nonblocking_get_peek_imp #(T,IMP)
uvm_analysis_imp #(T,IMP)
uvm_transport_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_blocking_transport_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_nonblocking_transport_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_master_imp #(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_blocking_master_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_nonblocking_master_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_slave_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_blocking_slave_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
uvm_nonblocking_slave_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
Search ✔
class subscriber extends uvm_subscriber#(instruction);
function new(string name, uvm_component p = null);
super.new(name,p);
endfunction
function void write(instruction t);
`uvm_info(get_full_name(),
endclass : subscriber
module test;
env e;
initial begin
e = new();
run_test();
end
endmodule
uvm_tlm_3.tar
Browse the code in uvm_tlm_3.tar
From the below log, you see that transaction is sent to both the components cov and
sb.
Log
Tlm Fifo
Methods
function new(string name,
uvm_component parent = null,
int size = 1)
The size indicates the maximum size of the FIFO; a value of zero indicates no upper
bound.
virtual function int size()
Returns the capacity of the FIFO. 0 indicates the FIFO capacity has no limit.
virtual function int used()
virtual function bit is_empty()
virtual function bit is_full()
Returns 1 when the number of entries in the FIFO is equal to its size, 0 otherwise.
virtual function void flush()
Removes all entries from the FIFO, after which used returns 0 and is_empty returns 1.
Example
class producer extends uvm_component;
uvm_blocking_put_port#(int) put_port;
function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);
endfunction
task run;
int randval;
for(int i = 0; i < 10; i++)
begin
#10;
uvm_tlm_4.tar
Browse the code in uvm_tlm_4.tar
Log
Search ✔
2)Define required callback methods. All the callback methods must be virtual.
OpenVera In this example, we will create callback methods which will be called before driving
Constructs the packet and after driving the packet to DUT.
Switch TB
virtual task pre_send(); endtask
RVM Switch TB virtual task post_send(); endtask
RVM Ethernet sample
3)Define the constructor and get_type_name methods and define type_name.
function new (string name = "Driver_callback");
Specman E super.new(name);
Interview Questions endfunction
static string type_name = "Driver_callback";
virtual function string get_type_name();
return type_name;
endfunction
Step 2) Register the facade class with driver and call the callback methods.
1)In the driver class, using `uvm_register_cb() macro, register the facade class.
class Driver extends uvm_component;
`uvm_component_utils(Driver)
`uvm_register_cb(Driver,Driver_callback)
function new (string name, uvm_component parent=null);
super.new(name,parent);
endfunction
endclass
Place the above macros before and after driving the packet.
virtual task run();
repeat(2) begin
`uvm_do_callbacks(Driver,Driver_callback,pre_send())
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`uvm_do_callbacks(Driver,Driver_callback,post_send())
end
endtask
function new (string name = "Driver_callback");
super.new(name);
endfunction
static string type_name = "Driver_callback";
virtual function string get_type_name();
return type_name;
endfunction
virtual task pre_send(); endtask
virtual task post_send(); endtask
endclass : Driver_callback
class Driver extends uvm_component;
`uvm_component_utils(Driver)
`uvm_register_cb(Driver,Driver_callback)
function new (string name, uvm_component parent=null);
super.new(name,parent);
endfunction
virtual task run();
repeat(2) begin
`uvm_do_callbacks(Driver,Driver_callback,pre_send())
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`uvm_do_callbacks(Driver,Driver_callback,post_send())
end
endtask
endclass
Let's run the driver in simple testcase. In this testcase, we are not changing any
callback methods definitions.
module test;
Driver drvr;
initial begin
drvr = new("drvr");
run_test();
end
endmodule
Download files
uvm_callback_1.tar
Browse the code in uvm_callback_1.tar
Log report
1) Implement the user defined callback method by extending facade class of the
driver class.
We will delay the driving of packet be 20 time units using the pre_send() call back
method.
class Custom_Driver_callbacks_1 extends Driver_callback;
function new (string name = "Driver_callback");
super.new(name);
endfunction
virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units.
%d",$time);
#20;
endtask
virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask
endclass
3) Register the callback method with the driver component. uvm_callback class has
static method add() which is used to register the callback.
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
function new (string name = "Driver_callback");
super.new(name);
endfunction
virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units.
%d",$time);
#20;
endtask
virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask
endclass
module test;
initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
drvr = new("drvr");
cb_1 = new("cb_1");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end
endmodule
uvm_callback_2.tar
Browse the code in uvm_callback_2.tar
Simulation Command
Run the testcase. See the log results; We delayed the driving of packet by 20 time
units using callback mechanism. See the difference between the previous testcase log
and this log.
Log report
cb_1 on drvr ON
UVM_INFO @ 0: reporter [RNTST] Running test ...
CB_1:pre_send: Delaying the packet driving by 20 time units. 0
Driver: Started Driving the packet ...... 20
Driver: Finished Driving the packet ...... 60
CB_1:post_send: Just a message from post send callback method
class Custom_Driver_callbacks_2 extends Driver_callback;
function new (string name = "Driver_callback");
super.new(name);
endfunction
virtual task pre_send();
$display("CB_2:pre_send: Hai .... this is from Second callback %d",$time);
endtask
endclass
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
function new (string name = "Driver_callback");
super.new(name);
endfunction
virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units.
%d",$time);
#20;
endtask
virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask
endclass
class Custom_Driver_callbacks_2 extends Driver_callback;
function new (string name = "Driver_callback");
super.new(name);
endfunction
virtual task pre_send();
$display("CB_2:pre_send: Hai .... this is from Second callback %d",$time);
endtask
endclass
module test;
initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
Custom_Driver_callbacks_2 cb_2;
drvr = new("drvr");
cb_1 = new("cb_1");
cb_2 = new("cb_2");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end
endmodule
uvm_callback_3.tar
Browse the code in uvm_callback_3.tar
Log report
The log results show that pre_send() method of CDc_1 is called first and then
pre_send() method of Cdc_2. This is because of the order of the registering callbacks.
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
Now we will see how to change the order of the callback method calls.
By changing the sequence of calls to add() method, order of callback method calling
can be changed.
initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
Custom_Driver_callbacks_2 cb_2;
drvr = new("drvr");
cb_1 = new("cb_1");
cb_2 = new("cb_2");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end
endmodule
uvm_callback_4.tar
Browse the code in uvm_callback_4.tar
Methods:
add_by_name:
static function void add_by_name(string name,
uvm_callback cb,
uvm_component root,
uvm_apprepend ordering = UVM_APPEND)
delete:
static function void delete_by_name(string name,
uvm_callback cb,
uvm_component root )
Macros:
`uvm_register_cb
Registers the given CB callback type with the given T object type.
`uvm_set_super_type
`uvm_do_callbacks
Calls the given METHOD of all callbacks of type CB registered with the calling object
`uvm_do_obj_callbacks
Calls the given METHOD of all callbacks based on type CB registered with the given
object, OBJ, which is or is based on type T.
`uvm_do_callbacks_exit_on
Calls the given METHOD of all callbacks of type CB registered with the calling object
`uvm_do_obj_callbacks_exit_on
Calls the given METHOD of all callbacks of type CB registered with the given object
OBJ, which must be or be based on type T, and returns upon the first callback that
returns the bit value given by VAL.
Search ✔
Specman E
Interview Questions
The VMM Standard Library provides base classes for key aspects of the verification
environment, transaction generation, notification service and a message logging
service.
vmm_env :
The class is a base class used to implement verification environments.
vmm_xactor :
This base class is to be used as the basis for all transactors, including bus-functional
models, monitors and generators. It provides a standard control mechanism expected
to be found in all transactors.
vmm_channel :
This class implements a generic transaction-level interface mechanism. Transaction-
level interfaces remove the higher-level layers from the physical interface details.
Using channels, transactors pass transactions from one to other.
vmm_data :
This base class is to be used as the basis for all transaction descriptors and data
models. It provides a standard set of methods expected to be found in all descriptors.
User must extend vmm_data to create a custom transaction.
vmm_log :
The vmm_log class used implements an interface to the message service. These
classes provide a mechanism for reporting simulation activity to a file or a terminal.
To ensure a consistent look and feel to the messages issued from different sources,
vmm_log is used.
vmm_atomic_gen :
This is a macro. This macro defines a atomic generator for generating transaction
which are derived from vmm_data.
vmm_scenario_gen :
Defines a scenario generator class to generate sequences of related instances of the
specified class.
vmm_notify :
The vmm_notify class implements an interface to the notification service. The
notification service provides a synchronization mechanism for concurrent threads or
transactors.
vmm_test :
This class will be useful for runtime selection of testcases to run on an environment.
Search ✔
OpenVera
Message Severity
Constructs
Switch TB Individual messages are categorized into different severities
RVM Switch TB
FATAL_SEV : An error which causes a program to abort.
RVM Ethernet sample ERROR_SEV : Simulation aborts after a certain number of errors are observed.
WARNING_SEV: Simulation can proceed and still produce useful result.
NORMAL_SEV : This message indicates the state of simulation.
Specman E TRACE_SEV : This message identifies high-level internal information that is not
Interview Questions normally issued.
DEBUG_SEV : This message identifies medium-level internal information that is not
normally issued.
VERBOSE_SEV: This message identifies low-level internal information that is not
normally issued.
We can use the following predefined macros to select the message severity.
`vmm_fatal(vmm_log log, string msg);
`vmm_error(vmm_log log, string msg);
`vmm_warning(vmm_log log, string msg);
`vmm_note(vmm_log log, string msg);
`vmm_trace(vmm_log log, string msg);
`vmm_debug(vmm_log log, string msg);
`vmm_verbose(vmm_log log, string msg);
The second argument in the above macro can accept only a string. So if we want to
pass a complex message, then convert it to string using a $psprintf() system task.
These macros are simple to use and the macro expansion is easy to understand.
Following is a expansion of `vmm_not macro. Other macros also have same logic with
different Message severity levels.
`define vmm_note ( log, msg )
do
if (log.start_msg(vmm_log::NOTE_TYP)) begin
void'(log.text(msg));
log.end_msg();
end
while (0)
To change the severity and verbosity of the messages services at simulation time , use
+vmm_log_default=SEVERITY TYPE. Where SEVERITY TYPE can be ERROR, WARNING,
NORMAL, TRACE, DEBUG OR VERBOSE. We will see the demo of this service in the
example.
Message Handling
Different messages require different action by the simulator once the message has
been issued.
To use this vmm feature, take the instance of vmm_log and use the message macros.
For most of the vmm classes like vmm_env,vmm_xactor,vmm_data etc, this
instantiation is already done internally, so user dont need to take a separate instance
of vmm_log.
program test_log();
initial begin
endprogram
vmm_log.tar
Browse the code in vmm_log.tar
Simulation commands
vcs -sverilog -f filelist -R -ntb_opts rvm -ntb_opts dtm
You can see the following messages on the terminal. You can only see Normal, Error,
warning and fatal messages.
Some time we need to count the number of messages executed based of the severity
type. vmm_log has get_message_count() function which returns the message count
based on severity type, source and message string.
user dont need to implement a logic to print the state of test i.e TEST PASSED or TEST
FAILED, vmm_env has already implemented this in the report() method. We will see
this in next topic.
virtual function int get_message_count(int severity = ALL_SEVS,
string name = "",
string instance = "",
bit recurse = 0);
program test_log();
initial begin
`vmm_note(log,$psprintf("This is a NOTE Message at time %d",$time));
`vmm_error(log,"This is a ERROR Message 1 ");
`vmm_error(log,"This is a ERROR Message 2 ");
`vmm_error(log,"This is a ERROR Message 3 ");
`vmm_warning(log,"This is a WARNING Message 1 ");
`vmm_warning(log,"This is a WARNING Message 2 ");
fatal_cnt = log.get_message_count(vmm_log::FATAL_SEV, "/./", "/./", 1);
error_cnt = log.get_message_count(vmm_log::ERROR_SEV, "/./", "/./", 1);
warn_cnt = log.get_message_count(vmm_log::WARNING_SEV, "/./", "/./", 1);
$display("\n\n");
$display(" Number of Fatal messages : %0d ",fatal_cnt);
$display(" Number of Error messages : %0d ",error_cnt);
$display(" Number of Warning messages : %0d ",warn_cnt);
$display("\n\n");
end
endprogram
vmm_log_1.tar
Browse the code in vmm_log_1.tar
Simulation commands
vcs -sverilog -f filelist -R -ntb_opts rvm -ntb_opts dtm
Sometimes we would like to wait for a specific message and execute some logic. For
example, you want to count number of crc error packets transmitted by dut in some
special testcase or you want to stop the simulation after a specific series of messages
are received. vmm_log has a method to wait for a specific message.
virtual task wait_for_msg(string name = "",
string instance = "",
bit recurse = 0,
int typs = ALL_TYPS,
int severity = ALL_SEVS,
string text = "",
logic issued = 1'bx,
ref vmm_log_msg msg);
Following is a simple example which demonstrates the use of above method. In this
example, wait_for_msg() method wait for a specific string.
program test_log();
initial
forever begin
log.wait_for_msg("/./","/./",-1,vmm_log::ALL_TYPS,vmm_log::ERROR_SEV,"Packet
with CRC ERROR is received",1'bx,msg);
// You can count number of crc errored pkts rcvd.
// or do whatever you want.
$display(" -- Rcvd CRC ERROR message at %d --",$time);
end
endprogram
vmm_log_2.tar
Browse the code in vmm_log_2.tar
Simulation commands
vcs -sverilog -f filelist -R -ntb_opts rvm -ntb_opts dtm
Search ✔
stop() :
Stops all the components of the verification environment to terminate the simulation
OpenVera cleanly. Stop data generators.
Constructs
Switch TB cleanup() :
Performs clean-up operations to let the simulation terminate gracefully. It waits for
RVM Switch TB DUT to drain all the data it has.
RVM Ethernet sample
report() :
The report method in vmm_env collects error and warning metrics from all the log
objects and reports a summary of the results.
Specman E
Interview Questions To create a user environment, define a new class extended from vmm_env and extend
the above methods. To retain the core functionality of the base class methods, each
extended method must call super. as the first line of code.
In The following example, we are defining a new class Custom_env from vmm_env and
extending all the vmm_env class methods. All the methods are extended and
`vmm_note() message is included to understand the simulation flow.
class Custom_env extends vmm_env;
function new();
super.new("Custom_env");
endfunction
virtual function void gen_cfg();
super.gen_cfg();
`vmm_note(this.log,"Start of gen_cfg() method ");
`vmm_note(this.log,"End of gen_cfg() method ");
endfunction
virtual function void build();
super.build();
`vmm_note(this.log,"Start of build() method ");
`vmm_note(this.log,"End of build() method ");
endfunction
virtual task reset_dut();
super.reset_dut();
`vmm_note(this.log,"Start of reset_dut() method ");
`vmm_note(this.log,"End of reset_dut() method ");
endtask
virtual task cfg_dut();
super.cfg_dut();
`vmm_note(this.log,"Start of cfg_dut() method ");
`vmm_note(this.log,"End of cfg_dut() method ");
endtask
virtual task start();
super.start();
`vmm_note(this.log,"Start of start() method ");
`vmm_note(this.log,"End of start() method ");
endtask
virtual task wait_for_end();
super.wait_for_end();
`vmm_note(this.log,"Start of wait_for_end() method ");
`vmm_note(this.log,"End of wait_for_end() method ");
endtask
virtual task stop();
super.stop();
`vmm_note(this.log,"Start of stop() method ");
`vmm_note(this.log,"End of stop() method ");
endtask
virtual task cleanup();
super.cleanup();
`vmm_note(this.log,"Start of cleanup() method ");
`vmm_note(this.log,"End of cleanup() method ");
endtask
virtual task report();
super.report();
`vmm_note(this.log,"Start of report() method \n\n\n");
`vmm_note(this.log,"End of report() method");
endtask
endclass
In addition to the methods that have already been discussed earlier, vmm_env also
contains a run() method which does not require any user extension. This method is
called from the testcase. When this method is called, individual steps in vmm_env are
called in a sequence in the following order:
gen_cfg => build => cfg_dut_t => start_t => wait_for_end_t => stop_t => cleanup_t =>
report
Now we will see the testcase implementation. VMM recommends the TestBench to be
implemented in program block. In a program block, create an object of the
Custom_env class and call the run() method.
program test();
endprogram
vmm_env_1.tar
Browse the code in vmm_env_1.tar
Simulation commands
vcs -sverilog -f filelist -R -ntb_opts rvm -ntb_opts dtm
Log file report shows that individual methods in vmm_env are called in a ordered
sequence upon calling run() method.
When you call build() and if gen_cfg() is not called before that, gen_cfg() will be
called first then build will execute.
Same way, if you call gen_cfg() followed by cfg_dut() followed by run(), then
cfg_dut() will make sure to call build() followed by reset_dut() first before executing
its user defined logic, run() will make sure to call start(), wait_for_end(), stop(),
clean(), report()in the order given.
program test();
endprogram
vmm_env_2.tar
Browse the code in vmm_env_2.tar
Simulation commands
vcs -sverilog -f filelist -R -ntb_opts rvm -ntb_opts dtm +vmm_log_default=VERBOSE
Search ✔
virtual function vmm_data copy(vmm_data to = null);
Packet cpy;
cpy = new;
super.copy_data(cpy);
cpy.da = this.da;
cpy.sa = this.sa;
cpy.length = this.length;
...........
Compare method compares the current value of the object instance with the current
value of the specified object instance.
virtual function bit compare(input vmm_data to,output string diff,input int
kind = -1);
Packet cmp;
compare = 1; // Assume success by default.
diff = "No differences found";
// data types are the same, do comparison:
if (this.da != cmp.da)
begin
diff = $psprintf("Different DA values: %b != %b", this.da, cmp.da);
compare = 0;
end
if (this.sa != cmp.sa)
begin
diff = $psprintf("Different SA values: %b != %b", this.sa, cmp.sa);
compare = 0;
end
........
........
byte_pack() method Packs the content of the transaction or data into the specified
dynamic array of bytes.
virtual function int unsigned byte_pack(
ref logic [7:0] bytes[],
input int unsigned offset =0 ,
input int kind = -1);
byte_pack = 0;
bytes = new[this.data.size() + 4];
bytes[0] = this.da;
bytes[1] = this.sa;
bytes[2] = this.length;
........
........
virtual function int unsigned byte_unpack(
const ref logic [7:0] bytes[],
input int unsigned offset = 0,
input int len = -1,
input int kind = -1);
this.da = bytes[0];
this.sa = bytes[1];
this.length = bytes[2];
.........
.........
class Packet extends vmm_data;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 6]};}
function new();
super.new(this.log);
endfunction:new
virtual function vmm_data allocate();
Packet pkt;
pkt = new();
return pkt;
endfunction:allocate
virtual function string psdisplay(string prefix = "");
int i;
$write(psdisplay, " %s packet
#%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.data_id);
$write(psdisplay, " %s%s da:0x%h\n", psdisplay, prefix,this.da);
$write(psdisplay, " %s%s sa:0x%h\n", psdisplay, prefix,this.sa);
$write(psdisplay, " %s%s length:0x%h
(data.size=%0d)\n", psdisplay, prefix,this.length,this.data.size());
$write(psdisplay, " %s%s data[%0d]:0x%h", psdisplay, prefix,0,data[0]);
if(data.size() > 1)
$write(psdisplay, " data[%0d]:0x%h", 1,data[1]);
if(data.size() > 4)
$write(psdisplay, " .... ");
if(data.size() > 2)
$write(psdisplay, " data[%0d]:0x%h", data.size() -2,data[data.size() -2]);
if(data.size() > 3)
$write(psdisplay, " data[%0d]:0x%h", data.size() -1,data[data.size() -1]);
$write(psdisplay, "\n %s%s fcs:0x%h \n", psdisplay, prefix, this.fcs);
endfunction
virtual function vmm_data copy(vmm_data to = null);
Packet cpy;
// Copying to a new instance?
if (to == null)
cpy = new;
else
// Copying to an existing instance. Correct type?
if (!$cast(cpy, to))
begin
`vmm_fatal(this.log, "Attempting to copy to a non packet instance");
copy = null;
return copy;
end
super.copy_data(cpy);
cpy.da = this.da;
cpy.sa = this.sa;
cpy.length = this.length;
cpy.data = new[this.data.size()];
foreach(data[i])
begin
cpy.data[i] = this.data[i];
end
cpy.fcs = this.fcs;
copy = cpy;
endfunction:copy
virtual function bit compare(input vmm_data to,output string diff,input int kind
= -1);
Packet cmp;
compare = 1; // Assume success by default.
diff = "No differences found";
if (!$cast(cmp, to))
begin
`vmm_fatal(this.log, "Attempting to compare to a non packet instance");
compare = 0;
diff = "Cannot compare non packets";
return compare;
end
// data types are the same, do comparison:
if (this.da != cmp.da)
begin
diff = $psprintf("Different DA values: %b != %b", this.da, cmp.da);
compare = 0;
return compare;
end
if (this.sa != cmp.sa)
begin
diff = $psprintf("Different SA values: %b != %b", this.sa, cmp.sa);
compare = 0;
return compare;
end
if (this.length != cmp.length)
begin
diff = $psprintf("Different LEN values: %b != %b", this.length, cmp.length);
compare = 0;
return compare;
end
foreach(data[i])
if (this.data[i] != cmp.data[i])
begin
diff = $psprintf("Different data[%0d] values: 0x%h !=
0x%h",i, this.data[i], cmp.data[i]);
compare = 0;
return compare;
end
if (this.fcs != cmp.fcs)
begin
diff = $psprintf("Different FCS values: %b != %b", this.fcs, cmp.fcs);
compare = 0;
return compare;
end
endfunction:compare
virtual function int unsigned byte_pack(
ref logic [7:0] bytes[],
input int unsigned offset =0 ,
input int kind = -1);
byte_pack = 0;
bytes = new[this.data.size() + 4];
bytes[0] = this.da;
bytes[1] = this.sa;
bytes[2] = this.length;
foreach(data[i])
bytes[3+i] = data[i];
bytes[this.data.size() + 3 ] = fcs;
byte_pack = this.data.size() + 4;
endfunction:byte_pack
virtual function int unsigned byte_unpack(
const ref logic [7:0] bytes[],
input int unsigned offset = 0,
input int len = -1,
input int kind = -1);
this.da = bytes[0];
this.sa = bytes[1];
this.length = bytes[2];
this.fcs = bytes[bytes.size() -1];
this.data = new[bytes.size() - 4];
foreach(data[i])
this.data[i] = bytes[i+3];
return bytes.size();
endfunction:byte_unpack
endclass
Vmm_data Methods
virtual function string psdisplay ( string prefix = "" );
virtual function bit is_valid ( bit silent = 1, int kind = -1 );
virtual function vmm_data allocate ( );
virtual function vmm_data copy ( vmm_data to = null );
virtual function bit compare (
input vmm_data to, output string diff, input int kind = -1 );
function void display(string prefix = "");
virtual protected function void copy_data ( vmm_data to );
virtual function int unsigned byte_pack (
ref logic [7:0] bytes [ ], int unsigned offset = 0, int kind = -1 );
virtual function int unsigned byte_unpack (
const ref logic [7:0] bytes [ ], input int unsigned offset = 0,
input int len = -1, input int kind = -1 );
virtual function int unsigned byte_size ( int kind = -1 );
virtual function int unsigned max_byte_size ( int kind = -1 );
virtual function void save ( int file );
virtual function bit load ( int file );
Search ✔
Verilog Channels are similar to SystemVerilog mailboxes with advanced features. Vmm
Channels provides much richer feature functionality than a SV mailbox. vmm channels
Verification
are superset of mailboxs.
Verilog Switch TB Some of the the benefits of channels over mailboxes:
Basic Constructs Dynamic reconfiguration
Inbuilt notifications
Strict type checking
OpenVera Out of order usage
Constructs task tee() for easy scoreboarding
Record and playback
Switch TB task sneak() for monitors
RVM Switch TB
RVM Ethernet sample
Using `vmm_channel() macro , channels can be created.
`vmm_channel(Custom_vmm_data)
Specman E
The above macro creates a channel Custom_vmm_data_channel . There are various
Interview Questions
methods to access the channels.
We will create a channel for vmm_data for this example. Users can create a channel
for any transaction which is derived from the vmm_data class. You can try this
example by creating channel for Packet class which is discussed in previous section.
`vmm_channel(vmm_data)
p_c.put(p_put);
p_c.get(p_put);
Complete Example
`vmm_channel(vmm_data)
program test_channel();
vmm_data p_put,p_get;
int i;
initial
repeat(10)
begin
#( $urandom()%10);
p_put = new(null);
p_put.stream_id = i++;
$display(" Pushed a packet in to channel with id %d",p_put.stream_id);
p_c.put(p_put); // Pushing a transaction in to channel
end
initial
forever
begin
p_c.get(p_get); // popping a transaction from channel.
$display(" Popped a packet from channel with id %d",p_get.stream_id);
end
endprogram
vmm_channel.tar
Browse the code in vmm_channel.tar
function new ( string name, string instance,
int unsigned full = 1, int unsigned empty = 0, bit fill_as_bytes = 0 );
function void reconfigure (int full = -1, int empty = -1, logic fill_as_bytes = 1'bx );
function int unsigned full_level ( );
function int unsigned empty_level ( );
function int unsigned level ( );
function int unsigned size ( );
function bit is_full ( );
function void flush ( );
function void sink ( );
function void flow ( );
function void lock ( bit [1:0] who );
function void unlock ( bit [1:0] who );
function bit is_locked ( bit [1:0] who );
task put ( class_name obj, int offset = -1 );
function void sneak ( class_name obj, int offset = -1 );
function class_name unput ( int offset = -1 );
task get ( output class_name obj, input int offset = 0 );
task peek ( output class_name obj, input int offset = 0 );
task activate ( output class_name obj, input int offset = 0 );
function class_name active_slot ( );
function class_name start ( );
function class_name complete ( vmm_data status = null );
function class_name remove ( );
function active_status_e status ( );
task tee ( output class_name obj );
function bit tee_mode ( bit is_on );
function void connect ( vmm_channel downstream );
function class_name for_each ( bit reset = 0 );
function int unsigned for_each_offset ( );
function bit record ( string filename );
task bit playback ( output bit success, input string filename,
input vmm_data loader, input bit metered = 0 );
Search ✔
To use <class_name>_atomic_gen class, a <class_name>_channel must exist.
Verilog <class_name>_atomic_gen generates transactions and pushes it to
Verification <class_name>_channel. A <class_name>_channel object can be passed to generator
Verilog Switch TB while constructing.
2) define `vmm_channel for the packet class. This macro creates a packet_channel
which will be used by the packet_atomic_gen to store the transactions. Any other
component can take the transactions from this channel.
`vmm_channel(packet)
pkt_gen.stop_after_n_insts = 4;
pkt_gen.start_xator();
6) Collect the packets from the pkt_chan and display the packet content to terminal.
pkt_gen.out_chan.get(pkt);
pkt.display();
Completed Example
`vmm_channel(Packet)
`vmm_atomic_gen(Packet,"Atomic Packet Generator")
program test_atomic_gen();
Packet_atomic_gen pkt_gen = new("Atomic Gen","test");
Packet pkt;
initial
begin
pkt_gen.stop_after_n_insts = 4;
#100; pkt_gen.start_xactor();
end
initial
#200 forever
begin
pkt_gen.out_chan.get(pkt);
pkt.display();
end
endprogram
vmm_atomic_gen.tar
Browse the code in vmm_atomic_gen.tar
packet #1952805748.0.0
da:0xdb
sa:0x71
length:0x0e (data.size=1)
data[0]:0x63
fcs:0xe9
packet #1952805748.0.1
da:0xa7
sa:0x45
length:0xa4 (data.size=5)
data[0]:0x00 data[1]:0x4f .... data[3]:0xe7 data[4]:0xd8
fcs:0x31
packet #1952805748.0.2
da:0x15
sa:0xe6
length:0xa1 (data.size=1)
data[0]:0x80
fcs:0x01
packet #1952805748.0.3
da:0xd7
sa:0xa9
length:0xdc (data.size=3)
data[0]:0xcc data[1]:0x7c data[1]:0x7c
fcs:0x67
Search ✔
class Driver extends vmm_xactor;
Verilog
Verification 2) Define constructor. In this example, we don't have any interfaces of channels, we
Verilog Switch TB will not implement them.
Call the super.new() method.
Basic Constructs
function new();
super.new("Driver Transactor", "inst", 0);
OpenVera endfunction: new
Constructs
3) Define main() method.
Switch TB
RVM Switch TB First call the super.main() method.
Then define the activity which you want to do.
RVM Ethernet sample
task main();
super.main();
Specman E
forever begin
Interview Questions #100;
$display(" Driver : %d",$time);
end
endtask: main
Now we will see how to use the above defined Custom_xtor class.
1) Create a object of Custom_xtor.
#100 drvr.start_xactor();
#1000 drvr.stop_xactor();
class Driver extends vmm_xactor;
function new();
super.new("Driver Transactor", "inst", 0);
endfunction: new
task main();
super.main();
forever begin
#100;
$display(" Driver : %d",$time);
end
endtask: main
endclass:Driver
program test();
vmm_xactor.tar
Browse the code in vmm_xactor.tar
Driver : 200
Driver : 300
Driver : 400
Driver : 500
Driver : 600
Driver : 700
Driver : 800
Driver : 900
Driver : 1000
$finish at simulation time 1000
Vmm_xactor Members
function new ( string name, string instance, int stream_id = -1 );
virtual function string get_name ( );
virtual function string get_instance ( );
vmm_log log;
int stream_id;
virtual function void prepend_callback ( vmm_xactor_callbacks cb );
virtual function void append_callback ( vmm_xactor_callbacks cb );
virtual function void unregister_callback ( vmm_xactor_callbacks cb );
vmm_notify notify;
// Enumeration values for the state of the transactor:
enum { XACTOR_IDLE, XACTOR_BUSY,
XACTOR_STARTED, XACTOR_STOPPED, XACTOR_RESET };
virtual function void start_xactor ( );
virtual function void stop_xactor ( );
virtual function void reset_xactor ( reset_e rst_typ = SOFT_RST );
protected task wait_if_stopped ( );
protected task wait_if_stopped_or_empty ( vmm_channel chan );
protected virtual task main ( );
virtual function void save_rng_state ( );
virtual function void restore_rng_state ( );
virtual function void xactor_status ( string prefix = "" );
// Macro to simplify the calling of callback methods:
`vmm_callback ( callback_class_name, method ( args ) )
Search ✔
virtual task pre_send(); endtask
OpenVera virtual task post_send(); endtask
Constructs
Switch TB endclass
RVM Switch TB 2) Calling callback method.
RVM Ethernet sample Inside the transactor, callback methods should be called whenever something
interesting happens.
We will call the callback method before driving the packet and after driving the
packet. We defined 2 methods in facade class. We will call pre_send() method before
Specman E sending the packet and post_send() method after sending the packet.
Interview Questions
Using a `vmm_callback(,) macro, callback methods are called.
There are 2 argumentd to `vmm_callback(,) macro.
First argument must be the facade class.
Second argument must be the callback method in the facade class.
To call pre_send() method , use macro
`vmm_callback(Driver_callbacks,pre_send());
and simillary to call post_send() method,
`vmm_callback(Driver_callbacks,post_send());
Place the above macros before and after driving the packet.
virtual task main();
super.main();
forever begin
`vmm_callback(Driver_callbacks,pre_send());
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`vmm_callback(Driver_callbacks,post_send());
end
endtask
virtual task pre_send(); endtask
virtual task post_send(); endtask
endclass
class Driver extends vmm_xactor;
function new();
super.new("Driver","class");
endfunction
virtual task main();
super.main();
forever begin
`vmm_callback(Driver_callbacks,pre_send());
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`vmm_callback(Driver_callbacks,post_send());
end
endtask
endclass
Let's run the driver in simple testcase. In this testcase, we are not changing any
callback methods definitions.
program testing_callbacks();
Driver drvr = new();
initial
begin
#100 drvr.start_xactor();
#200 drvr.stop_xactor();
end
endprogram
Download files
vmm_callback.tar
Browse the code in vmm_callback.tar
Log report
1) Implement the user defined callback method by extending facade class of the
driver class.
We will delay the driving of packet be 20 time units using the pre_send() call back
method.
We will just print a message from post_send() callback method.
drvr.append_callback(CDc_1);
program testing_callbacks();
Driver drvr = new();
class Custom_Driver_callbacks_1 extends Driver_callbacks;
virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units.
%d",$time);
#20;
endtask
virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask
endclass
vmm_callback_1.tar
Browse the code in vmm_callback_1.tar
Simulation Command
vcs -sverilog -f filelist -R -ntb_opts rvm -ntb_opts dtm
Run the testcase. See the log results; We delayed the driving of packet by 20 time
units using callback mechanism. See the difference between the previous testcase log
and this log.
Log report
drvr.append_callback(CDc_2);
class Custom_Driver_callbacks_1 extends Driver_callbacks;
virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units.
%d",$time);
#20;
endtask
virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask
endclass
class Custom_Driver_callbacks_2 extends Driver_callbacks;
virtual task pre_send();
$display("CB_2:pre_send: Hai .... this is from Second callback %d",$time);
endtask
endclass
vmm_callback_2.tar
Browse the code in vmm_callback_2.tar
Log report
The log results show that pre_send() method of CDc_1 is called first and then
pre_send() method of Cdc_2. This is beacuse of the order of the registering callbacks.
drvr.append_callback(CDc_1);
drvr.append_callback(CDc_2);
Now we will see how to change the order of the callback method calls.
Use prepend_callback() method for registering instead of append_callback() method.
program testing_callbacks();
Driver drvr = new();
class Custom_Driver_callbacks_1 extends Driver_callbacks;
virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units.
%d",$time);
#20;
endtask
virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask
endclass
class Custom_Driver_callbacks_2 extends Driver_callbacks;
virtual task pre_send();
$display("CB_2:pre_send: Hai .... this is from Second callback %d",$time);
endtask
endclass
vmm_callback_3.tar
Browse the code in vmm_callback_3.tar
Vmm also provides method to remove the callback methods which are registered.
Search ✔
The declarative part( like new constrained transacting definition) is defined outside
Verilog these macros.
Verification
Verilog Switch TB Writing A Testcase
Basic Constructs
Let us see an example of writing a testcase.
Inside the testcase, we will define a new transaction and pass this transaction to the
atomic generator.
OpenVera
Constructs
Switch TB Declarative part:
RVM Switch TB 1) Define all the declarative code.
RVM Ethernet sample
class constrained_tran extends pcie_transaction;
// Add some constraints
Specman E // Change some method definitions
Interview Questions
end class
constrained_tran c_tran_obj;
Procedural part:
The first argument is the name of the testcase class and will also be used as the name
of the testcase in the global testcase registry.
The second argument is the name of the environment class that will be used to
execute the testcase. A data member of that type named "env" will be defined and
assigned, ready to be used.
`vmm_test_begin(test_1,vmm_env,"Test_1")
In this testcase, we want to pass the c_tran_obj object. The steps t pass the
c_tran_obj as per the vmm_env is
env.build();
c_tran_obj = new(" ");
env.atomic_gen.randomized_obj = c_tran_obj;
env.run();
Now use `vmm_test_end to define the end of the testcase. The argument to this is
the testcase name.
`vmm_test_end(test_1)
end class
constrained_tran c_tran_obj
`vmm_test_begin(test_1,vmm_env,"Test_1")
$display(" Start of Testcase : Test_1 ");
env.build();
c_tran_obj = new(" ");
env.atomic_gen.randomized_obj = c_tran_obj;
env.run();
$display(" End of Testcase : Test_1 ");
`vmm_test_end(test_1)
Like this you can write many testcases in separate file or single file.
Now we will implement 3 simple testcases and a main testcase which will be used for
selecting any one of the 3 testcases.
testcase_1
// Define all the declarative code hear. I done have anything to show you.
//
// class constrained_tran extends pcie_transaction;
//
// end class
//
// constrained_tran c_tran_obj
`vmm_test_begin(test_1,vmm_env,"Test_1")
$display(" Start of Testcase : Test_1 ");
// This is procedural part. You can call build method.
env.build();
// You can pass the above created transaction to atomic gen.
// c_tran_obj = new(" ");
// env.atomic_gen.randomized_obj = c_tran_obj;
//
//
env.run();
$display(" End of Testcase : Test_1 ");
`vmm_test_end(test_1)
testcase_2
`vmm_test_begin(test_2,vmm_env,"Test_2")
$display(" Start of Testcase : Test_2 ");
// Do something like this ....
env.build();
// like this ....
env.run();
$display(" End of Testcase : Test_2 ");
`vmm_test_end(test_2)
testcase_3
`vmm_test_begin(test_3,vmm_env,"Test_3")
$display(" Start of Testcase : Test_3 ");
// Do something like this ....
env.build();
// like this ....
env.run();
$display(" End of Testcase : Test_3 ");
`vmm_test_end(test_3)
main testcase
Now we will write the main testcase. This doesn't have any test scenario, it is only
used for handling the above 3 testcases.
1) First include all the above testcases inside the program block.
`include "testcase_1.sv"
`include "testcase_2.sv"
`include "testcase_3.sv"
As I dont have a custom env class to show, I used vmm_env. You can use your custom
defined env.
3) In the initial block call the run() method of vmm_test_registry class and pass the
above env object as argument. This run method of vmm_test_registry is a static
method, so there is no need to create an object of this class.
vmm_test_registry::run(env);
`include "vmm.sv"
program main();
`include "testcase_1.sv"
`include "testcase_2.sv"
`include "testcase_3.sv"
vmm_env env;
initial
begin
$display(" START OF TEST CASE ");
env = new();
vmm_test_registry::run(env);
$display(" START OF TEST CASE ");
end
endprogram
LOG
LOG
LOG
You can also call the Default testcase, which just calls the env::run()
./simv +vmm_test=Default
LOG
Download the source code
vmm_test.tar
Browse the code in vmm_test.tar
Command to compile
./simv
./simv +vmm_test=Default
./simv +vmm_test=test_1
./simv +vmm_test=test_2
./simv +vmm_test=test_3
Search ✔
function bit record(string filename);
Specman E
Interview Questions The vmm_data::save() method must be implemented for recording. All the
transaction which are added to channel using the vmm_channel::put() method are
recorded and are avilabe for playback. A null filename stops the recording process.
vmm_channel::record() method returns TRUE if the specified file was successfully
opened.
Playing Back
method.
task playback(output bit success,
input string filename,
input vmm_data factory,
input bit metered = 0,
input vmm_scenario grabber = null);
This method will block the sources of the current channel like vmm_channl::put()
method till the playback is completed. The vmm_data::load() method must be
implemented for playback. The order of the transaction will be same as the order
while recording. If the metered argument is TRUE, the transaction descriptors are
added to the channel with the same relative time interval as they were originally put
in when the file was recorded.
The success argument is set to TRUE if the playback was successful. If the playback
process encounters an error condition such as a NULL (empty string) filename, a
corrupt file or an empty file, then success is set to FALSE.
EXAMPLE
Let us write an example to see how the record and playback works.
Record & Playback of channels can be used with atomic generator and scenario
generators. Here is a simple transaction with its channel and atomic generator. We
will use this atomic generator to generate transaction. The atomic generator has
out_chan channel, this channel is used send the generated transaction. We will record
and playback the transaction in the out_chan. I used Vmm_data macros for
implementing all the required methods.
class trans extends vmm_data;
typedef enum bit {BAD_FCS=1'b0, GOOD_FCS=1'b1} kind_e;
rand bit [47:0] DA;
rand bit [47:0] SA;
rand int length;
rand kind_e kind;
`vmm_data_member_begin(trans)
`vmm_data_member_scalar(DA, DO_ALL)
`vmm_data_member_scalar(SA, DO_ALL)
`vmm_data_member_scalar(length, DO_ALL)
`vmm_data_member_enum(kind, DO_ALL)
`vmm_data_member_end(trans)
endclass
// for declaring trans_channel
`vmm_channel(trans)
// for declaring trans_atomic_gen
`vmm_atomic_gen(trans, "Gen")
Now we will write a simple program to record and play back the above defined
transaction.
Use the trans_atomic_gen to generate the transactions. This also the put the
transactions in to out_chan channel. Call the start_xactor() method of the generator
to start the generator of transaction. Call the record() method of out_chan to record
the incoming transactions.
gen.stop_after_n_insts = 3;
gen.start_xactor();
gen.out_chan.record("Trans_recordes.tr");
To play back the recorded transactions, call the playback method. Then check if the
playback is fine.
tr = new();
gen.out_chan.playback(success,"Trans_recordes.tr",tr);
if(!success)
$display(" Failed to playback Trans_recordes.tr"); ]
Now we will write a logic which gets the transaction from the channel and prints the
content to terminal, so that we can observe the results.
The above the logic generates 3 transactions. Get the 3 transaction from the channel
and print the content.
initial
repeat(3)
begin
#10;
gen.out_chan.get(tr);
tr.display();
end
Log file
You can also see a file named "Trans_recordes.tr" in your simulation directory.
Log File
Look, the same transactions which were generated while RECORDING are played
back.
Search ✔
<class_name>_scenario_gen:
This class is the scenario generator which generates the transactions and sends out
using output channel. This class has a queue of scenario objects. Each scenario
contains transaction instances in an array.
<class_name>_scenario_gen_callbacks:
This class provides callback mechanism. There are two callback methods define.
pre_scenario_randomize() and post_scenario_gen() which are called at pre-
randomization of the scenario and post-generation of the scenario respectively.
Example
Following is the transaction class which we will use to write a scenario generator.
class instruction extends vmm_data;
vmm_log log;
typedef enum {LOAD__A,LOAD__B,ADD_A_B,SUB_A_B,STORE_C } kinds_e;
rand kinds_e inst;
function new();
super.new(this.log);
endfunction:new
virtual function string psdisplay(string prefix = "");
psdisplay = $psprintf(" Instruction : %s | stream_id : %0d | scenario_id : %0d
",inst.name(),stream_id,scenario_id);
endfunction:psdisplay
virtual function vmm_data allocate();
instruction tr = new;
allocate = tr;
endfunction:allocate
copy = to;
endfunction:copy
endclass
instruction_scenario_gen
instruction_scenario
instruction_atomic_scenario
instruction_scenario_election
instruction_scenario_gen_callbacks
class instruction_scenario_add_sub extends instruction_scenario;
int addition_scenario_id ;
Each scenario has more than one inductions. All these instructions are in a queue
"items" which is already defined in "instruction_scenario".
The rand varible "scenario_kind", which pre defined in the vmm_scenario class, will
randomly select one of the defined scenarios. "scenario_kind" varible has the id of the
current scenario. So we have to define the addition scenario, when the
"scenario_kind" value is addition_scenario_id.
constraint addition_scenario_items {
if($void(scenario_kind) == addition_scenario_id) {
length == 4;
d) The predefined variable "repeated" used to control if the VMM scenario generator
would run the scenario more than once each time it is created. We are not interested
in repeating so, constrain it to 0
repeated == 0;
foreach(items[i])
if(i == 0)
this.items[i].inst == instruction::LOAD__A;
else if(i == 1)
this.items[i].inst == instruction::LOAD__B;
else if(i == 2)
this.items[i].inst == instruction::ADD_A_B;
else if(i == 3)
this.items[i].inst == instruction::STORE_C;
int subtraction_scenario_id ;
constraint subtraction_scenario_items {
if($void(scenario_kind) == subtraction_scenario_id) {
length == 4;
repeated == 0;
foreach(items[i])
if(i == 0)
this.items[i].inst == instruction::LOAD__A;
else if(i == 1)
this.items[i].inst == instruction::LOAD__B;
else if(i == 2)
this.items[i].inst == instruction::SUB_A_B;
else if(i == 3)
this.items[i].inst == instruction::STORE_C;
function new();
this.addition_scenario_id = define_scenario(" ADDITION ",4);
this.subtraction_scenario_id = define_scenario(" SUBSTRACTION ",4);
endfunction
Scenario Code
class instruction_scenario_add_sub extends instruction_scenario;
///////////////////////////////////////////////////////////////
////// ADDITION SCENARIO //////////
///////////////////////////////////////////////////////////////
int addition_scenario_id ;
constraint addition_scenario_items {
if($void(scenario_kind) == addition_scenario_id) {
repeated == 0;
length == 4;
foreach(items[i])
if(i == 0)
this.items[i].inst == instruction::LOAD__A;
else if(i == 1)
this.items[i].inst == instruction::LOAD__B;
else if(i == 2)
this.items[i].inst == instruction::ADD_A_B;
else if(i == 3)
this.items[i].inst == instruction::STORE_C;
}
}
///////////////////////////////////////////////////////////////
////// ASUBTRACTION SCENARIO //////////
///////////////////////////////////////////////////////////////
int subtraction_scenario_id ;
constraint subtraction_scenario_items {
if($void(scenario_kind) == subtraction_scenario_id) {
repeated == 0;
length == 4;
foreach(items[i])
if(i == 0)
this.items[i].inst == instruction::LOAD__A;
else if(i == 1)
this.items[i].inst == instruction::LOAD__B;
else if(i == 2)
this.items[i].inst == instruction::SUB_A_B;
else if(i == 3)
this.items[i].inst == instruction::STORE_C;
}
}
function new();
this.addition_scenario_id = define_scenario(" ADDITION ",4);
this.subtraction_scenario_id = define_scenario(" SUBSTRACTION ",4);
endfunction
endclass
Testcase
Now we will write a test case to see how to above defined scenario works.
5) Scenario generators store all the scenarios in scenario_set queue. So, we have to
add the scenario which we constructed above to the queue.
gen.scenario_set[0] = sce_add_sub;
gen.start_xactor();
repeat(20) begin
gen.out_chan.get(inst);
inst.display();
Testcase code
program test();
initial
begin
gen = new("gen",0);
sce_add_sub = new();
//gen.log.set_verbosity(vmm_log::DEBUG_SEV,"/./","/./");
gen.stop_after_n_insts = 20;
gen.stop_after_n_scenarios = 4;
gen.scenario_set[0] = sce_add_sub;
gen.start_xactor();
repeat(20) begin
gen.out_chan.get(inst);
inst.display();
end
end
endprogram
vmm_scenario.tar
Browse the code in vmm_scenario.tar
Command to simulate
vcs -sverilog -ntb_opts rvm -f filelist -R
Observe the log file, you can see the both the scenarios.
Logfile
Search ✔
To supply a integer value "5" for runtime option "foo", use the
"+vmm_opts+...+foo=5+..." command-line option, or "+vmm_foo=5" command-line
option, or the line "+foo=5" in the option file.
To supply a string value "bar" for runtime option "foo" , use the
"+vmm_opts+...+foo=bar+..." command-line option, or "+vmm_foo=bar" command-line
option, or the line "+foo=bar" in the option file.
"+vmm_opts_file=finename.txt"
+vmm_help command line option will print the run time options help. This option will
call the vmm_opts::get_help() method.
The following is a basic example of how these parameters could be received using
vmm_opts
EXAMPLE
`include "vmm.sv"
class my_env extends vmm_env;
virtual function void gen_cfg();
integer foo1;
string foo2;
bit foo3;
super.gen_cfg();
`vmm_note(log,"START OF GEN_CFG ");
foo1 = vmm_opts::get_int("foo1" , 10 , "Help for the option foo1: pass any integer
between 0 to 100");
foo2 = vmm_opts::get_string("foo2" , "default_string" , "Help for the option foo2:
pass any string");
foo3 = vmm_opts::get_int("foo3" , "Help for the option foo3: just use foo3 to
enable ");
`vmm_note(log,$psprintf("\n Run time Options \n foo1 : %0d \n foo2 : %s
\n foo3 : %b \n",foo1,foo2,foo3));
`vmm_note(log,"END OF GEN_CFG ");
endfunction
endclass
program main();
initial
begin
my_env env;
env = new();
env.run();
end
endprogram
vmm_opts.tar
Browse the code in vmm_opts.tar
Commands to complie
Commands to complie
./simv
./simv +vmm_foo1=101
./simv +vmm_opts+foo1=101+foo2=Testbench.in
Log
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog NOTE: ovm_env and ovm_test are also extended from ovm_component.
Verification A typical ovm verification environment:
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
OVM phases
OVM Components execute their behavior in strictly ordered, pre-defined phases. Each
phase is defined by its own virtual method, which derived components can override to
incorporate component-specific behavior. By default , these methods do nothing.
--> virtual function void build()
--> virtual function void connect()
--> virtual function void end_of_elaboration()
--> virtual function void start_of_simulation()
--> virtual task run()
In this phase , Main body of the test is executed where all threads are forked off.
--> virtual function void extract()
--> virtual function void check()
In this phase, check the results of the extracted information such as un responded
requests in scoreboard, read statistics registers etc.
--> virtual function void report()
Ovm_test
Lets implement environment for the following topology. I will describe the
implementation of environment , testcase and top module. Agent, monitor and driver
are implemented similar to environment.
class env extends ovm_env;
2)Declare the utility macro. This utility macro provides the implementation of create()
and get_type_name() methods and all the requirements needed for factory.
`ovm_component_utils(env)
agent ag1;
agent ag2;
4)Define the constructor. In the constructor, call the super methods and pass the
parent object. Parent is the object in which environment is instantiated.
function void build();
super.build();
ovm_report_info(get_full_name(),"Build", OVM_LOG);
ag1 = agent::type_id::create("ag1",this);
ag2 = agent::type_id::create("ag2",this);
endfunction
6)Define
connect(),end_of_elaboration(),start_of_simulation(),run(),extract(),check(),report()
methods.
Just print a message from these methods, as we dont have any logic in this example
to define.
function void connect();
ovm_report_info(get_full_name(),"Connect", OVM_LOG);
endfunction
class env extends ovm_env;
`ovm_component_utils(env)
agent ag1;
agent ag2;
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction
function void build();
ovm_report_info(get_full_name(),"Build", OVM_LOG);
ag1 = agent::type_id::create("ag1",this);
ag2 = agent::type_id::create("ag2",this);
endfunction
function void connect();
ovm_report_info(get_full_name(),"Connect", OVM_LOG);
endfunction
function void end_of_elaboration();
ovm_report_info(get_full_name(),"End_of_elaboration", OVM_LOG);
endfunction
function void start_of_simulation();
ovm_report_info(get_full_name(),"Start_of_simulation", OVM_LOG);
endfunction
task run();
ovm_report_info(get_full_name(),"Run", OVM_LOG);
endtask
function void extract();
ovm_report_info(get_full_name(),"Extract", OVM_LOG);
endfunction
function void check();
ovm_report_info(get_full_name(),"Check", OVM_LOG);
endfunction
function void report();
ovm_report_info(get_full_name(),"Report", OVM_LOG);
endfunction
endclass
class test1 extends ovm_test;
`ovm_component_utils(test1)
env t_env;
3)Define constructor method. In the constructor, call the super method and construct
the environment object.
function new (string name="test1", ovm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
4)Define the end_of_elaboration method. In this method, call the print() method. This
print() method will print the topology of the test.
function void end_of_elaboration();
ovm_report_info(get_full_name(),"End_of_elaboration", OVM_LOG);
print();
endfunction
task run ();
#1000;
global_stop_request();
endtask : run
class test1 extends ovm_test;
`ovm_component_utils(test1)
env t_env;
function new (string name="test1", ovm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
function void end_of_elaboration();
ovm_report_info(get_full_name(),"End_of_elaboration", OVM_LOG);
print();
endfunction
task run ();
#1000;
global_stop_request();
endtask : run
endclass
Top Module:
To start the testbench, run_test() method must be called from initial block.
Run_test() mthod Phases all components through all registered phases.
module top;
initial
run_test();
endmodule
ovm_phases.tar
Browse the code in ovm_phases.tar
Log file:
ovm_test_top.t_env.ag1.drv[ovm_test_top.t_env.ag1.drv]Start_of_simulation
ovm_test_top.t_env.ag1.mon[ovm_test_top.t_env.ag1.mon]Start_of_simulation
ovm_test_top.t_env.ag1[ovm_test_top.t_env.ag1]Start_of_simulation
ovm_test_top.t_env.ag2.drv[ovm_test_top.t_env.ag2.drv]Start_of_simulation
ovm_test_top.t_env.ag2.mon[ovm_test_top.t_env.ag2.mon]Start_of_simulatio
..
..
..
..
1)Build method was called in top-down fashion. Look at the following part of message.
2)Connect method was called in bottopm up fashion. Look at the below part of log
file,
Search ✔
Basic Constructs verbosity -- the verbosity of the message, indicating its relative importance. If this
number is less than or equal to the effective verbosity level, then the report is issued,
subject to the configured action and file descriptor settings.
OpenVera
Constructs filename/line -- If required to print filename and line number from where the
message is issued, use macros, `__FILE__ and `__LINE__.
Switch TB
RVM Switch TB
Actions:
RVM Ethernet sample
These methods associate the specified action or actions with reports of the
givenseverity, id, or severity-id pair.
Specman E
Following are the actions defined:
Interview Questions
OVM_NO_ACTION -- Do nothing
OVM_DISPLAY -- Display report to standard output
OVM_LOG -- Write to a file
OVM_COUNT -- Count up to a max_quit_count value before exiting
OVM_EXIT -- Terminates simulation immediately
OVM_CALL_HOOK -- Callback the hook method .
Configuration:
Using these methods, user can set the verbosity levels and set actions.
function void set_report_verbosity_level
(int verbosity_level)
function void set_report_severity_action
(ovm_severity severity,ovm_action action)
function void set_report_id_action
(string id,ovm_action action)
function void set_report_severity_id_action
(ovm_severity severity,string id,ovm_action action)
Example
`include "ovm.svh"
import ovm_pkg::*;
class rpting extends ovm_threaded_component;
`ovm_component_utils(rpting)
function new(string name,ovm_component parent);
super.new(name, parent);
endfunction
task run();
ovm_report_info(get_full_name(),
"Info Message : Verbo lvl - OVM_NONE ",OVM_NONE,`__FILE__,`__LINE__);
ovm_report_info(get_full_name(),
"Info Message : Verbo lvl - OVM_LOW ",OVM_LOW);
ovm_report_info(get_full_name(),
"Info Message : Verbo lvl - 150 ",150);
ovm_report_info(get_full_name(),
"Info Message : Verbo lvl - OVM_MEDIUM",OVM_MEDIUM);
ovm_report_warning(get_full_name(),
"Warning Messgae from rpting",OVM_LOW);
ovm_report_error(get_full_name(),
"Error Message from rpting \n\n",OVM_LOG);
endtask
endclass
module top;
rpting rpt1;
rpting rpt2;
rpting rpt3;
initial begin
rpt1 = new("rpt1",null);
rpt2 = new("rpt2",null);
rpt3 = new("rpt3",null);
rpt1.set_report_verbosity_level(OVM_MEDIUM);
rpt2.set_report_verbosity_level(OVM_LOW);
rpt3.set_report_verbosity_level(OVM_NONE);
run_test();
end
endmodule
ovm_reporting.tar
Browse the code in ovm_reporting.tar
Log file:
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
User should define these methods in the transaction using do_<method_name> and
call them using <method_name>. Following table shows calling methods and user-
defined hook do_<method_name> methods. Clone and create methods, does not
use hook methods concepts.
Shorthand Macros:
Using the field automation concept of ovm, all the above defines methods can be
defined automatically.
To use these field automation macros, first declare all the data fields, then place the
field automation macros between the `ovm_object_utils_begin and
`ovm_object_utils_end macros.
class Packet extends ovm_transaction;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] length;
rand bit [7:0] data[];
rand byte fcs;
`ovm_object_utils_begin(Packet)
`ovm_field_int(da, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(sa, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(length, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_array_int(data, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(fcs, OVM_ALL_ON|OVM_NOPACK)
`ovm_object_utils_end
endclass.
For most of the data types in systemverilog, ovm defined corresponding field
automation macros. Following table shows all the field automation macros.
Each `ovm_field_* macro has at least two arguments: ARG and FLAG.
ARG is the instance name of the variable and FLAG is used to control the field usage in
core utilities operation.
By default, FLAG is set to OVM_ALL_ON. All these flags can be ored. Using NO_* flags,
can turn of particular field usage in a paerticuler method. NO_* flags takes
precedency over other flags.
Example of Flags:
`ovm_field_int(da, OVM_ALL_ON|OVM_NOPACK)
The above macro will use the field "da" in all utilities methods except Packing and
unpacking methods.
In the following example, all the utility methods are defined using field automation
macros except Packing and unpacking methods. Packing and unpacking methods are
done in do_pack() amd do_unpack() method.
`include "ovm.svh"
import ovm_pkg::*;
class Packet extends ovm_transaction;
rand fcs_kind_t fcs_kind;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 6]};}
constraint length_c { length == data.size; }
constraint solve_size_length { solve data.size before length; }
function new(string name = "");
super.new(name);
endfunction : new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
///// method to calculate the fcs /////
virtual function byte cal_fcs;
integer i;
byte result ;
result = 0;
result = result ^ da;
result = result ^ sa;
result = result ^ length;
for (i = 0;i< data.size;i++)
result = result ^ data[i];
result = fcs ^ result;
return result;
endfunction : cal_fcs
`ovm_object_utils_begin(Packet)
`ovm_field_int(da, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(sa, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(length, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_array_int(data, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(fcs, OVM_ALL_ON|OVM_NOPACK)
`ovm_object_utils_end
function void do_pack(ovm_packer packer);
super.do_pack(packer);
packer.pack_field_int(da,$bits(da));
packer.pack_field_int(sa,$bits(sa));
packer.pack_field_int(length,$bits(length));
foreach(data[i])
packer.pack_field_int(data[i],8);
packer.pack_field_int(fcs,$bits(fcs));
endfunction : do_pack
function void do_unpack(ovm_packer packer);
int sz;
super.do_pack(packer);
da = packer.unpack_field_int($bits(da));
sa = packer.unpack_field_int($bits(sa));
length = packer.unpack_field_int($bits(length));
data.delete();
data = new[length];
foreach(data[i])
data[i] = packer.unpack_field_int(8);
fcs = packer.unpack_field_int($bits(fcs));
endfunction : do_unpack
endclass : Packet
/////////////////////////////////////////////////////////
//// Test to check the packet implementation ////
/////////////////////////////////////////////////////////
module test;
initial
repeat(10)
if(pkt1.randomize)
begin
$display(" Randomization Sucessesfull.");
pkt1.print();
ovm_default_packer.use_metadata = 1;
void'(pkt1.pack_bytes(pkdbytes));
$display("Size of pkd bits %d",pkdbytes.size());
pkt2.unpack_bytes(pkdbytes);
pkt2.print();
if(pkt2.compare(pkt1))
$display(" Packing,Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***
\n \n");
end
else
$display(" *** Randomization Failed ***");
endmodule
ovm_transaction.tar
Browse the code in ovm_transaction.tar
Log report:
Randomization Sucessesfull.
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
pkt1 Packet - pkt1@3
da integral 8 'h1d
sa integral 8 'h26
length integral 8 'h5
data da(integral) 5 -
[0] integral 8 'hb1
[1] integral 8 'h3f
[2] integral 8 'h9e
[3] integral 8 'h38
[4] integral 8 'h8d
fcs integral 8 'h9b
-------------------------------------------------------------------
---
Size of pkd bits 9
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
pkt2 Packet - pkt2@5
da integral 8 'h1d
sa integral 8 'h26
length integral 8 'h5
data da(integral) 5 -
[0] integral 8 'hb1
[1] integral 8 'h3f
[2] integral 8 'h9e
[3] integral 8 'h38
[4] integral 8 'h8d
fcs integral 8 'h9b
-------------------------------------------------------------------
---
Packing,Unpacking and compare worked
Search ✔
Using the ovm fatroy, it is very easy to solve the above two requirements. Only classs
Verilog extended from ovm_object and ovm_component are supported for this.
Verification
There are three basic steps to be followed for using ovm factory.
Verilog Switch TB
Basic Constructs 1) Registration
2) Construction
3) Overriding
OpenVera
Constructs
The factory makes it is possible to override the type of ovm component /object or
instance of a ovm component/object in2 ways. They are based on ovm
Switch TB component/object type or ovm compoenent/object name.
RVM Switch TB
Registration:
RVM Ethernet sample
While defining a class , its type has to be registered with the ovm factory. To do this
job easier, ovm has predefined macros.
Specman E
Interview Questions `ovm_component_utils(class_type_name)
`ovm_component_param_utils(class_type_name #(params))
`ovm_object_utils(class_type_name)
`ovm_object_param_utils(class_type_name #(params))
For ovm_*_param_utils are used for parameterized classes and other two macros for
non-parameterized class. Registration is required for name-based overriding , it is
not required for type-based overriding.
class packet extends ovm_object;
`ovm_object_utils(packet)
endclass
class packet #(type T=int, int mode=0) extends ovm_object;
`ovm_object_param_utils(packet #(T,mode))
endclass
class driver extends ovm_component;
`ovm_component_utils(driver)
endclass
class monitor #(type T=int, int mode=0) extends ovm_component;
`ovm_component_param_utils(driver#(T,mode))
endclass
Construction:
To construct a ovm based component or ovm based objects, static method create()
should be used. This function constructs the appropriate object based on the
overrides and constructs the object and returns it. So while constructing the ovm
based components or ovm based objects , do not use new() constructor.
Syntax :
static function T create(string name,
ovm_component parent,
string context = " ")
EXAMPLE:
class_type object_name;
object_name = class_type::type_id::creat("object_name",this);
For ovm_object based classes, doesnt need the parent handle as second argument.
Overriding:
If required, user could override the registered classes or objects. User can override
based of name string or class-type.
function void set_inst_override_by_type
(ovm_object_wrapper original_type,
ovm_object_wrapper override_type,
string full_inst_path )
The above method is used to override the object instances of "original_type" with
"override_type" . "override_type" is extended from"original_type".
function void set_inst_override_by_name
(string original_type_name,
string override_type_name,
string full_inst_path )
Original_type_name and override_type_name are the class names which are registered
in the factory. All the instances of objects with name "Original_type_name" will be
overriden with objects of name "override_type_name" using
set_inst_override_by_name() method.
function void set_type_override_by_type
(ovm_object_wrapper original_type,
ovm_object_wrapper override_type,
bit replace = 1 )
function void set_type_override_by_name
(string original_type_name,
string override_type_name,
bit replace = 1)
When multiple overrides are done , then using the argument "replace" , we can
control whether to override the previous override or not. If argument "replace" is 1,
then previous overrides will be replaced otherwise, previous overrides will remain.
print() method, prints the state of the ovm_factory, registered types, instance
overrides, and type overrides.
Now we will see a complete example. This example is based on the environment build
in topic OVM TESTBENCH . Refer to that section for more information about this
example.
Lets look at the 3 steps which I discussed above using the example defined in OVM
TESTBENCH
1) Registration
2) Construction
In file agant.sv file, monitor and driver are constructed using create() method.
mon = monitor::type_id::create("mon",this);
drv = driver::type_id::create("drv",this);
In this example, there is one driver class and one monitor class. In this testcase , By
extending driver class , we will define driver_2 class and by extending monitor class,
we will define monitor_2 class.
To know about the overrides which are done, call print_all_overrides() method of
factory class.
class driver_2 extends driver;
`ovm_component_utils(driver_2)
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction
endclass
class monitor_2 extends monitor;
`ovm_component_utils(monitor_2)
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction
endclass
class test_factory extends ovm_test;
`ovm_component_utils(test_factory)
env t_env;
function new (string name="test1", ovm_component parent=null);
super.new (name, parent);
factory.set_type_override_by_type(driver::get_type(),driver_2::get_type(),"*");
factory.set_type_override_by_name("monitor","monitor_2","*");
factory.print_all_overrides();
t_env = new("t_env",this);
endfunction : new
function void end_of_elaboration();
ovm_report_info(get_full_name(),"End_of_elaboration", OVM_LOG);
print();
endfunction : end_of_elaboration
task run ();
#1000;
global_stop_request();
endtask : run
endclass
ovm_factory.tar
Browse the code in ovm_factory.tar
Command to simulate
Command to run the example with the testcase which is defined above:
Your_tool_simulation_command +incdir+path_to_ovm -f filelist
+OVM_TESTNAME=test_factory
In the below text printed by print_topology() method ,we can see overridden driver
and monitor.
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
ovm_test_top test_factory - ovm_test_top@2
t_env env - t_env@4
ag1 agent - ag1@6
drv driver_2 - drv@12
rsp_port ovm_analysis_port - rsp_port@16
sqr_pull_port ovm_seq_item_pull_+ - sqr_pull_port@14
mon monitor_2 - mon@10
ag2 agent - ag2@8
drv driver_2 - drv@20
rsp_port ovm_analysis_port - rsp_port@24
sqr_pull_port ovm_seq_item_pull_+ - sqr_pull_port@22
mon monitor_2 - mon@18
-------------------------------------------------------------------
---
In the below text printed by print_topology() method ,with testcase test1 which does
note have overrides.
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
ovm_test_top test1 - ovm_test_top@2
Search ✔
Ovm_sequence_item :
Verilog User has to define a transaction by extending
ovm_sequence_item. ovm_sequence_item class provides the basic functionality for
Verification objects, both sequence items and sequences, to operate in the sequence mechanism.
Verilog Switch TB For more information about ovm_sequence_item Refer to link
Basic Constructs
OVM_TRANSACTION
Ovm_sequence:
OpenVera User should extend ovm_sequence class and define the construction of sequence of
Constructs transactions. These transactions can be directed, constrained randomized or fully
randomized. The ovm_sequence class provides the interfaces necessary in order to
Switch TB
create streams of sequence items and/or other sequences.
RVM Switch TB
RVM Ethernet sample
virtual class ovm_sequence #(
type REQ = ovm_sequence_item,
type RSP = REQ
Specman E )
Interview Questions
Ovm_sequencer:
Ovm_sequencer is responsible for the coordination between sequence and driver.
Sequencer sends the transaction to driver and gets the response from the driver. The
response transaction from the driver is optional. When multiple sequences are running
in parallel, then sequencer is responsible for arbitrating between the parallel
sequences. There are two types of sequencers : ovm_sequencer and
ovm_push_sequencer
class ovm_sequencer #(
type REQ = ovm_sequence_item,
type RSP = REQ
)
class ovm_push_sequencer #(
type REQ = ovm_sequence_item,
type RSP = REQ
)
Ovm driver:
User should extend ovm_driver class to define driver component. ovm driver is a
component that initiate requests for new transactions and drives it to lower level
components. There are two types of drivers: ovm_driver and ovm_push_driver.
class ovm_driver #(
type REQ = ovm_sequence_item,
type RSP = REQ
)
class ovm_push_driver #(
type REQ = ovm_sequence_item,
type RSP = REQ
)
The above image shows how a transaction from a sequence is sent to driver and the
response from the driver is sent to sequencer. There are multiple methods called
during this operation.
6) The transaction which is sent from sequence , in the driver this transaction is
available as "seq_item_port.get_next_item(req)" method argument. Then driver can
drive this transaction to bus or lower level.
After this step, again the steps 1 to 7 are repeated five times.
If a response from driver is not required, then steps 5,6,7 can be skipped and
item_done() method from driver should be called as shown in above image.
Simple Example
Sequence Item
class instruction extends ovm_sequence_item;
typedef enum {PUSH_A,PUSH_B,ADD,SUB,MUL,DIV,POP_C} inst_t;
rand inst_t inst;
`ovm_object_utils_begin(instruction)
`ovm_field_enum(inst_t,inst, OVM_ALL_ON)
`ovm_object_utils_end
function new (string name = "instruction");
super.new(name);
endfunction
`ovm_object_utils_begin(instruction)
`ovm_field_enum(inst_t,inst, OVM_ALL_ON)
`ovm_object_utils_end
function new (string name = "instruction");
super.new(name);
endfunction
endclass
Sequence
function new(string name="operation_addition");
super.new(name);
endfunction
`ovm_sequence_utils(operation_addition, instruction_sequencer)
4)
In the body() method, first call wait_for_grant(), then construct a transaction and set
the instruction enum to PUSH_A . Then send the transaction to driver using
send_request() method. Then call the wait_for_item_done() method. Repeat the
above steps for other instructions PUSH_B, ADD and POP_C.
For construction of a transaction, we will use the create() method.
virtual task body();
req = instruction::type_id::create("req");
wait_for_grant();
assert(req.randomize() with {
inst == instruction::PUSH_A;
});
send_request(req);
wait_for_item_done();
//get_response(res); This is optional. Not using in this example.
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::PUSH_B;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::ADD;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::POP_C;
send_request(req);
wait_for_item_done();
//get_response(res);
endtask
Sequence code
instruction req;
function new(string name="operation_addition");
super.new(name);
endfunction
`ovm_sequence_utils(operation_addition, instruction_sequencer)
virtual task body();
req = instruction::type_id::create("req");
wait_for_grant();
assert(req.randomize() with {
inst == instruction::PUSH_A;
});
send_request(req);
wait_for_item_done();
//get_response(res); This is optional. Not using in this example.
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::PUSH_B;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::ADD;
send_request(req);
wait_for_item_done();
//get_response(res);
req = instruction::type_id::create("req");
wait_for_grant();
req.inst = instruction::POP_C;
send_request(req);
wait_for_item_done();
//get_response(res);
endtask
endclass
Sequencer:
started.
Ovm sequencer has seq_item_export and res_export tlm ports for connecting to ovm
driver.
function new (string name, ovm_component parent);
super.new(name, parent);
`ovm_update_sequence_lib_and_item(instruction)
endfunction
3) Place the ovm_sequencer_utils macro. This macro registers the sequencer for
factory overrides.
`ovm_sequencer_utils(instruction_sequencer)
Sequencer Code;
class instruction_sequencer extends ovm_sequencer #(instruction);
function new (string name, ovm_component parent);
super.new(name, parent);
`ovm_update_sequence_lib_and_item(instruction)
endfunction
`ovm_sequencer_utils(instruction_sequencer)
endclass
Driver:
Seq_item_port methods:
1) Define a driver which takes the instruction from the sequencer and does the
processing. In this example we will just print the instruction type and wait for some
delay.
`ovm_component_utils(instruction_driver)
3) Define Constructor method.
function new (string name, ovm_component parent);
super.new(name, parent);
endfunction
4) Define the run() method. Run() method is executed in the "run phase". In this
methods, transactions are taken from the sequencer and drive them on to dut
interface or to other components.
Driver class has a port "seq_item_port". Using the method
seq_item_port.get_next_item(), get the transaction from the sequencer and process
it. Once the processing is done, using the item_done() method, indicate to the
sequencer that the request is completed. In this example, after taking the
transaction, we will print the transaction and wait for 10 units time.
task run ();
while(1) begin
seq_item_port.get_next_item(req);
$display("%0d: Driving Instruction %s",$time,req.inst.name());
#10;
seq_item_port.item_done();
end
endtask
endclass
// Constructor
function new (string name, ovm_component parent);
super.new(name, parent);
endfunction
task run ();
forever begin
seq_item_port.get_next_item(req);
$display("%0d: Driving Instruction %s",$time,req.inst.name());
#10;
// rsp.set_id_info(req); These two steps are required only if
// seq_item_port.put(esp); responce needs to be sent back to sequence
seq_item_port.item_done();
end
endtask
endclass
Deriver and sequencer are connected using TLM. Ovm_driver has seq_item_port which
is used to get the transaction from ovm sequencer. This port is connected to
ovm_sequencer seq_item_export Using
"<driver>.seq_item_port.connect(<sequencer>.seq_item_export);" driver and
sequencer can be connected. Simillarly "res_port" of driver which is used to send
response from driver to sequencer is connected to "res_export" of the sequencer using
""<driver>.res_port.connect(<sequencer>.res_export);".
Testcase:
This testcase is used only for the demo purpose of this tutorial session. Actually, the
sequencer and the driver and instantiated and their ports are connected in a agent
component and used. Lets implement a testcase
sequencer = new("sequencer", null);
sequencer.build();
driver = new("driver", null);
driver.build();
2)
Connect the seq_item_export to the drivers seq_item_port.
driver.seq_item_port.connect(sequencer.seq_item_export);
set_config_string("sequencer", "default_sequence", "operation_addition");
sequencer.start_default_sequence();
Testcase Code:
module test;
instruction_sequencer sequencer;
instruction_driver driver;
initial begin
set_config_string("sequencer", "default_sequence", "operation_addition");
sequencer = new("sequencer", null);
sequencer.build();
driver = new("driver", null);
driver.build();
driver.seq_item_port.connect(sequencer.seq_item_export);
sequencer.print();
fork
begin
run_test();
sequencer.start_default_sequence();
end
#2000 global_stop_request();
join
end
endmodule
ovm_basic_sequence.tar
Browse the code in ovm_basic_sequence.tar
Command to simulate
From the above log , we can see that transactions are generates as we defined in ovm
sequence.
Search ✔
Verilog
Verification
Verilog Switch TB Ovm_random_sequence :
Basic Constructs
This sequence randomly selects and executes a sequence from the sequencer
sequence library, excluding ovm_random_sequence itself, and
ovm_exhaustive_sequence. From the above image, from sequence id 2 to till the last
OpenVera sequence, all the sequences are executed randomly. If the "count" variable of the
Constructs sequencer is set to 0, then non of the sequence is executed. If the "count" variable of
Switch TB the sequencer is set to -1, then some random number of sequences from 0 to
"max_random_count" are executed. By default "mac_random_count" is set to
RVM Switch TB 10. "Count" and "mac_random_count" can be changed using set_config_int().
RVM Ethernet sample
The sequencer when automatically started executes the sequence which is point by
default_sequence. By default default_sequence variable points to
ovm_random_sequence.
Specman E
Interview Questions ovm_exaustive_sequence:
This sequence randomly selects and executes each sequence from the sequencers
sequence library once in a randc style, excluding itself and ovm_random_sequence.
ovm_simple_sequence:
The print() method of the sequencer in that example printed the following
-------------------------------------------------------------------
---
Name Type Size Value
-------------------------------------------------------------------
---
sequencer instruction_sequen+ - sequencer@2
rsp_export ovm_analysis_export - rsp_export@4
seq_item_export ovm_seq_item_pull_+ - seq_item_export@28
default_sequence string 18 operation_addition
count integral 32 -1
max_random_count integral 32 'd10
sequences array 4 -
[0] string 19 ovm_random_sequence
[1] string 23 ovm_exhaustive_sequ+
[2] string 19 ovm_simple_sequence
[3] string 18 operation_addition
max_random_depth integral 32 'd4
num_last_reqs integral 32 'd1
num_last_rsps integral 32 'd1
-------------------------------------------------------------------
---
Lets look at a example: In the attached example, in file sequence.sv file, there are 4
seuqneces, they are operation_addition, operation_subtraction,
operation_multiplication.
ovm_sequence_1.tar
Browse the code in ovm_sequence_1.tar
Log File
0: Driving Instruction PUSH_B
From the above log , we can see that all the 3 user defined sequences and predefined
ovm_simple_sequence are executed.
All these steps have be automated using "sequence action macros". There are some
more additional steps added in these macros. Following are the steps defined with the
"sequence action macro".
Pre_do(), mid_do() and post_do() are callback methods which are in ovm sequence. If
user is interested , he can use these methods. For example, in mid_do() method, user
can print the transaction or the randomized transaction can be fined tuned. These
methods should not be clled by user directly.
Syntax:
virtual task pre_do(bit is_item)
virtual function void mid_do(ovm_sequence_item this_item)
virtual function void post_do(ovm_sequence_item this_item)
Pre_do() is a task , if the method consumes simulation cycles, the behavior may be
unexpected.
Lets look at a example: We will define a sequence using `ovm_do macro. This macro
has all the above defined phases.
1)Define the body method using the `ovm_do() macro. Before and after this macro,
just call messages.
virtual task body();
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : Before ovm_do macro ",OVM_LOW);
`ovm_do(req);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : After ovm_do macro ",OVM_LOW);
endtask
2)Define pre_do() method. Lets just print a message from this method.
virtual task pre_do(bit is_item);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : PRE_DO ",OVM_LOW);
endtask
3)Define mid_do() method. Lets just print a message from this method.
virtual function void mid_do(ovm_sequence_item this_item);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : MID_DO ",OVM_LOW);
endfunction
4)Define post_do() method. Lets just print a message from this method.
virtual function void post_do(ovm_sequence_item this_item);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : POST_DO ",OVM_LOW);
endfunction
instruction req;
function new(string name="demo_ovm_do");
super.new(name);
endfunction
`ovm_sequence_utils(demo_ovm_do, instruction_sequencer)
virtual task pre_do(bit is_item);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : PRE_DO ",OVM_LOW);
endtask
virtual function void mid_do(ovm_sequence_item this_item);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : MID_DO ",OVM_LOW);
endfunction
virtual function void post_do(ovm_sequence_item this_item);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : POST_DO ",OVM_LOW);
endfunction
virtual task body();
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : Before ovm_do macro ",OVM_LOW);
`ovm_do(req);
ovm_report_info(get_full_name(),
"Seuqnce Action Macro Phase : After ovm_do macro ",OVM_LOW);
endtask
endclass
ovm_sequence_2.tar
Browse the code in ovm_sequence_2.tar
OVM_INFO@0:reporter[sequencer.demo_ovm_do]
Seuqnce Action Macro Phase : Before ovm_do macro
OVM_INFO@0:reporter[sequencer.demo_ovm_do]
Seuqnce Action Macro Phase : PRE_DO
OVM_INFO@0:reporter[sequencer.demo_ovm_do]
Seuqnce Action Macro Phase : MID_DO
0: Driving Instruction MUL
OVM_INFO@10:reporter[sequencer.demo_ovm_do]
The above log file shows the messages from pre_do,mid_do and post_do methods.
These macros are used to start sequences and sequence items that were either
registered with a <`ovm-sequence_utils> macro or whose associated sequencer was
already set using the <set_sequencer> method.
`ovm_create(item/sequence)
This action creates the item or sequence using the factory. Only the create phase will
be executed.
`ovm_do(item/sequence)
This is the same as `ovm_do except that the constraint block in the 2nd argument is
applied to the item or sequence in a randomize with statement before execution.
`ovm_send(item/sequence)
Create phase and randomize phases are skipped, rest all the phases will be executed.
Using `ovm_create, create phase can be executed. Essentially, an `ovm_do without
the create or randomization.
`ovm_rand_send(item/sequence)
Only create phase is skipped. rest of all the phases will be executed. User should use
`ovm_create to create the sequence or item.
Only create phase is skipped. rest of all the phases will be executed. User should use
`ovm_create to create the sequence or item. Constraint block will be applied which
randomization.
`ovm_do_pri(item/sequence, priority )
This is the same as `ovm_do except that the sequence item or sequence is executed
with the priority specified in the argument.
This is the same as `ovm_do_pri except that the given constraint block is applied to
the item or sequence in a randomize with statement before execution.
`ovm_send_pri(item/sequence,priority)
This is the same as `ovm_send except that the sequence item or sequence is executed
with the priority specified in the argument.
`ovm_rand_send_pri(item/sequence,priority)
This is the same as `ovm_rand_send except that the sequence item or sequence is
executed with the priority specified in the argument.
`ovm_rand_send_pri_with(item/sequence,priority,constraint block)
This is the same as `ovm_rand_send_pri except that the given constraint block is
applied to the item or sequence in a randomize with statement before execution.
`ovm_create_on(item/sequence,sequencer)
This is the same as `ovm_create except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
`ovm_do_on(item/sequence,sequencer)
This is the same as `ovm_do except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
`ovm_do_on_pri(item/sequence,sequencer, priority)
This is the same as `ovm_do_pri except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
This is the same as `ovm_do_with except that it also sets the parent sequence to the
sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument. The user must supply brackets around the constraints.
`ovm_do_on_pri_with(item/sequence,sequencer,priority,constraint block)
This is the same as `ovm_do_pri_with except that it also sets the parent sequence to
the sequence in which the macro is invoked, and it sets the sequencer to the specified
sequencer argument.
virtual task body();
ovm_report_info(get_full_name(),
"Executing Sequence Action Macro ovm_do",OVM_LOW);
`ovm_do(req)
endtask
virtual task body();
ovm_report_info(get_full_name(),
"Executing Sequence Action Macro ovm_do_with ",OVM_LOW);
`ovm_do_with(req,{ inst == ADD; })
endtask
virtual task body();
ovm_report_info(get_full_name(),
"Executing Sequence Action Macro ovm_create and ovm_send",OVM_LOW);
`ovm_create(req)
req.inst = instruction::PUSH_B;
`ovm_send(req)
endtask
virtual task body();
ovm_report_info(get_full_name(),
"Executing Sequence Action Macro ovm_create and
ovm_rand_send",OVM_LOW);
`ovm_create(req)
`ovm_rand_send(req)
endtask
ovm_sequence_3.tar
Browse the code in ovm_sequence_3.tar
0: Driving Instruction PUSH_B
OVM_INFO@10:reporter[***]Executing Sequence Action Macro ovm_do_with
10: Driving Instruction ADD
OVM_INFO@20:reporter[***]Executing Sequence Action Macro ovm_create and
ovm_send
20: Driving Instruction PUSH_B
OVM_INFO@30:reporter[***]Executing Sequence Action Macro ovm_do
30: Driving Instruction DIV
OVM_INFO@40:reporter[***]Executing Sequence Action Macro ovm_create and
ovm_rand_send
40: Driving Instruction MUL
Search ✔
Verilog virtual task pre_body();
Verification ovm_report_info(get_full_name()," pre_body() callback ",OVM_LOW);
endtask
Verilog Switch TB
Basic Constructs virtual task post_body();
ovm_report_info(get_full_name()," post_body() callback ",OVM_LOW);
endtask
OpenVera virtual task body();
Constructs ovm_report_info(get_full_name(),
Switch TB "body() method: Before ovm_do macro ",OVM_LOW);
`ovm_do(req);
RVM Switch TB ovm_report_info(get_full_name(),
RVM Ethernet sample "body() method: After ovm_do macro ",OVM_LOW);
endtask
endclass
Specman E
Interview Questions
Download the example
ovm_sequence_4.tar
Browse the code in ovm_sequence_4.tar
Hierarchical Sequences
Sequential Sequences
Sequence 1 code:
virtual task body();
repeat(4) begin
`ovm_do_with(req, { inst == PUSH_A; });
end
endtask
Sequence 2 code:
virtual task body();
repeat(4) begin
`ovm_do_with(req, { inst == PUSH_B; });
end
endtask
seq_a s_a;
seq_b s_b;
function new(string name="sequential_sequence");
super.new(name);
endfunction
`ovm_sequence_utils(sequential_sequence, instruction_sequencer)
virtual task body();
`ovm_do(s_a);
`ovm_do(s_b);
endtask
endclass
ovm_sequence_5.tar
Browse the code in ovm_sequence_5.tar
0: Driving Instruction PUSH_A
10: Driving Instruction PUSH_A
20: Driving Instruction PUSH_A
30: Driving Instruction PUSH_A
40: Driving Instruction PUSH_B
50: Driving Instruction PUSH_B
60: Driving Instruction PUSH_B
70: Driving Instruction PUSH_B
If you observe the above log, you can see sequence seq_a is executed first and then
sequene seq_b is executed.
Parallelsequences
To executes child sequences Parallel, child sequence start() method should be called
parallel using fork/join in body method.
seq_a s_a;
seq_b s_b;
function new(string name="parallel_sequence");
super.new(name);
endfunction
`ovm_sequence_utils(parallel_sequence, instruction_sequencer)
virtual task body();
fork
`ovm_do(s_a)
`ovm_do(s_b)
join
endtask
endclass
ovm_sequence_6.tar
Browse the code in ovm_sequence_6.tar
Search ✔
Verilog
Verification
To set the arbitaration, use the set_arbitration() method of the sequencer. By default
Verilog Switch TB , the arbitration algorithms is set to SEQ_ARB_FIFO.
Basic Constructs
function void set_arbitration(SEQ_ARB_TYPE val)
Sequence code 3:
virtual task body();
repeat(3) begin
`ovm_do_with(req, { inst == SUB; });
end
endtask
In the body method, before starting child sequences, set the arbitration using
set_arbitration(). In this code, im setting it to SEQ_ARB_RANDOM.
seq_add add;
seq_sub sub;
seq_mul mul;
function new(string name="parallel_sequence");
super.new(name);
endfunction
`ovm_sequence_utils(parallel_sequence, instruction_sequencer)
virtual task body();
m_sequencer.set_arbitration(SEQ_ARB_RANDOM);
fork
`ovm_do(add)
`ovm_do(sub)
`ovm_do(mul)
join
endtask
endclass
ovm_sequence_7.tar
Browse the code in ovm_sequence_7.tar
0: Driving Instruction MUL
10: Driving Instruction SUB
20: Driving Instruction MUL
30: Driving Instruction SUB
40: Driving Instruction MUL
50: Driving Instruction ADD
60: Driving Instruction ADD
70: Driving Instruction SUB
80: Driving Instruction ADD
0: Driving Instruction ADD
10: Driving Instruction SUB
20: Driving Instruction MUL
30: Driving Instruction ADD
40: Driving Instruction SUB
50: Driving Instruction MUL
60: Driving Instruction ADD
70: Driving Instruction SUB
80: Driving Instruction MUL
If you observe the first log report, all the transaction of the sequences are generated
in random order. In the second log file, the transactions are given equal priority and
are in fifo order.
There are two ways to set the priority of a sequence. One is using the start method of
the sequence and other using the set_priority() method of the sequence. By default,
the priority of a sequence is 100. Higher numbers indicate higher priority.
virtual task start (ovm_sequencer_base sequencer,
ovm_sequence_base parent_sequence = null,
integer this_priority = 100,
bit call_pre_post = 1)
function void set_priority (int value)
In the below example, start() method is used to override the default priority value.
Code :
seq_add add;
seq_sub sub;
seq_mul mul;
function new(string name="parallel_sequence");
super.new(name);
endfunction
`ovm_sequence_utils(parallel_sequence, instruction_sequencer)
virtual task body();
m_sequencer.set_arbitration(SEQ_ARB_WEIGHTED);
add = new("add");
sub = new("sub");
mul = new("mul");
fork
sub.start(m_sequencer,this,400);
add.start(m_sequencer,this,300);
mul.start(m_sequencer,this,200);
join
endtask
endclass
ovm_sequence_8.tar
Browse the code in ovm_sequence_8.tar
0: Driving Instruction MUL
10: Driving Instruction ADD
20: Driving Instruction SUB
30: Driving Instruction SUB
Search ✔
rand integer num_inst ;
OpenVera instruction req;
Constructs
Switch TB constraint num_c { num_inst inside { 3,5,7 }; };
RVM Switch TB `ovm_sequence_utils_begin(seq_mul,instruction_sequencer)
RVM Ethernet sample `ovm_field_int(num_inst, OVM_ALL_ON)
`ovm_sequence_utils_end
function new(string name="seq_mul");
Specman E super.new(name);
Interview Questions endfunction
virtual task body();
ovm_report_info(get_full_name(),
$psprintf("Num of transactions %d",num_inst),OVM_LOW);
repeat(num_inst) begin
`ovm_do_with(req, { inst == MUL; });
end
endtask
endclass
ovm_sequence_9.tar
Browse the code in ovm_sequence_9.tar
Log
set_config_* can be used only for the components not for the sequences.
By using configuration you can change the variables inside components only not in
sequences.
Sequence has handle name called p_sequencer which is pointing the Sequencer on
which it is running.
Sequencer is a component , so get_config_* methods are implemented for it.
So from the sequence, using the sequencer get_config_* methods, sequence members
can be updated if the variable is configured.
When using set_config_* , path to the variable should be sequencer name, as we are
using the sequencer get_config_* method.
Sequence:
integer num_inst = 4;
instruction req;
`ovm_sequence_utils_begin(seq_mul,instruction_sequencer)
`ovm_field_int(num_inst, OVM_ALL_ON)
`ovm_sequence_utils_end
function new(string name="seq_mul");
super.new(name);
endfunction
virtual task body();
void'(p_sequencer.get_config_int("num_inst",num_inst));
ovm_report_info(get_full_name(),
$psprintf("Num of transactions %d",num_inst),OVM_LOW);
repeat(num_inst) begin
Testcase:
From the testcase, using the set_config_int() method, configure the num_inst to 3.
The instance path argument should be the sequencer path name.
module test;
instruction_sequencer sequencer;
instruction_driver driver;
initial begin
set_config_string("sequencer", "default_sequence", "seq_mul");
set_config_int("sequencer", "num_inst",3);
sequencer = new("sequencer", null);
sequencer.build();
driver = new("driver", null);
driver.build();
driver.seq_item_port.connect(sequencer.seq_item_export);
sequencer.print();
fork
begin
run_test();
sequencer.start_default_sequence();
end
#3000 global_stop_request();
join
end
endmodule
ovm_sequence_10.tar
Browse the code in ovm_sequence_10.tar
Log
Search ✔
Sequence 1 code:
OpenVera
virtual task body();
Constructs repeat(4) begin
Switch TB `ovm_do_with(req, { inst == PUSH_A; });
end
RVM Switch TB
endtask
RVM Ethernet sample
Sequence 2 code:
virtual task body();
repeat(4) begin
Specman E
`ovm_do_with(req, { inst == POP_C; });
Interview Questions end
endtask
Sequence 3 code:
In this sequence , call the lock() method to get the exclusive access to driver.
After completing all the transaction driving, then call the unclock() method.
virtual task body();
lock();
repeat(4) begin
`ovm_do_with(req, { inst == PUSH_B; });
end
unlock();
endtask
virtual task body();
fork
`ovm_do(s_a)
`ovm_do(s_b)
`ovm_do(s_c)
join
endtask
ovm_sequence_11.tar
Browse the code in ovm_sequence_11.tar
Log file:
0: Driving Instruction PUSH_A
10: Driving Instruction POP_C
20: Driving Instruction PUSH_A
30: Driving Instruction PUSH_B
40: Driving Instruction PUSH_B
50: Driving Instruction PUSH_B
60: Driving Instruction PUSH_B
70: Driving Instruction POP_C
80: Driving Instruction PUSH_A
90: Driving Instruction POP_C
100: Driving Instruction PUSH_A
110: Driving Instruction POP_C
From the above log file, we can observe that , when seq_b sequence got the access,
then transactions from seq_a and seq_c are not generated.
Lock() will be arbitrated before giving the access. To get the exclusive access without
arbitration, grab() method should be used.
Grab-Ungrab
grab() method requests a lock on the specified sequencer. A grab() request is put in
front of the arbitration queue. It will be arbitrated before any other requests. A
grab() is granted when no other grabs or locks are blocking this sequence.
Ungrab() method removes any locks or grabs obtained by this sequence on the
specified sequencer.
If no argument is supplied, then current default sequencer is chosen.
Example:
virtual task body();
#25;
grab();
repeat(4) begin
`ovm_do_with(req, { inst == PUSH_B; });
end
ungrab();
endtask
ovm_sequence_12.tar
Browse the code in ovm_sequence_12.tar
0: Driving Instruction PUSH_A
10: Driving Instruction POP_C
20: Driving Instruction PUSH_A
30: Driving Instruction PUSH_B
40: Driving Instruction PUSH_B
50: Driving Instruction PUSH_B
60: Driving Instruction PUSH_B
70: Driving Instruction POP_C
80: Driving Instruction PUSH_A
90: Driving Instruction POP_C
100: Driving Instruction PUSH_A
110: Driving Instruction POP_C
Search ✔
function void set_config_object (string inst_name,
Verilog string field_name,
Verification ovm_object value, bit clone = 1)
Verilog Switch TB
Basic Constructs Arguments description:
Specman E
Interview Questions "*" matches zero or more characters
"?" matches exactly one character
Some examples:
"ab?" -All the lower level components which start with "ab" , then followed by one
more character.
Example: "abc","abb","abx" ....
"?bc" -All the lower level components which start with any one character ,then
followed by "c".
Example: "abc","xbc","bbc" ....
"a?c" -All the lower level components which start with "a" , then followed by one
more character and then followed by "c".
Example: "abc","aac","axc" …..
Automatic Configuration:
To use the atomic configuration, all the configurable fields should be defined using
ovm component field macros and ovm component utilities macros.
Example:
Following example is from link
OVM_TESTBENCH
2 Configurable fields, a integer and a string are defined in env, agent, monitor and
driver classes. Topology of the environment using these classes is
Similar to driver class, all other components env, agent and monitor are define.
class driver extends ovm_driver;
integer int_cfg;
string str_cfg;
`ovm_component_utils_begin(driver)
`ovm_field_int(int_cfg, OVM_DEFAULT)
`ovm_field_string(str_cfg, OVM_DEFAULT)
`ovm_component_utils_end
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction
function void build();
super.build();
endfunction
endclass
Testcase:
//t_env.ag1.drv.int_cfg
//t_env.ag1.mon.int_cfg
set_config_int("*.ag1.*","int_cfg",32);
//t_env.ag2.drv
set_config_int("t_env.ag2.drv","int_cfg",32);
//t_env.ag2.mon
set_config_int("t_env.ag2.mon","int_cfg",32);
//t_env.ag1.mon.str_cfg
//t_env.ag2.mon.str_cfg
//t_env.ag1.drv.str_cfg
//t_env.ag2.drv.str_cfg
set_config_string("*.ag?.*","str_cfg","pars");
//t_env.str_cfg
set_config_string("t_env","str_cfg","abcd");
ovm_configuration_1.tar
Browse the code in ovm_configuration_1.tar
From the above log report of th example, we can see the variables int_cfg and str_cfg
of all the components and they are as per the configuration setting from the testcase.
Manual Configurations:
Using get_config_* methods, user can get the required data if the data is available in
the table.
Following are the method to get configure data of type integer , string and object of
ovm_object based class respectively.
function bit get_config_int (string field_name,
inout ovm_bitstream_t value)
function bit get_config_string (string field_name,
inout string value)
function bit get_config_object (string field_name,
inout ovm_object value,
input bit clone = 1)
If a entry is found in the table with "field_name" then data will be updated to "value"
argument . If entry is not found, then the function returns "0". So when these
methods are called, check the return value.
Example:
Driver class code:
class driver extends ovm_driver;
integer int_cfg;
string str_cfg;
`ovm_component_utils(driver)
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction
function void build();
super.build();
void'(get_config_int("int_cfg",int_cfg));
void'(get_config_string("str_cfg",str_cfg));
ovm_report_info(get_full_name(),
$psprintf("int_cfg %0d : str_cfg %0s ",int_cfg,str_cfg),OVM_LOW);
endfunction
endclass
Download the source code
ovm_configuration_2.tar
Browse the code in ovm_configuration_2.tar
Log file
OVM_INFO @ 0: ovm_test_top.t_env
int_cfg x : str_cfg abcd
OVM_INFO @ 0: ovm_test_top.t_env.ag1
int_cfg x : str_cfg
OVM_INFO @ 0: ovm_test_top.t_env.ag1.drv
int_cfg 32 : str_cfg pars
OVM_INFO @ 0: ovm_test_top.t_env.ag1.mon
int_cfg 32 : str_cfg pars
OVM_INFO @ 0: ovm_test_top.t_env.ag2
int_cfg x : str_cfg
OVM_INFO @ 0: ovm_test_top.t_env.ag2.drv
int_cfg 32 : str_cfg pars
OVM_INFO @ 0: ovm_test_top.t_env.ag2.mon
int_cfg 32 : str_cfg pars
print_config_settings
function void print_config_settings
( string field = "",
ovm_component comp = null,
bit recurse = 0 )
print_config_matches
static bit print_config_matches = 0
Setting this static variable causes get_config_* to print info about matching
configuration settings as they are being applied. These two members will be helpful
to know while debugging.
ovm_configuration_3.tar
Browse the code in ovm_configuration_3.tar
Log file
When print_config_settings method is called
ovm_test_top.t_env.ag1.drv
ovm_test_top.*.ag1.* int_cfg int 32
ovm_test_top.t_env.ag1.drv.rsp_port
ovm_test_top.*.ag?.* str_cfg string pars
ovm_test_top.t_env.ag1.drv.rsp_port
ovm_test_top.*.ag1.* int_cfg int 32
ovm_test_top.t_env.ag1.drv.sqr_pull_port
ovm_test_top.*.ag?.* str_cfg string pars
ovm_test_top.t_env.ag1.drv.sqr_pull_port
ovm_test_top.*.ag1.* int_cfg int 32
Search ✔
Verilog Phase 6) We will develop receiver class. Receiver collects the packets coming from
the output port of the DUT.
Verification
Verilog Switch TB Phase 7) We will develop scoreboard class which does the comparison of the
Basic Constructs expected packet with the actual packet received from the DUT.
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet Format:
OpenVera
Constructs Packet contains 3 parts. They are Header, data and frame check sequence.
Packet width is 8 bits and the length of the packet can be between 4 bytes to 259
Switch TB bytes.
RVM Switch TB
RVM Ethernet sample
Packet Header:
Configuration:
Switch has four output ports. These output ports address have to be configured to a
unique address. Switch matches the DA field of the packet with this configured port
address and sends the packet on to that port. Switch contains a memory. This
memory has 4 locations, each can store 8 bits. To configure the switch port address,
memory write operation has to be done using memory interface. Memory address
(0,1,2,3) contains the address of port(0,1,2,3) respectively.
Interface Specification:
The Switch has one input Interface, from where the packet enters and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured. Switch also has a clock and asynchronous reset
signal.
Memory Interface:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively.
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
All the signals are active high and are synchronous to the positive edge of clock
signal.
To configure a port address,
1. Assert the mem_en signal.
Input Port
Output Port
Switch sends the packets out using the output ports. There are 4 ports, each having
data, ready and read signals. All the signals are active high and are synchronous to
the positive edge of clock signal.
Signal list is
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
When the data is ready to be sent out from the port, switch asserts ready_* signal
high indicating that data is ready to be sent.
If the read_* signal is asserted, when ready_* is high, then the data comes out of the
port_* signal after one clock cycle.
RTL code:
RTL code is attached with the tar files. From the Phase 1, you can download the tar
files.
Search ✔
Coverage Plan
Specman E
Interview Questions 1) Cover all the port address configurations.
2) Cover all the packet lengths.
3) Cover all correct and incorrect length fields.
4) Cover good and bad FCS.
5) Cover all the above combinations.
Verification Environment
Search ✔
endinterface
////////////////////////////////////////////
// Interface for the input side of switch.//
// Reset signal is also passed hear. //
////////////////////////////////////////////
interface input_interface(input bit clock);
logic data_status;
logic [7:0] data_in;
logic reset;
clocking cb@(posedge clock);
default input #1 output #1;
output data_status;
output data_in;
endclocking
modport IP(clocking cb,output reset,input clock);
endinterface
/////////////////////////////////////////////////
// Interface for the output side of the switch.//
// output_interface is for only one output port//
/////////////////////////////////////////////////
interface output_interface(input bit clock);
logic [7:0] data_out;
logic ready;
logic read;
clocking cb@(posedge clock);
default input #1 output #1;
input data_out;
input ready;
output read;
endclocking
modport OP(clocking cb,input clock);
endinterface
//////////////////////////////////////////////////
`endif
Testcase
Testcase is a program block which provides an entry point for the test and creates a
scope that encapsulates program-wide data. Currently this is an empty testcase which
just ends the simulation after 100 time units. Program block contains all the above
declared interfaces as arguments. This testcase has initial and final blocks.
`ifndef GUARD_TESTCASE
`define GUARD_TESTCASE
program testcase(mem_interface.MEM mem_intf,input_interface.IP input_intf,output_interface.OP output_intf[4
]);
initial
begin
$display(" ******************* Start of testcase ****************");
#1000;
end
final
$display(" ******************** End of testcase *****************");
endprogram
`endif
Top Module
The modules that are included in the source text but are not instantiated are called
top modules. This module is the highest scope of modules. Generally this module is
named as "top" and referenced as "top module". Module name can be anything.
bit Clock;
initial
forever #10 Clock = ~Clock;
mem_interface mem_intf(Clock);
input_interface input_intf(Clock);
output_interface output_intf[4](Clock);
5)Do the instance of testcase and pass all the above declared interfaces.
testcase TC (mem_intf,input_intf,output_intf);
switch DUT (.
7)Connect all the interfaces and DUT. The design which we have taken is in
verilog. So Verilog DUT instance is connected signal by signal.
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
`ifndef GUARD_TOP
`define GUARD_TOP
module top();
/////////////////////////////////////////////////////
// Clock Declaration and Generation //
/////////////////////////////////////////////////////
bit Clock;
initial
forever #10 Clock = ~Clock;
/////////////////////////////////////////////////////
// Memory interface instance //
/////////////////////////////////////////////////////
mem_interface mem_intf(Clock);
/////////////////////////////////////////////////////
// Input interface instance //
/////////////////////////////////////////////////////
input_interface input_intf(Clock);
/////////////////////////////////////////////////////
// output interface instance //
/////////////////////////////////////////////////////
output_interface output_intf[4](Clock);
/////////////////////////////////////////////////////
// Program block Testcase instance //
/////////////////////////////////////////////////////
testcase TC (mem_intf,input_intf,output_intf);
/////////////////////////////////////////////////////
// DUT instance and signal connection //
/////////////////////////////////////////////////////
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
endmodule
`endif
switch_1.tar
Browse the code in switch_1.tar
Search ✔
Following are the methods which are going to be defined in environment class.
Verilog
1) new() : In constructor method, we will connect the virtual interfaces which are
Verification passed as argument to the virtual interfaces to those which are declared in
Verilog Switch TB environment class.
Basic Constructs 2) build(): In this method , all the objects like driver, monitor etc are constructed.
Currently this method is empty as we did not develop any other component.
8) run(): This method calls all the above declared methods in a sequence order. The
testcase calls this method, to start the simulation.
We are not implementing build(), reset(), cfg_dut() , strat() and report() methods in
this phase.
top module.
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
function new(virtual mem_interface.MEM mem_intf_new ,
virtual input_interface.IP input_intf_new ,
virtual output_interface.OP output_intf_new[4] );
In constructor methods, the interfaces which are arguments are connected to the
virtual interfaces of environment class.
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
Run :
The run() method is called from the testcase to start the simulation. run() method
calls all the methods which are defined in the Environment class.
task run();
$display(" %0d : Environment : start of run() method",$time);
build();
reset();
cfg_dut();
start();
wait_for_end();
report();
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment ;
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
function new(virtual mem_interface.MEM mem_intf_new ,
virtual input_interface.IP input_intf_new ,
virtual output_interface.OP output_intf_new[4] );
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
$display(" %0d : Environment : created env object",$time);
endfunction : new
function void build();
$display(" %0d : Environment : start of build() method",$time);
$display(" %0d : Environment : end of build() method",$time);
endfunction :build
task reset();
$display(" %0d : Environment : start of reset() method",$time);
$display(" %0d : Environment : end of reset() method",$time);
endtask : reset
task cfg_dut();
$display(" %0d : Environment : start of cfg_dut() method",$time);
$display(" %0d : Environment : end of cfg_dut() method",$time);
endtask : cfg_dut
task start();
$display(" %0d : Environment : start of start() method",$time);
$display(" %0d : Environment : end of start() method",$time);
endtask : start
task wait_for_end();
task run();
$display(" %0d : Environment : start of run() method",$time);
build();
reset();
cfg_dut();
start();
wait_for_end();
report();
$display(" %0d : Environment : end of run() method",$time);
endtask : run
task report();
endtask : report
endclass
`endif
We will create a file Global.sv for global requirement. In this file, define all the port
address as macros in this file. Define a variable error as integer to keep track the
number of errors occurred during the simulation.
`ifndef GUARD_GLOBALS
`define GUARD_GLOBALS
`define P0 8'h00
`define P1 8'h11
`define P2 8'h22
`define P3 8'h33
int error = 0;
int num_of_pkts = 10;
`endif
Now we will update the testcase. Take an instance of the Environment class and call
the run method of the Environment class.
`ifndef GUARD_TESTCASE
`define GUARD_TESTCASE
Environment env;
initial
begin
$display(" ******************* Start of testcase ****************");
env = new(mem_intf,input_intf,output_intf);
env.run();
#1000;
end
final
$display(" ******************** End of testcase *****************");
endprogram
`endif
switch_2.tar
Browse the code in switch_2.tar
Search ✔
mem_intf.cb.mem_data <= 0;
OpenVera mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_en <= 0;
Constructs
mem_intf.cb.mem_rd_wr <= 0;
Switch TB input_intf.cb.data_in <= 0;
input_intf.cb.data_status <= 0;
RVM Switch TB
output_intf[0].cb.read <= 0;
RVM Ethernet sample output_intf[1].cb.read <= 0;
output_intf[2].cb.read <= 0;
output_intf[3].cb.read <= 0;
Specman E
Interview Questions 2) Reset the DUT.
task cfg_dut();
task wait_for_end();
$display(" %0d : Environment : start of wait_for_end() method",$time);
repeat(10000) @(input_intf.clock);
$display(" %0d : Environment : end of wait_for_end() method",$time);
endtask : wait_for_end
switch_3.tar
Browse the code in switch_3.tar
Search ✔
rand bit [7:0] length;
OpenVera rand bit [7:0] da;
Constructs rand bit [7:0] sa;
Switch TB rand byte data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;
RVM Switch TB
RVM Ethernet sample 5) Constraint the DA field to be any one of the configured address.
constraint address_c { da inside {`P0,`P1,`P2,`P3} ; }
Specman E 6) Constrain the payload dynamic array size to between 1 to 255.
Interview Questions
constraint payload_size_c { data.size inside { [1 : 255]};}
7) Constrain the payload length to the length field based on the length type.
constraint length_kind_c {
(length_kind == GOOD_LENGTH) -> length == data.size;
(length_kind == BAD_LENGTH) -> length == data.size + 2 ; }
Use solve before to direct the randomization to generate first the payload dynamic
constraint solve_size_length { solve data.size before length; }
8) Constrain the FCS field initial value based on the fcs kind field.
constraint fcs_kind_c {
(fcs_kind == GOOD_FCS) -> fcs == 8'b0;
(fcs_kind == BAD_FCS) -> fcs == 8'b1; }
function byte cal_fcs;
integer i;
byte result ;
result = 0;
result = result ^ da;
result = result ^ sa;
result = result ^ length;
for (i = 0;i< data.size;i++)
result = result ^ data[i];
result = fcs ^ result;
return result;
endfunction : cal_fcs
virtual function void display();
$display("\n---------------------- PACKET KIND ------------------------- ");
$display(" fcs_kind : %s ",fcs_kind.name() );
$display(" length_kind : %s ",length_kind.name() );
$display("-------- PACKET ---------- ");
$display(" 0 : %h ",da);
$display(" 1 : %h ",sa);
$display(" 2 : %h ",length);
foreach(data[i])
$write("%3d : %0h ",i + 3,data[i]);
$display("\n %2d : %h ",data.size() + 3 , cal_fcs);
$display("----------------------------------------------------------- \n");
endfunction : display
Packing is commonly used to convert the high level data to low level data that can be
applied to DUT. In packet class various fields are generated. Required fields are
concatenated to form a stream of bytes which can be driven conveniently to DUT
interface by the driver.
virtual function int unsigned byte_pack(ref logic [7:0] bytes[]);
bytes = new[data.size + 4];
bytes[0] = da;
bytes[1] = sa;
bytes[2] = length;
foreach(data[i])
bytes[3 + i] = data[i];
bytes[data.size() + 3] = cal_fcs;
byte_pack = bytes.size;
endfunction : byte_pack
The unpack() method does exactly the opposite of pack method. Unpacking is
commonly used to convert a data stream coming from DUT to high level data packet
object.
virtual function void byte_unpack(const ref logic [7:0] bytes[]);
this.da = bytes[0];
this.sa = bytes[1];
this.length = bytes[2];
this.fcs = bytes[bytes.size - 1];
this.data = new[bytes.size - 4];
foreach(data[i])
data[i] = bytes[i + 3];
this.fcs = 0;
if(bytes[bytes.size - 1] != cal_fcs)
this.fcs = 1;
endfunction : byte_unpack
virtual function bit compare(packet pkt);
compare = 1;
if(pkt == null)
begin
$display(" ** ERROR ** : pkt : received a null object ");
compare = 0;
end
else
begin
if(pkt.da !== this.da)
begin
$display(" ** ERROR **: pkt : Da field did not match");
compare = 0;
end
if(pkt.sa !== this.sa)
begin
$display(" ** ERROR **: pkt : Sa field did not match");
compare = 0;
end
`ifndef GUARD_PACKET
`define GUARD_PACKET
class packet;
rand fcs_kind_t fcs_kind;
rand length_kind_t length_kind;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand byte data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 255]};}
constraint length_kind_c {
(length_kind == GOOD_LENGTH) -> length == data.size;
(length_kind == BAD_LENGTH) -> length == data.size + 2 ; }
constraint solve_size_length { solve data.size before length; }
constraint fcs_kind_c {
(fcs_kind == GOOD_FCS) -> fcs == 8'b0;
(fcs_kind == BAD_FCS) -> fcs == 8'b1; }
foreach(data[i])
$write("%3d : %0h ",i + 3,data[i]);
$display("\n %2d : %h ",data.size() + 3 , cal_fcs);
$display("----------------------------------------------------------- \n");
endfunction : display
endclass
Now we will write a small program to test our packet implantation. This program
block is not used to verify the DUT.
Write a simple program block and do the instance of packet class. Randomize the
packet and call the display method to analyze the generation. Then pack the packet
in to bytes and then unpack bytes and then call compare method to check all the
methods.
program test;
end
else
$display(" *** Randomization Failed ***");
endprogram
switch_4.tar
Browse the code in switch_4.tar
Randomization Sucessesfull.
80 165 : 2b 166 : f0 167 : ba 168 : 4a 169 : a9 170 : 7f 171 : 13 172 : 1e 173 : 12 174
: a8 175 : 2 176 : 3 177 : 3d 178 : 71 179 : e6 180 : 96 181 : 89 182 : c6 183 : 46 184
: d6 185 : 1b 186 : 5f 187 : 20 188 : a0 189 : a3 190 : 49 191 : 79 192 : 9
193 : 53
-----------------------------------------------------------
..............
..............
..............
Search ✔
Verilog
Verification
Verilog Switch TB 1) Declare a packet.
Basic Constructs packet gpkt;
2) Declare a virtual input_interface of the switch. We will connect this to the Physical
OpenVera interface of the top module same as what we did in environment class.
Constructs
virtual input_interface.IP input_intf;
Switch TB
RVM Switch TB 3) Define a mailbox "drvr2sb" which is used to send the packets to the score board.
RVM Ethernet sample mailbox drvr2sb;
4) Define new constructor with arguments, virtual input interface and a mail box
Specman E which is used to send packets from the driver to scoreboard.
Interview Questions function new(virtual input_interface.IP input_intf_new,mailbox drvr2sb);
this.input_intf = input_intf_new ;
if(drvr2sb == null)
begin
$display(" **ERROR**: drvr2sb is null");
$finish;
end
else
this.drvr2sb = drvr2sb;
gpkt = new();
repeat($root.num_of_pkts)
if ( pkt.randomize())
begin
$display (" %0d : Driver : Randomization Successes full.",$time);
...........
...........
else
begin
$display (" %0d Driver : ** Randomization failed. **",$time);
............
...........
pkt.display();
length = pkt.byte_pack(bytes);
Then send the packet byte in to the switch by asserting data_status of the input
interface signal and driving the data bytes on to the data_in signal.
foreach(bytes[i])
begin
@(posedge input_intf.clock);
input_intf.cb.data_status <= 1;
input_intf.cb.data_in <= bytes[i];
end
After driving all the data bytes, deassert data_status signal of the input interface.
@(posedge input_intf.clock);
input_intf.cb.data_status <= 0;
input_intf.cb.data_in <= 0;
drvr2sb.put(pkt);
If randomization fails, increment the error counter which is defined in Globals.sv file
$root.error++;
`ifndef GUARD_DRIVER
`define GUARD_DRIVER
class Driver;
virtual input_interface.IP input_intf;
mailbox drvr2sb;
packet gpkt;
this.input_intf = input_intf_new ;
if(drvr2sb == null)
begin
$display(" **ERROR**: drvr2sb is null");
$finish;
end
else
this.drvr2sb = drvr2sb;
gpkt = new();
endfunction : new
endclass
`endif
Now we will take the instance of the driver in the environment class.
1) Declare a mailbox "drvr2sb" which will be used to connect the scoreboard and
driver.
mailbox drvr2sb;
Driver drvr;
drvr2sb = new();
4) In build method, construct the driver object. Pass the input_intf and "drvr2sb" mail
box.
drvr= new(input_intf,drvr2sb);
5) To start sending the packets to the DUT, call the start method of "drvr" in the start
method of Environment class.
drvr.start();
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment ;
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Driver drvr;
mailbox drvr2sb;
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
drvr2sb = new();
drvr= new(input_intf,drvr2sb);
task reset();
$display(" %0d : Environment : start of reset() method",$time);
// Drive all DUT inputs to a known state
mem_intf.cb.mem_data <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_en <= 0;
mem_intf.cb.mem_rd_wr <= 0;
input_intf.cb.data_in <= 0;
input_intf.cb.data_status <= 0;
output_intf[0].cb.read <= 0;
output_intf[1].cb.read <= 0;
output_intf[2].cb.read <= 0;
output_intf[3].cb.read <= 0;
// Reset the DUT
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
$display(" %0d : Environment : end of reset() method",$time);
endtask : reset
task cfg_dut();
$display(" %0d : Environment : start of cfg_dut() method",$time);
mem_intf.cb.mem_en <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h0;
mem_intf.cb.mem_data <= `P0;
$display(" %0d : Environment : Port 0 Address %h ",$time,`P0);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h1;
mem_intf.cb.mem_data <= `P1;
$display(" %0d : Environment : Port 1 Address %h ",$time,`P1);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h2;
mem_intf.cb.mem_data <= `P2;
$display(" %0d : Environment : Port 2 Address %h ",$time,`P2);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h3;
mem_intf.cb.mem_data <= `P3;
$display(" %0d : Environment : Port 3 Address %h ",$time,`P3);
@(posedge mem_intf.clock);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
$display(" %0d : Environment : end of cfg_dut() method",$time);
endtask :cfg_dut
task start();
$display(" %0d : Environment : start of start() method",$time);
drvr.start();
task wait_for_end();
$display(" %0d : Environment : start of wait_for_end() method",$time);
repeat(10000) @(input_intf.clock);
$display(" %0d : Environment : end of wait_for_end() method",$time);
endtask : wait_for_end
task run();
$display(" %0d : Environment : start of run() method",$time);
build();
reset();
cfg_dut();
start();
wait_for_end();
report();
$display(" %0d : Environment : end of run() method",$time);
endtask : run
task report();
endtask : report
endclass
`endif
switch_5.tar
Browse the code in switch_5.tar
..................
..................
..................
Search ✔
Verilog
Verification
Verilog Switch TB
1) Declare a virtual output_interface. We will connect this to the Physical interface of
Basic Constructs the top module, same as what we did in environment class.
virtual output_interface.OP output_intf;
OpenVera
2) Declare a mailbox "rcvr2sb" which is used to send the packets to the score board
Constructs
Switch TB mailbox rcvr2sb;
RVM Switch TB
3) Define new constructor with arguments, virtual input interface and a mail box
RVM Ethernet sample which is used to send packets from the receiver to scoreboard.
function new(virtual output_interface.OP output_intf_new,mailbox rcvr2sb);
Specman E this.output_intf = output_intf_new ;
if(rcvr2sb == null)
Interview Questions begin
$display(" **ERROR**: rcvr2sb is null");
$finish;
end
else
this.rcvr2sb = rcvr2sb;
endfunction : new
wait(output_intf.cb.ready)
If the ready signal is asserted, then request the DUT to send the data out from the
data_out signal by asserting the read signal. When the data to be sent is finished by
the DUT, it will deassert the ready signal. Once the ready signal is deasserted, stop
collecting the data bytes and deasseart the read signal.
output_intf.cb.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin
bytes = new[bytes.size + 1](bytes);
bytes[bytes.size - 1] = output_intf.cb.data_out;
@(posedge output_intf.clock);
end
output_intf.cb.read <= 0;
@(posedge output_intf.clock);
$display(" %0d : Receiver : Received a packet of length %0d",$time,bytes.size);
pkt = new();
Then call the unpack method of the packet to unpacked the bytes and then display
the packet content.
pkt.byte_unpack(bytes);
pkt.display();
rcvr2sb.put(pkt);
bytes.delete();
class Receiver;
virtual output_interface.OP output_intf;
mailbox rcvr2sb;
task start();
logic [7:0] bytes[];
packet pkt;
forever
begin
repeat(2) @(posedge output_intf.clock);
wait(output_intf.cb.ready)
output_intf.cb.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin
bytes = new[bytes.size + 1](bytes);
bytes[bytes.size - 1] = output_intf.cb.data_out;
@(posedge output_intf.clock);
end
output_intf.cb.read <= 0;
@(posedge output_intf.clock);
$display(" %0d : Receiver : Received a packet of length %0d",$time,bytes.size);
pkt = new();
pkt.byte_unpack(bytes);
pkt.display();
rcvr2sb.put(pkt);
bytes.delete();
end
endtask : start
endclass
`endif
Now we will take the instance of the receiver in the environment class.
1) Declare a mailbox "rcvr2sb" which will be used to connect the scoreboard and
receiver.
mailbox rcvr2sb;
Receiver rcvr[4];
rcvr2sb = new();
4) In build method, construct the receiver object. Pass the output_intf and "rcvr2sb"
mail box. There are 4 output interfaces and receiver objects. We will connect one
receiver for one output interface.
foreach(rcvr[i])
rcvr[i]= new(output_intf[i],rcvr2sb);
5) To start collecting the packets from the DUT, call the "start" method of "rcvr" in the
"start" method of Environment class.
task start();
$display(" %0d : Environment : start of start() method",$time);
fork
drvr.start();
rcvr[0].start();
rcvr[1].start();
rcvr[2].start();
rcvr[3].start();
join_any
$display(" %0d : Environment : end of start() method",$time);
endtask : start
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment ;
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Driver drvr;
Receiver rcvr[4];
mailbox drvr2sb;
mailbox rcvr2sb;
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
$display(" %0d : Environment : created env object",$time);
endfunction : new
rcvr2sb = new();
drvr= new(input_intf,drvr2sb);
foreach(rcvr[i])
rcvr[i]= new(output_intf[i],rcvr2sb);
task reset();
$display(" %0d : Environment : start of reset() method",$time);
// Drive all DUT inputs to a known state
mem_intf.cb.mem_data <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_en <= 0;
mem_intf.cb.mem_rd_wr <= 0;
input_intf.cb.data_in <= 0;
input_intf.cb.data_status <= 0;
output_intf[0].cb.read <= 0;
output_intf[1].cb.read <= 0;
output_intf[2].cb.read <= 0;
output_intf[3].cb.read <= 0;
// Reset the DUT
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
$display(" %0d : Environment : end of reset() method",$time);
endtask : reset
task cfg_dut();
$display(" %0d : Environment : start of cfg_dut() method",$time);
mem_intf.cb.mem_en <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h0;
mem_intf.cb.mem_data <= `P0;
$display(" %0d : Environment : Port 0 Address %h ",$time,`P0);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h1;
mem_intf.cb.mem_data <= `P1;
$display(" %0d : Environment : Port 1 Address %h ",$time,`P1);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h2;
mem_intf.cb.mem_data <= `P2;
$display(" %0d : Environment : Port 2 Address %h ",$time,`P2);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h3;
mem_intf.cb.mem_data <= `P3;
$display(" %0d : Environment : Port 3 Address %h ",$time,`P3);
@(posedge mem_intf.clock);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
$display(" %0d : Environment : end of cfg_dut() method",$time);
endtask :cfg_dut
task start();
$display(" %0d : Environment : start of start() method",$time);
fork
drvr.start();
rcvr[0].start();
rcvr[1].start();
rcvr[2].start();
rcvr[3].start();
join_any
$display(" %0d : Environment : end of start() method",$time);
endtask : start
task wait_for_end();
$display(" %0d : Environment : start of wait_for_end() method",$time);
repeat(10000) @(input_intf.clock);
$display(" %0d : Environment : end of wait_for_end() method",$time);
endtask : wait_for_end
task run();
$display(" %0d : Environment : start of run() method",$time);
build();
reset();
cfg_dut();
start();
wait_for_end();
report();
$display(" %0d : Environment : end of run() method",$time);
endtask : run
task report();
endtask: report
endclass
`endif
switch_6.tar
Browse the code in switch_6.tar
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs 1) Declare 2 mailboxes drvr2sb and rcvr2sb.
mailbox drvr2sb;
OpenVera mailbox rcvr2sb;
Constructs
2) Declare a constructor method with "drvr2sb" and "rcvr2sb" mailboxes as arguments.
Switch TB
RVM Switch TB function new(mailbox drvr2sb,mailbox rcvr2sb);
RVM Ethernet sample 3) Connect the mailboxes of the constructor to the mail boxes of the scoreboard.
this.drvr2sb = drvr2sb;
Specman E this.rcvr2sb = rcvr2sb;
Interview Questions 4) Define a start method.
Do the following steps forever.
Wait until there is a packet is in "rcvr2sb". Then pop the packet from the mail box.
rcvr2sb.get(pkt_rcv);
$display(" %0d : Scorebooard : Scoreboard received a packet from receiver ",$time);
drvr2sb.get(pkt_exp);
Compare both packets and increment an error counter if they are not equal.
if(pkt_rcv.compare(pkt_exp))
$display(" %0d : Scoreboardd :Packet Matched ",$time);
else
$root.error++;
`ifndef GUARD_SCOREBOARD
`define GUARD_SCOREBOARD
class Scoreboard;
mailbox drvr2sb;
mailbox rcvr2sb;
function new(mailbox drvr2sb,mailbox rcvr2sb);
this.drvr2sb = drvr2sb;
this.rcvr2sb = rcvr2sb;
endfunction:new
task start();
packet pkt_rcv,pkt_exp;
forever
begin
rcvr2sb.get(pkt_rcv);
$display(" %0d : Scorebooard : Scoreboard received a packet from receiver
",$time);
drvr2sb.get(pkt_exp);
if(pkt_rcv.compare(pkt_exp))
$display(" %0d : Scoreboardd :Packet Matched ",$time);
else
$root.error++;
end
endtask : start
endclass
`endif
Now we will see how to connect the scoreboard in the Environment class.
1) Declare a scoreboard.
Scoreboard sb;
2) Construct the scoreboard in the build method. Pass the drvr2sb and rcvr2sb
mailboxes to the score board constructor.
sb = new(drvr2sb,rcvr2sb);
sb.start();
task report();
$display("\n\n*************************************************");
if( 0 == $root.error)
$display("******** TEST PASSED *********");
else
$display("******** TEST Failed with %0d errors *********",$root.error);
$display("*************************************************\n\n");
endtask : report
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment ;
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Driver drvr;
Receiver rcvr[4];
Scoreboard sb;
mailbox drvr2sb ;
mailbox rcvr2sb ;
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
sb = new(drvr2sb,rcvr2sb);
drvr= new(input_intf,drvr2sb);
foreach(rcvr[i])
rcvr[i]= new(output_intf[i],rcvr2sb);
$display(" %0d : Environment : end of build() method",$time);
endfunction : build
task reset();
$display(" %0d : Environment : start of reset() method",$time);
// Drive all DUT inputs to a known state
mem_intf.cb.mem_data <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_en <= 0;
mem_intf.cb.mem_rd_wr <= 0;
input_intf.cb.data_in <= 0;
input_intf.cb.data_status <= 0;
output_intf[0].cb.read <= 0;
output_intf[1].cb.read <= 0;
output_intf[2].cb.read <= 0;
output_intf[3].cb.read <= 0;
// Reset the DUT
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
$display(" %0d : Environment : end of reset() method",$time);
endtask : reset
task cfg_dut();
$display(" %0d : Environment : start of cfg_dut() method",$time);
mem_intf.cb.mem_en <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h0;
mem_intf.cb.mem_data <= `P0;
$display(" %0d : Environment : Port 0 Address %h ",$time,`P0);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h1;
mem_intf.cb.mem_data <= `P1;
$display(" %0d : Environment : Port 1 Address %h ",$time,`P1);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h2;
mem_intf.cb.mem_data <= `P2;
$display(" %0d : Environment : Port 2 Address %h ",$time,`P2);
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h3;
mem_intf.cb.mem_data <= `P3;
$display(" %0d : Environment : Port 3 Address %h ",$time,`P3);
@(posedge mem_intf.clock);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
$display(" %0d : Environment : end of cfg_dut() method",$time);
endtask :cfg_dut
task start();
$display(" %0d : Environment : start of start() method",$time);
fork
drvr.start();
rcvr[0].start();
rcvr[1].start();
rcvr[2].start();
rcvr[3].start();
sb.start();
join_any
$display(" %0d : Environment : end of start() method",$time);
endtask : start
task wait_for_end();
$display(" %0d : Environment : start of wait_for_end() method",$time);
repeat(10000) @(input_intf.clock);
$display(" %0d : Environment : end of wait_for_end() method",$time);
endtask : wait_for_end
task run();
$display(" %0d : Environment : start of run() method",$time);
build();
reset();
cfg_dut();
start();
wait_for_end();
report();
$display(" %0d : Environment : end of run() method",$time);
endtask: run
task report();
$display("\n\n*************************************************");
if( 0 == $root.error)
$display("******** TEST PASSED *********");
else
$display("******** TEST Failed with %0d errors *********",$root.error);
$display("*************************************************\n\n");
endtask : report
endclass
`endif
switch_7.tar
Browse the code in switch_7.tar
Search ✔
`ifndef GUARD_COVERAGE
`define GUARD_COVERAGE
class coverage;
packet pkt;
covergroup switch_coverage;
length : coverpoint pkt.length;
da : coverpoint pkt.da {
bins p0 = { `P0 };
bins p1 = { `P1 };
bins p2 = { `P2 };
bins p3 = { `P3 }; }
length_kind : coverpoint pkt.length_kind;
fcs_kind : coverpoint pkt.fcs_kind;
all_cross: cross length,da,length_kind,fcs_kind;
endgroup
function new();
switch_coverage = new();
endfunction : new
task sample(packet pkt);
this.pkt = pkt;
switch_coverage.sample();
endtask:sample
endclass
`endif
2) Call the sample method and pass the exp_pkt to the sample method.
cov.sample(pkt_exp);
`ifndef GUARD_SCOREBOARD
`define GUARD_SCOREBOARD
class Scoreboard;
mailbox drvr2sb;
mailbox rcvr2sb;
task start();
packet pkt_rcv,pkt_exp;
forever
begin
rcvr2sb.get(pkt_rcv);
$display(" %0d : Scorebooard : Scoreboard received a packet from receiver ",$time);
drvr2sb.get(pkt_exp);
if(pkt_rcv.compare(pkt_exp))
begin
cov.sample(pkt_exp);
end
else
$root.error++;
end
endtask : start
endclass
`endif
switch_8.tar
Browse the code in switch_8.tar
Search ✔
Verilog env.reset();
Verification env.cfg_dut();
env.start();
Verilog Switch TB env.wait_for_end();
Basic Constructs env.report();
constraint small_c { data.size > 200 ; }
Specman E endclass
Interview Questions
program testcase(mem_interface.MEM mem_intf,input_interface.IP input_intf,output_interface.OP output_intf[4
]);
Environment env;
small_packet spkt;
initial
begin
$display(" ******************* Start of testcase ****************");
spkt = new();
env = new(mem_intf,input_intf,output_intf);
env.build();
env.drvr.gpkt = spkt;
env.reset();
env.cfg_dut();
env.start();
env.wait_for_end();
env.report();
#1000;
end
final
$display(" ******************** End of testcase *****************");
endprogram
`endif
switch_9.tar
Browse the code in switch_9.tar
Search ✔
OpenVera
Constructs Installing Uvm Library
Switch TB
RVM Switch TB
RVM Ethernet sample 1)Go to http://www.accellera.org/activities/vip/
2)Download the uvm*.tar.gz file.
3)Untar the file.
4)Go to the extracted directory : cd uvm*\uvm\src
Specman E 5)Set the UVM_HOME path : setenv UVM_HOME `pwd`
Interview Questions (This is required to run the examples which are downloaded from this site)
6)Go to examples : cd ../examples/hello_world/uvm/
7)Compile the example using :
your_tool_compilation_command -f compile_<toolname>.f
(example for questasim use : qverilog -f compile_questa.f)
8)Run the example.
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet Format:
OpenVera
Constructs Packet contains 3 parts. They are Header, data and frame check sequence.
Packet width is 8 bits and the length of the packet can be between 4 bytes to 259
Switch TB bytes.
RVM Switch TB
RVM Ethernet sample
Packet header:
Length: Length of the data is of 8 bits and from 0 to 255. Length is measured in
terms of bytes.
If Length = 0, it means data length is 0 bytes
If Length = 1, it means data length is 1 bytes
Configuration:
Switch has four output ports. These output ports address have to be configured to a
unique address. Switch matches the DA field of the packet with this configured port
address and sends the packet on to that port. Switch contains a memory. This
memory has 4 locations, each can store 8 bits. To configure the switch port address,
memory write operation has to be done using memory interface. Memory address
(0,1,2,3) contains the address of port(0,1,2,3) respectively.
Interface Specification:
The Switch has one input Interface, from where the packet enters and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured. Switch also has a clock and asynchronous reset
signal.
MEMORY INTERFACE:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively.
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
All the signals are active high and are synchronous to the positive edge of clock
signal.
To configure a port address,
INPUT PORT
OUTPUT PORT
Switch sends the packets out using the output ports. There are 4 ports, each having
data, ready and read signals. All the signals are active high and are synchronous to
the positive edge of clock signal.
Signal list is
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
When the data is ready to be sent out from the port, switch asserts ready_* signal
high indicating that data is ready to be sent.
If the read_* signal is asserted, when ready_* is high, then the data comes out of the
port_* signal after one clock cycle.
RTL code:
RTL code is attached with the tar files. From the Phase 1, you can download the tar
files.
Search ✔
Verilog 5)
Verification ID: FCS
Description:
Verilog Switch TB Good FCS: Send packet with good FCS.
Basic Constructs Bad FCS: Send packet with corrupted FCS.
Verification Environment
Specman E
Interview Questions
Search ✔
interface mem_interface(input bit clock);
OpenVera parameter setup_time = 5ns;
Constructs parameter hold_time = 3ns;
Switch TB
wire [7:0] mem_data;
RVM Switch TB wire [1:0] mem_add;
RVM Ethernet sample wire mem_en;
wire mem_rd_wr;
clocking cb@(posedge clock);
Specman E default input #setup_time output #hold_time;
Interview Questions output mem_data;
output mem_add;
output mem_en;
output mem_rd_wr;
endclocking:cb
modport MEM(clocking cb,input clock);
endinterface :mem_interface
////////////////////////////////////////////
parameter setup_time = 5ns;
parameter hold_time = 3ns;
wire data_status;
wire [7:0] data_in;
reg reset;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
output data_status;
output data_in;
endclocking:cb
modport IP(clocking cb,output reset,input clock);
endinterface:input_interface
/////////////////////////////////////////////////
// Interface for the output side of the switch.//
// output_interface is for only one output port//
/////////////////////////////////////////////////
interface output_interface(input bit clock);
parameter setup_time = 5ns;
parameter hold_time = 3ns;
wire [7:0] data_out;
wire ready;
wire read;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
input data_out;
input ready;
output read;
endclocking:cb
modport OP(clocking cb,input clock);
endinterface:output_interface
//////////////////////////////////////////////////
`endif
Top Module
The modules that are included in the source text but are not instantiated are called
top modules. This module is the highest scope of modules. Generally this module is
named as "top" and referenced as "top module". Module name can be anything.
This top-level module will contain the design portion of the simulation.
`include "uvm.svh"
import uvm_pkg::*;
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
mem_interface mem_intf(Clock);
input_interface input_intf(Clock);
output_interface output_intf[4](Clock);
5) Connect all the interfaces and DUT. The design which we have taken is in
verilog. So Verilog DUT instance is connected signal by signal.
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
`ifndef GUARD_TOP
`define GUARD_TOP
/////////////////////////////////////////////////////
// Importing UVM Packages //
/////////////////////////////////////////////////////
`include "uvm.svh"
import uvm_pkg::*;
module top();
/////////////////////////////////////////////////////
// Clock Declaration and Generation //
/////////////////////////////////////////////////////
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
/////////////////////////////////////////////////////
// Memory interface instance //
/////////////////////////////////////////////////////
mem_interface mem_intf(Clock);
/////////////////////////////////////////////////////
input_interface input_intf(Clock);
/////////////////////////////////////////////////////
// output interface instance //
/////////////////////////////////////////////////////
output_interface output_intf[4](Clock);
/////////////////////////////////////////////////////
// DUT instance and signal connection //
/////////////////////////////////////////////////////
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
endmodule : top
`endif
uvm_switch_1.tar
Browse the code in uvm_switch_1.tar
Command to compile
Search ✔
virtual input_interface.IP input_intf;
Verilog virtual mem_interface.MEM mem_intf;
Verification virtual output_interface.OP output_intf[4];
Verilog Switch TB 3) Declare 4 variables which holds the device port address.
Basic Constructs
bit [7:0] device_add[4] ;
return t;
endfunction : create
class Configuration extends uvm_object;
virtual input_interface.IP input_intf;
virtual mem_interface.MEM mem_intf;
virtual output_interface.OP output_intf[4];
bit [7:0] device_add[4] ;
virtual function uvm_object create(string name="");
Configuration t = new();
t.device_add = this.device_add;
t.input_intf = this.input_intf;
t.mem_intf = this.mem_intf;
t.output_intf = this.output_intf;
return t;
endfunction : create
endclass : Configuration
`endif
In top module we will create an object of the above defined configuration class and
update the interfaces so that all the verification components can access to physical
interfaces in top module using configuration class object.
Configuration cfg;
initial begin
cfg = new();
cfg.input_intf = input_intf;
cfg.mem_intf = mem_intf;
cfg.output_intf = output_intf;
run_test();
module top();
/////////////////////////////////////////////////////
// Clock Declaration and Generation //
/////////////////////////////////////////////////////
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
/////////////////////////////////////////////////////
// Memory interface instance //
/////////////////////////////////////////////////////
mem_interface mem_intf(Clock);
/////////////////////////////////////////////////////
// Input interface instance //
/////////////////////////////////////////////////////
input_interface input_intf(Clock);
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
// Creat Configuration and Strart the run_test//
/////////////////////////////////////////////////////
Configuration cfg;
initial begin
cfg = new();
cfg.input_intf = input_intf;
cfg.mem_intf = mem_intf;
cfg.output_intf = output_intf;
run_test();
end
/////////////////////////////////////////////////////
// DUT instance and signal connection //
/////////////////////////////////////////////////////
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
endmodule : top
`endif
uvm_switch_2.tar
Browse the code in uvm_switch_2.tar
Command to compile
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs We will not implement all the uvm_env virtual methods in this phase but will we print
messages from these methods which are required for this example to understand the
simulation execution.
OpenVera
Testcase contains the instance of the environment class. This testcase Creates a
Constructs Environment object and defines the required test specific functionality.
Switch TB
Verification environment contains the declarations of the virtual interfaces. These
RVM Switch TB
virtual interfaces are pointed to the physical interfaces which are declared in the top
RVM Ethernet sample module. These virtual interfaces are made to point to physical interface in the
testcase.
Specman E
Environment
Interview Questions
1) Extend uvm_env class to define Environment class.
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment extends uvm_env;
endclass : Environment
`endif
2) Declare the utility macro. This utility macro provides the implementation of
create() and get_type_name() methods.
`uvm_component_utils(Environment)
3) Define the constructor. In the constructor, call the super methods and pass the
parent object. Parent is the object in which environment is instantiated.
4) Define build method. In build method, just print messages and super.build() must
be called. This method is automatically called.
Build is the first phase in simulation. This phase is used to construct the child
components of the current class.
virtual function void build();
super.build();
uvm_report_info(get_full_name(),"START of build ",UVM_LOW);
uvm_report_info(get_full_name(),"END of build ",UVM_LOW);
endfunction
virtual function void connect();
super.connect();
uvm_report_info(get_full_name(),"START of connect ",UVM_LOW);
uvm_report_info(get_full_name(),"END of connect ",UVM_LOW);
endfunction
class Environment extends uvm_env;
`uvm_component_utils(Environment)
virtual function void build();
super.build();
uvm_report_info(get_full_name(),"START of build ",UVM_LOW);
uvm_report_info(get_full_name(),"END of build ",UVM_LOW);
endfunction
virtual function void connect();
super.connect();
uvm_report_info(get_full_name(),"START of connect ",UVM_LOW);
uvm_report_info(get_full_name(),"END of connect ",UVM_LOW);
endfunction
endclass : Environment
`endif
Testcase
class test1 extends uvm_test;
endclass
`uvm_component_utils(test1)
function new (string name="test1", uvm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
As we dont have anything now to write in this testcase, just call the
global_stop_request() after some delay.
virtual task run ();
#3000ns;
global_stop_request();
endtask : run
`uvm_component_utils(test1)
function new (string name="test1", uvm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
virtual task run ();
#3000ns;
global_stop_request();
endtask : run
endclass : test1
uvm_switch_3.tar
Browse the code in uvm_switch_3.tar
Search ✔
Verilog typedef enum { GOOD_FCS, BAD_FCS } fcs_kind_t;
Verification
2) Define transaction by extending uvm_sequence_item.
Verilog Switch TB
Basic Constructs class Packet extends uvm_sequence_item;
endclass : Packet
OpenVera 3) Define all the fields as rand variables.
Constructs
Switch TB rand fcs_kind_t fcs_kind;
RVM Switch TB rand bit [7:0] length;
RVM Ethernet sample rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];
rand byte fcs;
Specman E
Interview Questions
4) Define constraints to constraint payload size of data.
constraint payload_size_c { data.size inside { [2 : 255]};}
constraint length_c { length == data.size; }
function new(string name = "");
super.new(name);
endfunction : new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
`uvm_object_utils_begin(Packet)
`uvm_field_int(da, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(sa, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(length, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_array_int(data, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(fcs, UVM_ALL_ON|UVM_NOPACK)
`uvm_object_utils_end
function void do_pack(uvm_packer packer);
super.do_pack(packer);
packer.pack_field_int(da,$bits(da));
packer.pack_field_int(sa,$bits(sa));
packer.pack_field_int(length,$bits(length));
foreach(data[i])
packer.pack_field_int(data[i],8);
packer.pack_field_int(fcs,$bits(fcs));
endfunction : do_pack
function void do_unpack(uvm_packer packer);
int sz;
super.do_pack(packer);
da = packer.unpack_field_int($bits(da));
sa = packer.unpack_field_int($bits(sa));
length = packer.unpack_field_int($bits(length));
data.delete();
data = new[length];
foreach(data[i])
data[i] = packer.unpack_field_int(8);
fcs = packer.unpack_field_int($bits(fcs));
endfunction : do_unpack
`ifndef GUARD_PACKET
`define GUARD_PACKET
`include "uvm.svh"
import uvm_pkg::*;
class Packet extends uvm_sequence_item;
rand fcs_kind_t fcs_kind;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 6]};}
constraint length_c { length == data.size; }
function new(string name = "");
super.new(name);
endfunction : new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
///// method to calculate the fcs /////
virtual function byte cal_fcs;
return da ^ sa ^ length ^ data.xor() ^ fcs;
endfunction : cal_fcs
`uvm_object_utils_begin(Packet)
`uvm_field_int(da, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(sa, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(length, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_array_int(data, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(fcs, UVM_ALL_ON|UVM_NOPACK)
`uvm_object_utils_end
function void do_pack(uvm_packer packer);
super.do_pack(packer);
packer.pack_field_int(da,$bits(da));
packer.pack_field_int(sa,$bits(sa));
packer.pack_field_int(length,$bits(length));
foreach(data[i])
packer.pack_field_int(data[i],8);
packer.pack_field_int(fcs,$bits(fcs));
endfunction : do_pack
function void do_unpack(uvm_packer packer);
int sz;
super.do_pack(packer);
da = packer.unpack_field_int($bits(da));
sa = packer.unpack_field_int($bits(sa));
length = packer.unpack_field_int($bits(length));
data.delete();
data = new[length];
foreach(data[i])
data[i] = packer.unpack_field_int(8);
fcs = packer.unpack_field_int($bits(fcs));
endfunction : do_unpack
endclass : Packet
Now we will write a small logic to test our packet implantation. This module is not
used in normal verification.
Define a module and take the instance of packet class. Randomize the packet and call
the print method to analyze the generation. Then pack the packet in to bytes and
then unpack bytes and then call compare method to check all the method
implementation.
2) In a initial block, randomize the packet, pack the packet in to pkdbytes and then
unpack it and compare the packets.
if(pkt1.randomize)
begin
$display(" Randomization Sucessesfull.");
pkt1.print();
uvm_default_packer.use_metadata = 1;
void'(pkt1.pack_bytes(pkdbytes));
$display("Size of pkd bits %d",pkdbytes.size());
pkt2.unpack_bytes(pkdbytes);
pkt2.print();
if(pkt2.compare(pkt1))
$display(" Packing,Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***
\n \n");
initial
repeat(10)
if(pkt1.randomize)
begin
$display(" Randomization Successesfull.");
pkt1.print();
uvm_default_packer.use_metadata = 1;
void'(pkt1.pack_bytes(pkdbytes));
$display("Size of pkd bits %d",pkdbytes.size());
pkt2.unpack_bytes(pkdbytes);
pkt2.print();
if(pkt2.compare(pkt1))
$display(" Packing,Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***
\n \n");
end
else
$display(" *** Randomization Failed ***");
endmodule
uvm_switch_4.tar
Browse the code in uvm_switch_4.tar
Randomization Sucessesfull.
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
pkt1 Packet - pkt1@3
--da integral 8 'ha5
--sa integral 8 'ha1
--length integral 8 'h6
--data da(integral) 6 -
----[0] integral 8 'h58
----[1] integral 8 'h60
----[2] integral 8 'h34
----[3] integral 8 'hdd
----[4] integral 8 'h9
----[5] integral 8 'haf
--fcs integral 8 'h75
----------------------------------------------------------------------
Size of pkd bits 10
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
pkt2 Packet - pkt2@5
--da integral 8 'ha5
--sa integral 8 'ha1
--length integral 8 'h6
--data da(integral) 6 -
----[0] integral 8 'h58
----[1] integral 8 'h60
----[2] integral 8 'h34
----[3] integral 8 'hdd
----[4] integral 8 'h9
----[5] integral 8 'haf
--fcs integral 8 'h75
----------------------------------------------------------------------
Packing,Unpacking and compare worked
....
....
....
....
Search ✔
`uvm_sequencer_utils(Sequencer)
function new (string name, uvm_component parent);
super.new(name, parent);
`uvm_update_sequence_lib_and_item(Packet)
endfunction : new
virtual function void end_of_elaboration();
uvm_object tmp;
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
endfunction
`ifndef GUARD_SEQUENCER
`define GUARD_SEQUENCER
endclass : Sequencer
`endif
Sequence
You can define as many sequences as you want. We will define 2 sequences.
endclass: Seq_device0_and_device1
function new(string name = "Seq_do");
super.new(name);
endfunction : new
`uvm_sequence_utils(Seq_device0_and_device1, Sequencer)
4) The algorithm for the transaction should be defined in body() method of the
sequence. In this sequence we will define the algorithm such that alternate
transactions for device port 0 and 1 are generated.
The device addresses are available in configuration object which is in sequencer.
Every sequence has a handle to its sequence through p_sequencer. Using p_sequencer
handle, access the device address.
virtual task body();
forever begin
`uvm_do_with(item, {da == p_sequencer.cfg.device_add[0];} );
`uvm_do_with(item, {da == p_sequencer.cfg.device_add[1];} );
end
endtask : body
function new(string name = "Seq_device0_and_device1");
super.new(name);
endfunction : new
Packet item;
`uvm_sequence_utils(Seq_device0_and_device1, Sequencer)
virtual task body();
forever begin
`uvm_do_with(item, {da == p_sequencer.cfg.device_add[0];} );
`uvm_do_with(item, {da == p_sequencer.cfg.device_add[1];} );
end
endtask : body
endclass :Seq_device0_and_device1
function new(string name = "Seq_constant_length");
super.new(name);
endfunction : new
Packet item;
`uvm_sequence_utils(Seq_constant_length, Sequencer)
virtual task body();
forever begin
`uvm_do_with(item, {length == 10;da == p_sequencer.cfg.device_add[0];} );
end
endtask : body
endclass : Seq_constant_length
uvm_switch_5.tar
Browse the code in uvm_switch_5.tar
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
2) Create a handle to configuration object. Using this object we can get DUT
interfaces and DUT port addresses.
Specman E
Interview Questions Configuration cfg;
`uvm_component_utils(Driver)
6) Define the constructor method. Pass the parent object to super class.
virtual function void build();
super.build();
Drvr2Sb_port = new("Drvr2Sb_port", this);
endfunction : build
virtual function void end_of_elaboration();
uvm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
this.input_intf = cfg.input_intf;
this.mem_intf = cfg.mem_intf;
endfunction : end_of_elaboration
9) Define the reset_dut() method which will be used for resetting the DUT.
virtual task reset_dut();
uvm_report_info(get_full_name(),"Start of reset_dut() method ",UVM_LOW);
mem_intf.mem_data <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_en <= 0;
mem_intf.mem_rd_wr <= 0;
input_intf.data_in <= 0;
input_intf.data_status <= 0;
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
10) Define the cfg_dut() method which does the configuration due port address.
virtual task cfg_dut();
uvm_report_info(get_full_name(),"Start of cfg_dut() method ",UVM_LOW);
mem_intf.cb.mem_en <= 1;
@(mem_intf.cb);
mem_intf.cb.mem_rd_wr <= 1;
foreach (cfg.device_add[i]) begin
@(mem_intf.cb);
mem_intf.cb.mem_add <= i;
mem_intf.cb.mem_data <= cfg.device_add[i];
uvm_report_info(get_full_name(),$psprintf(" Port %0d Address %h
",i,cfg.device_add[i]),UVM_LOW);
end
@(mem_intf.cb);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
uvm_report_info(get_full_name(),"End of cfg_dut() method ",UVM_LOW);
endtask : cfg_dut
11) Define drive() method which will be used to drive the packet to DUT. In this
method pack the packet fields using the pack_bytes() method of the transaction and
drive the packed data to DUT interface.
virtual task drive(Packet pkt);
byte unsigned bytes[];
int pkt_len;
pkt_len = pkt.pack_bytes(bytes);
uvm_report_info(get_full_name(),"Driving packet ...",UVM_LOW);
foreach(bytes[i])
begin
@(input_intf.cb);
input_intf.data_status <= 1 ;
input_intf.data_in <= bytes[i];
end
@(input_intf.cb);
input_intf.data_status <= 0 ;
input_intf.data_in <= 0;
repeat(2) @(input_intf.cb);
endtask : drive
12) Now we will use the above 3 defined methods and update the run() method of
uvm_driver.
First call the reset_dut() method and then cfg_dut(). After completing the
configuration, in a forever loop get the transaction from seq_item_port and send it
DUT using drive() method and also to scoreboard using Drvr2SB_port .
virtual task run();
Packet pkt;
@(input_intf.cb);
reset_dut();
cfg_dut();
forever begin
seq_item_port.get_next_item(pkt);
Drvr2Sb_port.write(pkt);
@(input_intf.cb);
drive(pkt);
@(input_intf.cb);
seq_item_port.item_done();
end
endtask : run
`ifndef GUARD_DRIVER
`define GUARD_DRIVER
Configuration cfg;
virtual input_interface.IP input_intf;
virtual mem_interface.MEM mem_intf;
uvm_analysis_port #(Packet) Drvr2Sb_port;
`uvm_component_utils(Driver)
function new( string name = "" , uvm_component parent = null) ;
super.new( name , parent );
endfunction : new
virtual function void build();
super.build();
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : build
virtual function void end_of_elaboration();
uvm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
this.input_intf = cfg.input_intf;
this.mem_intf = cfg.mem_intf;
endfunction : end_of_elaboration
virtual task run();
Packet pkt;
@(input_intf.cb);
reset_dut();
cfg_dut();
forever begin
seq_item_port.get_next_item(pkt);
Drvr2Sb_port.write(pkt);
@(input_intf.cb);
drive(pkt);
@(input_intf.cb);
seq_item_port.item_done();
end
endtask : run
virtual task reset_dut();
uvm_report_info(get_full_name(),"Start of reset_dut() method ",UVM_LOW);
mem_intf.mem_data <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_en <= 0;
mem_intf.mem_rd_wr <= 0;
input_intf.data_in <= 0;
input_intf.data_status <= 0;
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
uvm_report_info(get_full_name(),"End of reset_dut() method ",UVM_LOW);
endtask : reset_dut
virtual task cfg_dut();
uvm_report_info(get_full_name(),"Start of cfg_dut() method ",UVM_LOW);
mem_intf.cb.mem_en <= 1;
@(mem_intf.cb);
mem_intf.cb.mem_rd_wr <= 1;
foreach (cfg.device_add[i]) begin
@(mem_intf.cb);
mem_intf.cb.mem_add <= i;
mem_intf.cb.mem_data <= cfg.device_add[i];
uvm_report_info(get_full_name(),$psprintf(" Port %0d Address %h
",i,cfg.device_add[i]),UVM_LOW);
end
@(mem_intf.cb);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
uvm_report_info(get_full_name(),"End of cfg_dut() method ",UVM_LOW);
endtask : cfg_dut
virtual task drive(Packet pkt);
byte unsigned bytes[];
int pkt_len;
pkt_len = pkt.pack_bytes(bytes);
uvm_report_info(get_full_name(),"Driving packet ...",UVM_LOW);
foreach(bytes[i])
begin
@(input_intf.cb);
input_intf.data_status <= 1 ;
input_intf.data_in <= bytes[i];
end
@(input_intf.cb);
input_intf.data_status <= 0 ;
input_intf.data_in <= 0;
repeat(2) @(input_intf.cb);
endtask : drive
endclass : Driver
`endif
Environment Updates
We will take the instance of Sequencer and Driver and connect them in Environment
class.
2) In build method, construct Seqncr and Drvr object using create() method.
Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);
Drvr.seq_item_port.connect(Seqncr.seq_item_export);
`ifndef GUARD_ENV
`define GUARD_ENV
`uvm_component_utils(Environment)
Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);
Drvr.seq_item_port.connect(Seqncr.seq_item_export);
endclass : Environment
`endif
Testcase Updates
1)In the build() method, update the configuration address in the configuration object
which in top module.
virtual function void build();
super.build();
cfg.device_add[0] = 0;
cfg.device_add[1] = 1;
cfg.device_add[2] = 2;
cfg.device_add[3] = 3;
set_config_object("t_env.*","Configuration",cfg);
set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");
set_config_int("*.Seqncr", "count",2);
t_env.Seqncr.print();
Testcase code
`uvm_component_utils(test1)
virtual function void build();
super.build();
cfg.device_add[0] = 0;
cfg.device_add[1] = 1;
cfg.device_add[2] = 2;
cfg.device_add[3] = 3;
set_config_object("t_env.*","Configuration",cfg);
set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");
set_config_int("*.Seqncr", "count",2);
endfunction
t_env.Seqncr.print();
#3000ns;
global_stop_request();
endtask : run
endclass : test1
uvm_switch_6.tar
Browse the code in uvm_switch_6.tar
Port 3 Address 03
UVM_INFO @ 190: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
End of cfg_dut() method
UVM_INFO @ 210: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 590: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 970: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
`endif
Specman E
Interview Questions 2) Declare configuration class object.
Configuration cfg;
integer id;
virtual output_interface.OP output_intf;
5) Declare analysis port which is used by receiver to send the received transaction to
scoreboard.
uvm_analysis_port #(Packet) Rcvr2Sb_port;
6) Declare the utility macro. This utility macro provides the implementation of creat()
and get_type_name() methods.
`uvm_component_utils(Receiver)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
virtual function void build();
super.build();
Rcvr2Sb_port = new("Rcvr2Sb", this);
endfunction : build
virtual function void end_of_elaboration();
uvm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
output_intf = cfg.output_intf[id];
endfunction : end_of_elaboration
10) Define the run() method. This method collects the packets from the DUT output
interface and unpacks it into high level transaction using transactions unpack_bytes()
method.
virtual task run();
Packet pkt;
fork
forever
begin
// declare the queue and dynamic array here
// so they are automatically allocated for every packet
bit [7:0] bq[$],bytes[];
repeat(2) @(posedge output_intf.clock);
wait(output_intf.cb.ready)
output_intf.cb.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin
bq.push_back(output_intf.cb.data_out);
@(posedge output_intf.clock);
end
bytes = new[bq.size()] (bq); // Copy queue into dyn array
endtask : run
class Receiver extends uvm_component;
virtual output_interface.OP output_intf;
Configuration cfg;
integer id;
uvm_analysis_port #(Packet) Rcvr2Sb_port;
`uvm_component_utils(Receiver)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
virtual function void build();
super.build();
Rcvr2Sb_port = new("Rcvr2Sb", this);
endfunction : build
virtual function void end_of_elaboration();
uvm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
output_intf = cfg.output_intf[id];
endfunction : end_of_elaboration
virtual task run();
Packet pkt;
fork
forever
begin
// declare the queue and dynamic array here
// so they are automatically allocated for every packet
bit [7:0] bq[$],bytes[];
repeat(2) @(posedge output_intf.clock);
wait(output_intf.cb.ready)
output_intf.cb.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin
bq.push_back(output_intf.cb.data_out);
@(posedge output_intf.clock);
end
bytes = new[bq.size()] (bq); // Copy queue into dyn array
endtask : run
endclass : Receiver
We will update the Environment class and take instance of receiver and run the
testcase.
1) Declare 4 receivers.
Receiver Rcvr[4];
2) In the build() method construct the Receivers using create() methods. Also update
the id variable of the receiver object.
foreach(Rcvr[i]) begin
Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
`ifndef GUARD_ENV
`define GUARD_ENV
`uvm_component_utils(Environment)
foreach(Rcvr[i]) begin
Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
endclass : Environment
`endif
uvm_switch_7.tar
Browse the code in uvm_switch_7.tar
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
1) We need 2 import, one for expected packet which is sent by driver and received
packet which is coming from receiver.
OpenVera Declare 2 imports using `uvm_analysis_imp_decl macros should not be defined
inside the class.
Constructs
Switch TB `uvm_analysis_imp_decl(_rcvd_pkt)
`uvm_analysis_imp_decl(_sent_pkt)
RVM Switch TB
RVM Ethernet sample 2) Declare a scoreboard by extending uvm_scoreboard class.
class Scoreboard extends uvm_scoreboard;
Specman E
endclass : Scoreboard
Interview Questions
3) Declare the utility macro.
`uvm_component_utils(Scoreboard)
Packet exp_que[$];
uvm_analysis_imp_rcvd_pkt #(Packet,Scoreboard) Rcvr2Sb_port;
uvm_analysis_imp_sent_pkt #(Packet,Scoreboard) Drvr2Sb_port;
6) In the constructor, create objects for the above two declared imports.
function new(string name, uvm_component parent);
super.new(name, parent);
Rcvr2Sb_port = new("Rcvr2Sb", this);
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : new
virtual function void write_sent_pkt(input Packet pkt);
exp_que.push_back(pkt);
endfunction : write_sent_pkt
virtual function void write_rcvd_pkt(input Packet pkt);
Packet exp_pkt;
pkt.print();
if(exp_que.size())
begin
exp_pkt = exp_que.pop_front();
exp_pkt.print();
if( pkt.compare(exp_pkt))
uvm_report_info(get_type_name(),
$psprintf("Sent packet and received packet matched"), UVM_LOW);
else
uvm_report_error(get_type_name(),
$psprintf("Sent packet and received packet mismatched"), UVM_LOW);
end
else
uvm_report_error(get_type_name(),
$psprintf("No more packets in the expected queue to compare"), UVM_LOW);
endfunction : write_rcvd_pkt
virtual function void report();
uvm_report_info(get_type_name(),
$psprintf("Scoreboard Report %s", this.sprint()), UVM_LOW);
endfunction : report
`uvm_analysis_imp_decl(_rcvd_pkt)
`uvm_analysis_imp_decl(_sent_pkt)
class Scoreboard extends uvm_scoreboard;
`uvm_component_utils(Scoreboard)
Packet exp_que[$];
uvm_analysis_imp_rcvd_pkt #(Packet,Scoreboard) Rcvr2Sb_port;
uvm_analysis_imp_sent_pkt #(Packet,Scoreboard) Drvr2Sb_port;
function new(string name, uvm_component parent);
super.new(name, parent);
Rcvr2Sb_port = new("Rcvr2Sb", this);
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : new
virtual function void write_rcvd_pkt(input Packet pkt);
Packet exp_pkt;
pkt.print();
if(exp_que.size())
begin
exp_pkt = exp_que.pop_front();
exp_pkt.print();
if( pkt.compare(exp_pkt))
uvm_report_info(get_type_name(),
$psprintf("Sent packet and received packet matched"), UVM_LOW);
else
uvm_report_error(get_type_name(),
$psprintf("Sent packet and received packet mismatched"), UVM_LOW);
end
else
uvm_report_error(get_type_name(),
$psprintf("No more packets to in the expected queue to
compare"), UVM_LOW);
endfunction : write_rcvd_pkt
virtual function void write_sent_pkt(input Packet pkt);
exp_que.push_back(pkt);
endfunction : write_sent_pkt
virtual function void report();
uvm_report_info(get_type_name(),
$psprintf("Scoreboard Report %s", this.sprint()), UVM_LOW);
endfunction : report
endclass : Scoreboard
`endif
We will take the instance of scoreboard in the environment and connect its ports to
driver and receiver ports.
Sbd = Scoreboard::type_id::create("Sbd",this);
Drvr.Drvr2Sb_port.connect(Sbd.Drvr2Sb_port);
foreach(Rcvr[i])
Rcvr[i].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
`ifndef GUARD_ENV
`define GUARD_ENV
`uvm_component_utils(Environment)
Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);
foreach(Rcvr[i]) begin
Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
Sbd = Scoreboard::type_id::create("Sbd",this);
Drvr.seq_item_port.connect(Seqncr.seq_item_export);
Drvr.Drvr2Sb_port.connect(Sbd.Drvr2Sb_port);
foreach(Rcvr[i])
Rcvr[i].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
endclass : Environment
`endif
uvm_switch_8.tar
Browse the code in uvm_switch_8.tar
seq_item_export uvm_seq_item_pull_+ - seq_item_export@40
default_sequence string 19 uvm_random_sequence
count integral 32 -1
max_random_count integral 32 'd10
sequences array 5 -
[0] string 19 uvm_random_sequence
[1] string 23 uvm_exhaustive_sequ+
[2] string 19 uvm_simple_sequence
[3] string 23 Seq_device0_and_dev+
[4] string 19 Seq_constant_length
max_random_depth integral 32 'd4
num_last_reqs integral 32 'd1
num_last_rsps integral 32 'd1
----------------------------------------------------------------------
UVM_INFO @ 30: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Start of reset_dut() method
UVM_INFO @ 70: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
End of reset_dut() method
UVM_INFO @ 70: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Start of cfg_dut() method
UVM_INFO @ 110: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 0 Address 00
UVM_INFO @ 130: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 1 Address 01
UVM_INFO @ 150: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 2 Address 02
UVM_INFO @ 170: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 3 Address 03
UVM_INFO @ 190: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
End of cfg_dut() method
UVM_INFO @ 210: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 590: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 610: uvm_test_top.t_env.Rcvr0 [uvm_test_top.t_env.Rcvr0]
Received packet ...
UVM_INFO @ 610: uvm_test_top.t_env.Sbd [Scoreboard]
Sent packet and received packet matched
UVM_INFO @ 970: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 990: uvm_test_top.t_env.Rcvr0 [uvm_test_top.t_env.Rcvr0]
Received packet ...
UVM_INFO @ 990: uvm_test_top.t_env.Sbd [Scoreboard]
Sent packet and received packet matched
UVM_INFO @ 1000: uvm_test_top.t_env.Sbd [Scoreboard]
Scoreboard Report
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
Sbd Scoreboard - Sbd@52
Drvr2Sb uvm_analysis_imp_s+ - Drvr2Sb@56
Rcvr2Sb uvm_analysis_imp_r+ - Rcvr2Sb@54
----------------------------------------------------------------------
Search ✔
OpenVera I would like to thank to Vishnu Prashant(Vitesse) for teaching me OVM.
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet Format:
OpenVera
Constructs Packet contains 3 parts. They are Header, data and frame check sequence.
Packet width is 8 bits and the length of the packet can be between 4 bytes to 259
Switch TB bytes.
RVM Switch TB
RVM Ethernet sample
Packet header:
Length: Length of the data is of 8 bits and from 0 to 255. Length is measured in
terms of bytes.
If Length = 0, it means data length is 0 bytes
If Length = 1, it means data length is 1 bytes
Configuration:
Switch has four output ports. These output ports address have to be configured to a
unique address. Switch matches the DA field of the packet with this configured port
address and sends the packet on to that port. Switch contains a memory. This
memory has 4 locations, each can store 8 bits. To configure the switch port address,
memory write operation has to be done using memory interface. Memory address
(0,1,2,3) contains the address of port(0,1,2,3) respectively.
Interface Specification:
The Switch has one input Interface, from where the packet enters and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured. Switch also has a clock and asynchronous reset
signal.
MEMORY INTERFACE:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively.
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
All the signals are active high and are synchronous to the positive edge of clock
signal.
To configure a port address,
INPUT PORT
OUTPUT PORT
Switch sends the packets out using the output ports. There are 4 ports, each having
data, ready and read signals. All the signals are active high and are synchronous to
the positive edge of clock signal.
Signal list is
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
When the data is ready to be sent out from the port, switch asserts ready_* signal
high indicating that data is ready to be sent.
If the read_* signal is asserted, when ready_* is high, then the data comes out of the
port_* signal after one clock cycle.
RTL code:
RTL code is attached with the tar files. From the Phase 1, you can download the tar
files.
Search ✔
Verilog 5)
Verification ID: FCS
Description:
Verilog Switch TB Good FCS: Send packet with good FCS.
Basic Constructs Bad FCS: Send packet with corrupted FCS.
Verification Environment
Specman E
Interview Questions
Search ✔
interface mem_interface(input bit clock);
OpenVera parameter setup_time = 5ns;
Constructs parameter hold_time = 3ns;
Switch TB
wire [7:0] mem_data;
RVM Switch TB wire [1:0] mem_add;
RVM Ethernet sample wire mem_en;
wire mem_rd_wr;
clocking cb@(posedge clock);
Specman E default input #setup_time output #hold_time;
Interview Questions output mem_data;
output mem_add;
output mem_en;
output mem_rd_wr;
endclocking:cb
modport MEM(clocking cb,input clock);
endinterface :mem_interface
////////////////////////////////////////////
parameter setup_time = 5ns;
parameter hold_time = 3ns;
wire data_status;
wire [7:0] data_in;
reg reset;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
output data_status;
output data_in;
endclocking:cb
modport IP(clocking cb,output reset,input clock);
endinterface:input_interface
/////////////////////////////////////////////////
// Interface for the output side of the switch.//
// output_interface is for only one output port//
/////////////////////////////////////////////////
interface output_interface(input bit clock);
parameter setup_time = 5ns;
parameter hold_time = 3ns;
wire [7:0] data_out;
wire ready;
wire read;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
input data_out;
input ready;
output read;
endclocking:cb
modport OP(clocking cb,input clock);
endinterface:output_interface
//////////////////////////////////////////////////
`endif
Top Module
The modules that are included in the source text but are not instantiated are called
top modules. This module is the highest scope of modules. Generally this module is
named as "top" and referenced as "top module". Module name can be anything.
This top-level module will contain the design portion of the simulation.
`include "ovm.svh"
import ovm_pkg::*;
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
mem_interface mem_intf(Clock);
input_interface input_intf(Clock);
output_interface output_intf[4](Clock);
5) Connect all the interfaces and DUT. The design which we have taken is in
verilog. So Verilog DUT instance is connected signal by signal.
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
`ifndef GUARD_TOP
`define GUARD_TOP
/////////////////////////////////////////////////////
// Importing OVM Packages //
/////////////////////////////////////////////////////
`include "ovm.svh"
import ovm_pkg::*;
typedef class Configuration;
module top();
/////////////////////////////////////////////////////
// Clock Declaration and Generation //
/////////////////////////////////////////////////////
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
/////////////////////////////////////////////////////
// Memory interface instance //
/////////////////////////////////////////////////////
mem_interface mem_intf(Clock);
/////////////////////////////////////////////////////
// Input interface instance //
/////////////////////////////////////////////////////
input_interface input_intf(Clock);
/////////////////////////////////////////////////////
// output interface instance //
/////////////////////////////////////////////////////
output_interface output_intf[4](Clock);
/////////////////////////////////////////////////////
// DUT instance and signal connection //
/////////////////////////////////////////////////////
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
endmodule : top
`endif
ovm_switch_1.tar
Browse the code in ovm_switch_1.tar
Command to compile
Search ✔
virtual input_interface.IP input_intf;
Verilog virtual mem_interface.MEM mem_intf;
Verification virtual output_interface.OP output_intf[4];
Verilog Switch TB 3) Declare 4 variables which holds the device port address.
Basic Constructs
bit [7:0] device0_add ;
bit [7:0] device1_add ;
bit [7:0] device2_add ;
OpenVera bit [7:0] device3_add ;
Constructs
Switch TB 4) ovm_object required to define the ovm_object::creat() method.
ovm_object::create method allocates a new object of the same type as this object
RVM Switch TB and returns it via a base ovm_object handle.
RVM Ethernet sample
In create method, we have to construct a new object of configuration class and
update all the important fields and return it.
Specman E virtual function ovm_object create(string name="");
Interview Questions Configuration t = new();
t.device0_add = this.device0_add;
t.device1_add = this.device1_add;
t.device2_add = this.device2_add;
t.device3_add = this.device3_add;
t.input_intf = this.input_intf;
t.mem_intf = this.mem_intf;
t.output_intf = this.output_intf;
return t;
endfunction : create
class Configuration extends ovm_object;
virtual input_interface.IP input_intf;
virtual mem_interface.MEM mem_intf;
virtual output_interface.OP output_intf[4];
bit [7:0] device0_add ;
bit [7:0] device1_add ;
bit [7:0] device2_add ;
bit [7:0] device3_add ;
virtual function ovm_object create(string name="");
Configuration t = new();
t.device0_add = this.device0_add;
t.device1_add = this.device1_add;
t.device2_add = this.device2_add;
t.device3_add = this.device3_add;
t.input_intf = this.input_intf;
t.mem_intf = this.mem_intf;
t.output_intf = this.output_intf;
return t;
endfunction : create
endclass : Configuration
`endif
In top module we will create an object of the above defined configuration class and
update the interfaces so that all the verification components can access to physical
interfaces in top module using configuration class object.
Configuration cfg;
initial begin
cfg = new();
cfg.input_intf = input_intf;
cfg.mem_intf = mem_intf;
cfg.output_intf = output_intf;
run_test();
module top();
/////////////////////////////////////////////////////
// Clock Declaration and Generation //
/////////////////////////////////////////////////////
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
/////////////////////////////////////////////////////
// Memory interface instance //
/////////////////////////////////////////////////////
mem_interface mem_intf(Clock);
/////////////////////////////////////////////////////
// Input interface instance //
/////////////////////////////////////////////////////
input_interface input_intf(Clock);
/////////////////////////////////////////////////////
// output interface instance //
/////////////////////////////////////////////////////
output_interface output_intf[4](Clock);
/////////////////////////////////////////////////////
// Creat Configuration and Strart the run_test//
/////////////////////////////////////////////////////
Configuration cfg;
initial begin
cfg = new();
cfg.input_intf = input_intf;
cfg.mem_intf = mem_intf;
cfg.output_intf = output_intf;
run_test();
end
/////////////////////////////////////////////////////
// DUT instance and signal connection //
/////////////////////////////////////////////////////
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
endmodule : top
`endif
ovm_switch_2.tar
Browse the code in ovm_switch_2.tar
Command to compile
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs We will not implement all the ovm_env virtual methods in this phase but will we print
messages from these methods which are required for this example to understand the
simulation execution.
OpenVera
Testcase contains the instance of the environment class. This testcase Creates a
Constructs Environment object and defines the required test specific functionality.
Switch TB
Verification environment contains the declarations of the virtual interfaces. These
RVM Switch TB
virtual interfaces are pointed to the physical interfaces which are declared in the top
RVM Ethernet sample module. These virtual interfaces are made to point to physical interface in the
testcase.
Specman E
Environment
Interview Questions
1) Extend ovm_env class to define Environment class.
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment extends ovm_env;
endclass : Environment
`endif
2) Declare the utility macro. This utility macro provides the implementation of
create() and get_type_name() methods.
`ovm_component_utils(Environment)
3) Define the constructor. In the constructor, call the super methods and pass the
parent object. Parent is the object in which environment is instantiated.
4) Define build method. In build method, just print messages and super.build() must
be called. This method is automatically called.
Build is the first phase in simulation. This phase is used to construct the child
components of the current class.
function void build();
super.build();
ovm_report_info(get_full_name(),"START of build ",OVM_LOW);
ovm_report_info(get_full_name(),"END of build ",OVM_LOW);
endfunction
function void connect();
super.connect();
ovm_report_info(get_full_name(),"START of connect ",OVM_LOW);
ovm_report_info(get_full_name(),"END of connect ",OVM_LOW);
endfunction
class Environment extends ovm_env;
`ovm_component_utils(Environment)
function void build();
super.build();
ovm_report_info(get_full_name(),"START of build ",OVM_LOW);
ovm_report_info(get_full_name(),"END of build ",OVM_LOW);
endfunction
function void connect();
super.connect();
ovm_report_info(get_full_name(),"START of connect ",OVM_LOW);
ovm_report_info(get_full_name(),"END of connect ",OVM_LOW);
endfunction
endclass : Environment
`endif
Testcase
class test1 extends ovm_test;
endclass
`ovm_component_utils(test1)
function new (string name="test1", ovm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
As we dont have anything now to write in this testcase, just call the
global_stop_request() after some delay.
task run ();
#1000;
global_stop_request();
endtask : run
`ovm_component_utils(test1)
function new (string name="test1", ovm_component parent=null);
super.new (name, parent);
t_env = new("t_env",this);
endfunction : new
task run ();
#1000;
global_stop_request();
endtask : run
endclass : test1
ovm_switch_3.tar
Browse the code in ovm_switch_3.tar
Search ✔
Verilog typedef enum { GOOD_FCS, BAD_FCS } fcs_kind_t;
Verification
2) Define transaction by extending ovm_sequence_item.
Verilog Switch TB
Basic Constructs class Packet extends ovm_sequence_item;
endclass : Packet
OpenVera 3) Define all the fields as rand variables.
Constructs
Switch TB rand fcs_kind_t fcs_kind;
RVM Switch TB rand bit [7:0] length;
RVM Ethernet sample rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];
rand byte fcs;
Specman E
Interview Questions
4) Define constraints to constraint payload size of data.
constraint payload_size_c { data.size inside { [2 : 255]};}
constraint length_c { length == data.size; }
function new(string name = "");
super.new(name);
endfunction : new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
virtual function byte cal_fcs;
integer i;
byte result ;
result = 0;
result = result ^ da;
result = result ^ sa;
result = result ^ length;
for (i = 0;i< data.size;i++)
result = result ^ data[i];
result = fcs ^ result;
return result;
endfunction : cal_fcs
`ovm_object_utils_begin(Packet)
`ovm_field_int(da, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(sa, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(length, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_array_int(data, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(fcs, OVM_ALL_ON|OVM_NOPACK)
`ovm_object_utils_end
function void do_pack(ovm_packer packer);
super.do_pack(packer);
packer.pack_field_int(da,$bits(da));
packer.pack_field_int(sa,$bits(sa));
packer.pack_field_int(length,$bits(length));
foreach(data[i])
packer.pack_field_int(data[i],8);
packer.pack_field_int(fcs,$bits(fcs));
endfunction : do_pack
function void do_unpack(ovm_packer packer);
int sz;
super.do_pack(packer);
da = packer.unpack_field_int($bits(da));
sa = packer.unpack_field_int($bits(sa));
length = packer.unpack_field_int($bits(length));
data.delete();
data = new[length];
foreach(data[i])
data[i] = packer.unpack_field_int(8);
fcs = packer.unpack_field_int($bits(fcs));
endfunction : do_unpack
`ifndef GUARD_PACKET
`define GUARD_PACKET
`include "ovm.svh"
import ovm_pkg::*;
class Packet extends ovm_sequence_item;
rand fcs_kind_t fcs_kind;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 6]};}
constraint length_c { length == data.size; }
function new(string name = "");
super.new(name);
endfunction : new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
///// method to calculate the fcs /////
virtual function byte cal_fcs;
integer i;
byte result ;
result = 0;
result = result ^ da;
result = result ^ sa;
result = result ^ length;
for (i = 0;i< data.size;i++)
result = result ^ data[i];
result = fcs ^ result;
return result;
endfunction : cal_fcs
`ovm_object_utils_begin(Packet)
`ovm_field_int(da, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(sa, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(length, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_array_int(data, OVM_ALL_ON|OVM_NOPACK)
`ovm_field_int(fcs, OVM_ALL_ON|OVM_NOPACK)
`ovm_object_utils_end
function void do_pack(ovm_packer packer);
super.do_pack(packer);
packer.pack_field_int(da,$bits(da));
packer.pack_field_int(sa,$bits(sa));
packer.pack_field_int(length,$bits(length));
foreach(data[i])
packer.pack_field_int(data[i],8);
packer.pack_field_int(fcs,$bits(fcs));
endfunction : do_pack
function void do_unpack(ovm_packer packer);
int sz;
super.do_pack(packer);
da = packer.unpack_field_int($bits(da));
sa = packer.unpack_field_int($bits(sa));
length = packer.unpack_field_int($bits(length));
data.delete();
data = new[length];
foreach(data[i])
data[i] = packer.unpack_field_int(8);
fcs = packer.unpack_field_int($bits(fcs));
endfunction : do_unpack
endclass : Packet
Now we will write a small logic to test our packet implantation. This module is not
used in normal verification.
Define a module and take the instance of packet class. Randomize the packet and call
the print method to analyze the generation. Then pack the packet in to bytes and
then unpack bytes and then call compare method to check all the method
implementation.
2) In a initial block, randomize the packet, pack the packet in to pkdbytes and then
unpack it and compare the packets.
if(pkt1.randomize)
begin
$display(" Randomization Sucessesfull.");
pkt1.print();
ovm_default_packer.use_metadata = 1;
void'(pkt1.pack_bytes(pkdbytes));
$display("Size of pkd bits %d",pkdbytes.size());
pkt2.unpack_bytes(pkdbytes);
pkt2.print();
if(pkt2.compare(pkt1))
$display(" Packing,Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***
\n \n");
initial
repeat(10)
if(pkt1.randomize)
begin
$display(" Randomization Successesfull.");
pkt1.print();
ovm_default_packer.use_metadata = 1;
void'(pkt1.pack_bytes(pkdbytes));
$display("Size of pkd bits %d",pkdbytes.size());
pkt2.unpack_bytes(pkdbytes);
pkt2.print();
if(pkt2.compare(pkt1))
$display(" Packing,Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***
\n \n");
end
else
$display(" *** Randomization Failed ***");
endmodule
ovm_switch_4.tar
Browse the code in ovm_switch_4.tar
Randomization Sucessesfull.
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
pkt1 Packet - pkt1@3
--da integral 8 'ha5
--sa integral 8 'ha1
--length integral 8 'h6
--data da(integral) 6 -
----[0] integral 8 'h58
----[1] integral 8 'h60
----[2] integral 8 'h34
----[3] integral 8 'hdd
----[4] integral 8 'h9
----[5] integral 8 'haf
--fcs integral 8 'h75
----------------------------------------------------------------------
Size of pkd bits 10
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
pkt2 Packet - pkt2@5
--da integral 8 'ha5
--sa integral 8 'ha1
--length integral 8 'h6
--data da(integral) 6 -
----[0] integral 8 'h58
----[1] integral 8 'h60
----[2] integral 8 'h34
----[3] integral 8 'hdd
----[4] integral 8 'h9
----[5] integral 8 'haf
--fcs integral 8 'h75
----------------------------------------------------------------------
Packing,Unpacking and compare worked
....
....
....
....
Search ✔
`ovm_sequencer_utils(Sequencer)
function new (string name, ovm_component parent);
super.new(name, parent);
`ovm_update_sequence_lib_and_item(Packet)
endfunction : new
function void end_of_elaboration();
ovm_object tmp;
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
endfunction
`ifndef GUARD_SEQUENCER
`define GUARD_SEQUENCER
endclass : Sequencer
`endif
Sequence
You can define as many sequences as you want. We will define 2 sequences.
endclass: Seq_device0_and_device1
function new(string name = "Seq_do");
super.new(name);
endfunction : new
`ovm_sequence_utils(Seq_device0_and_device1, Sequencer)
4) The algorithm for the transaction should be defined in body() method of the
sequence. In this sequence we will define the algorithm such that alternate
transactions for device port 0 and 1 are generated.
The device addresses are available in configuration object which is in sequencer.
Every sequence has a handle to its sequence through p_sequencer. Using p_sequencer
handle, access the device address.
virtual task body();
forever begin
`ovm_do_with(item, {da == p_sequencer.cfg.device0_add;} );
`ovm_do_with(item, {da == p_sequencer.cfg.device1_add;} );
end
endtask : body
function new(string name = "Seq_device0_and_device1");
super.new(name);
endfunction : new
Packet item;
`ovm_sequence_utils(Seq_device0_and_device1, Sequencer)
virtual task body();
forever begin
`ovm_do_with(item, {da == p_sequencer.cfg.device0_add;} );
`ovm_do_with(item, {da == p_sequencer.cfg.device1_add;} );
end
endtask : body
endclass :Seq_device0_and_device1
function new(string name = "Seq_constant_length");
super.new(name);
endfunction : new
Packet item;
`ovm_sequence_utils(Seq_constant_length, Sequencer)
virtual task body();
forever begin
`ovm_do_with(item, {length == 10;da == p_sequencer.cfg.device0_add;} );
end
endtask : body
endclass : Seq_constant_length
ovm_switch_5.tar
Browse the code in ovm_switch_5.tar
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
2) Create a handle to configuration object. Using this object we can get DUT
interfaces and DUT port addresses.
Specman E
Interview Questions Configuration cfg;
`ovm_component_utils(Driver)
6) Define the constructor method. Pass the parent object to super class.
function void build();
super.build();
Drvr2Sb_port = new("Drvr2Sb_port", this);
endfunction : build
function void end_of_elaboration();
ovm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
this.input_intf = cfg.input_intf;
this.mem_intf = cfg.mem_intf;
endfunction : end_of_elaboration
9) Define the reset_dut() method which will be used for resetting the DUT.
virtual task reset_dut();
ovm_report_info(get_full_name(),"Start of reset_dut() method ",OVM_LOW);
mem_intf.mem_data <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_en <= 0;
mem_intf.mem_rd_wr <= 0;
input_intf.data_in <= 0;
input_intf.data_status <= 0;
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
10) Define the cfg_dut() method which does the configuration due port address.
virtual task cfg_dut();
ovm_report_info(get_full_name(),"Start of cfg_dut() method ",OVM_LOW);
mem_intf.mem_en <= 1;
@(posedge mem_intf.clock);
mem_intf.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h0;
mem_intf.mem_data <= cfg.device0_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 0 Address %h ",cfg.device0_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h1;
mem_intf.mem_data <= cfg.device1_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 1 Address %h ",cfg.device1_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h2;
mem_intf.mem_data <= cfg.device2_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 2 Address %h ",cfg.device2_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h3;
mem_intf.mem_data <= cfg.device3_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 3 Address %h ",cfg.device3_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_en <=0;
mem_intf.mem_rd_wr <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_data <= 0;
11) Define drive() method which will be used to drive the packet to DUT. In this
method pack the packet fields using the pack_bytes() method of the transaction and
drive the packed data to DUT interface.
task drive(Packet pkt);
byte unsigned bytes[];
int pkt_len;
pkt_len = pkt.pack_bytes(bytes);
ovm_report_info(get_full_name(),"Driving packet ...",OVM_LOW);
foreach(bytes[i])
begin
@(posedge input_intf.clock);
input_intf.data_status <= 1 ;
input_intf.data_in <= bytes[i];
end
@(posedge input_intf.clock);
input_intf.data_status <= 0 ;
input_intf.data_in <= 0;
repeat(2) @(posedge input_intf.clock);
endtask : drive
12) Now we will use the above 3 defined methods and update the run() method of
ovm_driver.
First call the reset_dut() method and then cfg_dut(). After completing the
configuration, in a forever loop get the transaction from seq_item_port and send it
DUT using drive() method and also to scoreboard using Drvr2SB_port .
task run();
Packet pkt;
@(posedge input_intf.clock);
reset_dut();
cfg_dut();
forever begin
seq_item_port.get_next_item(pkt);
Drvr2Sb_port.write(pkt);
@(posedge input_intf.clock);
drive(pkt);
@(posedge input_intf.clock);
seq_item_port.item_done();
end
endtask : run
`ifndef GUARD_DRIVER
`define GUARD_DRIVER
Configuration cfg;
virtual input_interface.IP input_intf;
virtual mem_interface.MEM mem_intf;
ovm_analysis_port #(Packet) Drvr2Sb_port;
`ovm_component_utils(Driver)
function new( string name = "" , ovm_component parent = null) ;
super.new( name , parent );
endfunction : new
function void build();
super.build();
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : build
function void end_of_elaboration();
ovm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
this.input_intf = cfg.input_intf;
this.mem_intf = cfg.mem_intf;
endfunction : end_of_elaboration
task run();
Packet pkt;
@(posedge input_intf.clock);
reset_dut();
cfg_dut();
forever begin
seq_item_port.get_next_item(pkt);
Drvr2Sb_port.write(pkt);
@(posedge input_intf.clock);
drive(pkt);
@(posedge input_intf.clock);
seq_item_port.item_done();
end
endtask : run
virtual task reset_dut();
ovm_report_info(get_full_name(),"Start of reset_dut() method ",OVM_LOW);
mem_intf.mem_data <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_en <= 0;
mem_intf.mem_rd_wr <= 0;
input_intf.data_in <= 0;
input_intf.data_status <= 0;
input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;
ovm_report_info(get_full_name(),"End of reset_dut() method ",OVM_LOW);
endtask : reset_dut
virtual task cfg_dut();
ovm_report_info(get_full_name(),"Start of cfg_dut() method ",OVM_LOW);
mem_intf.mem_en <= 1;
@(posedge mem_intf.clock);
mem_intf.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h0;
mem_intf.mem_data <= cfg.device0_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 0 Address %h ",cfg.device0_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h1;
mem_intf.mem_data <= cfg.device1_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 1 Address %h ",cfg.device1_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h2;
mem_intf.mem_data <= cfg.device2_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 2 Address %h ",cfg.device2_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_add <= 8'h3;
mem_intf.mem_data <= cfg.device3_add;
ovm_report_info(get_full_name(),
$psprintf(" Port 3 Address %h ",cfg.device3_add),OVM_LOW);
@(posedge mem_intf.clock);
mem_intf.mem_en <=0;
mem_intf.mem_rd_wr <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_data <= 0;
ovm_report_info(get_full_name(),"End of cfg_dut() method ",OVM_LOW);
endtask : cfg_dut
task drive(Packet pkt);
byte unsigned bytes[];
int pkt_len;
pkt_len = pkt.pack_bytes(bytes);
ovm_report_info(get_full_name(),"Driving packet ...",OVM_LOW);
foreach(bytes[i])
begin
@(posedge input_intf.clock);
input_intf.data_status <= 1 ;
input_intf.data_in <= bytes[i];
end
@(posedge input_intf.clock);
input_intf.data_status <= 0 ;
input_intf.data_in <= 0;
repeat(2) @(posedge input_intf.clock);
endtask : drive
endclass : Driver
`endif
Environment Updates
We will take the instance of Sequencer and Driver and connect them in Environment
class.
2) In build method, construct Seqncr and Drvr object using create() method.
Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);
Drvr.seq_item_port.connect(Seqncr.seq_item_export);
`ifndef GUARD_ENV
`define GUARD_ENV
`ovm_component_utils(Environment)
Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);
Drvr.seq_item_port.connect(Seqncr.seq_item_export);
endclass : Environment
`endif
Testcase Updates
1)In the build() method, update the configuration address in the configuration object
which in top module.
function void build();
super.build();
cfg.device0_add = 0;
cfg.device1_add = 1;
cfg.device2_add = 2;
cfg.device3_add = 3;
set_config_object("t_env.*","Configuration",cfg);
set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");
set_config_int("*.Seqncr", "count",2);
t_env.Seqncr.print();
Testcase code
`ovm_component_utils(test1)
function void build();
super.build();
cfg.device0_add = 0;
cfg.device1_add = 1;
cfg.device2_add = 2;
cfg.device3_add = 3;
set_config_object("t_env.*","Configuration",cfg);
set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");
set_config_int("*.Seqncr", "count",2);
endfunction
t_env.Seqncr.print();
#1000;
global_stop_request();
endtask : run
endclass : test1
ovm_switch_6.tar
Browse the code in ovm_switch_6.tar
----------------------------------------------------------------------
Seqncr Sequencer - Seqncr@14
--rsp_export ovm_analysis_export - rsp_export@16
--seq_item_export ovm_seq_item_pull_+ - seq_item_export@40
--default_sequence string 19 ovm_random_sequence
--count integral 32 -1
--max_random_count integral 32 'd10
--sequences array 5 -
----[0] string 19 ovm_random_sequence
----[1] string 23 ovm_exhaustive_sequ+
----[2] string 19 ovm_simple_sequence
----[3] string 23 Seq_device0_and_dev+
----[4] string 19 Seq_constant_length
--max_random_depth integral 32 'd4
--num_last_reqs integral 32 'd1
--num_last_rsps integral 32 'd1
----------------------------------------------------------------------
OVM_INFO @ 30: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Start of reset_dut() method
OVM_INFO @ 70: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
End of reset_dut() method
OVM_INFO @ 70: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Start of cfg_dut() method
OVM_INFO @ 110: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 0 Address 00
OVM_INFO @ 130: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 1 Address 01
OVM_INFO @ 150: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 2 Address 02
OVM_INFO @ 170: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 3 Address 03
OVM_INFO @ 190: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
End of cfg_dut() method
OVM_INFO @ 210: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Driving packet ...
OVM_INFO @ 590: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Driving packet ...
OVM_INFO @ 970: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Driving packet ...
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
`endif
Specman E
Interview Questions 2) Declare configuration class object.
Configuration cfg;
integer id;
virtual output_interface.OP output_intf;
5) Declare analysis port which is used by receiver to send the received transaction to
scoreboard.
ovm_analysis_port #(Packet) Rcvr2Sb_port;
6) Declare the utility macro. This utility macro provides the implementation of creat()
and get_type_name() methods.
`ovm_component_utils(Receiver)
function new (string name, ovm_component parent);
super.new(name, parent);
endfunction : new
function void build();
super.build();
Rcvr2Sb_port = new("Rcvr2Sb", this);
endfunction : build
function void end_of_elaboration();
ovm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
output_intf = cfg.output_intf[id];
endfunction : end_of_elaboration
10) Define the run() method. This method collects the packets from the DUT output
interface and unpacks it into high level transaction using transactions unpack_bytes()
method.
virtual task run();
bit [7:0] bytes[];
Packet pkt;
fork
forever
begin
repeat(2) @(posedge output_intf.clock);
wait(output_intf.ready)
output_intf.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.ready)
begin
bytes = new[bytes.size + 1](bytes);
bytes[bytes.size - 1] = output_intf.data_out;
@(posedge output_intf.clock);
end
endtask : run
class Receiver extends ovm_component;
virtual output_interface.OP output_intf;
Configuration cfg;
integer id;
ovm_analysis_port #(Packet) Rcvr2Sb_port;
`ovm_component_utils(Receiver)
function new (string name, ovm_component parent);
super.new(name, parent);
endfunction : new
function void build();
super.build();
Rcvr2Sb_port = new("Rcvr2Sb", this);
endfunction : build
function void end_of_elaboration();
ovm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
output_intf = cfg.output_intf[id];
endfunction : end_of_elaboration
virtual task run();
bit [7:0] bytes[];
Packet pkt;
fork
forever
begin
repeat(2) @(posedge output_intf.clock);
wait(output_intf.ready)
output_intf.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.ready)
begin
bytes = new[bytes.size + 1](bytes);
bytes[bytes.size - 1] = output_intf.data_out;
@(posedge output_intf.clock);
end
endtask : run
endclass : Receiver
We will update the Environment class and take instance of receiver and run the
testcase.
1) Declare 4 receivers.
Receiver Rcvr[4];
2) In the build() method construct the Receivers using create() methods. Also update
the id variable of the receiver object.
foreach(Rcvr[i]) begin
Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
`ifndef GUARD_ENV
`define GUARD_ENV
`ovm_component_utils(Environment)
foreach(Rcvr[i]) begin
Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
endclass : Environment
`endif
ovm_switch_7.tar
Browse the code in ovm_switch_7.tar
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
1) Declare a scoreboard by extending ovm_scoreboard class.
`ovm_analysis_imp_decl(_rcvd_pkt)
`ovm_analysis_imp_decl(_sent_pkt)
Specman E
Interview Questions 3) Declare the utility macro.
`ovm_component_utils(Scoreboard)
Packet exp_que[$];
ovm_analysis_imp_rcvd_pkt #(Packet,Scoreboard) Rcvr2Sb_port;
ovm_analysis_imp_sent_pkt #(Packet,Scoreboard) Drvr2Sb_port;
6) In the constructor, create objects for the above two declared imports.
function new(string name, ovm_component parent);
super.new(name, parent);
Rcvr2Sb_port = new("Rcvr2Sb", this);
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : new
virtual function void write_sent_pkt(input Packet pkt);
exp_que.push_back(pkt);
endfunction : write_sent_pkt
virtual function void write_rcvd_pkt(input Packet pkt);
Packet exp_pkt;
pkt.print();
if(exp_que.size())
begin
exp_pkt = exp_que.pop_front();
exp_pkt.print();
if( pkt.compare(exp_pkt))
ovm_report_info(get_type_name(),
$psprintf("Sent packet and reeived packet mathed"), OVM_LOW);
else
ovm_report_error(get_type_name(),
$psprintf("Sent packet and reeived packet mismatched"), OVM_LOW);
end
else
ovm_report_error(get_type_name(),
$psprintf("No more packets in the expected queue to compare"), OVM_LOW);
endfunction : write_rcvd_pkt
virtual function void report();
ovm_report_info(get_type_name(),
$psprintf("Scoreboard Report %s", this.sprint()), OVM_LOW);
endfunction : report
`ovm_analysis_imp_decl(_rcvd_pkt)
`ovm_analysis_imp_decl(_sent_pkt)
class Scoreboard extends ovm_scoreboard;
`ovm_component_utils(Scoreboard)
Packet exp_que[$];
ovm_analysis_imp_rcvd_pkt #(Packet,Scoreboard) Rcvr2Sb_port;
ovm_analysis_imp_sent_pkt #(Packet,Scoreboard) Drvr2Sb_port;
function new(string name, ovm_component parent);
super.new(name, parent);
Rcvr2Sb_port = new("Rcvr2Sb", this);
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : new
virtual function void write_rcvd_pkt(input Packet pkt);
Packet exp_pkt;
pkt.print();
if(exp_que.size())
begin
exp_pkt = exp_que.pop_front();
exp_pkt.print();
if( pkt.compare(exp_pkt))
ovm_report_info(get_type_name(),
$psprintf("Sent packet and reeived packet mathed"), OVM_LOW);
else
ovm_report_error(get_type_name(),
$psprintf("Sent packet and reeived packet mismatched"), OVM_LOW);
end
else
ovm_report_error(get_type_name(),
$psprintf("No more packets to in the expected queue to
compare"), OVM_LOW);
endfunction : write_rcvd_pkt
virtual function void write_sent_pkt(input Packet pkt);
exp_que.push_back(pkt);
endfunction : write_sent_pkt
virtual function void report();
ovm_report_info(get_type_name(),
$psprintf("Scoreboard Report %s", this.sprint()), OVM_LOW);
endfunction : report
endclass : Scoreboard
`endif
We will take the instance of scoreboard in the environment and connect its ports to
driver and receiver ports.
Sbd = Scoreboard::type_id::create("Sbd",this);
Drvr.Drvr2Sb_port.connect(Sbd.Drvr2Sb_port);
Rcvr[0].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
Rcvr[1].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
Rcvr[2].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
Rcvr[3].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
`ifndef GUARD_ENV
`define GUARD_ENV
`ovm_component_utils(Environment)
Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);
foreach(Rcvr[i]) begin
Rcvr[i] = Receiver::type_id::create($psprintf("Rcvr%0d",i),this);
Rcvr[i].id = i;
end
Sbd = Scoreboard::type_id::create("Sbd",this);
Drvr.seq_item_port.connect(Seqncr.seq_item_export);
Drvr.Drvr2Sb_port.connect(Sbd.Drvr2Sb_port);
Rcvr[0].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
Rcvr[1].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
Rcvr[2].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
Rcvr[3].Rcvr2Sb_port.connect(Sbd.Rcvr2Sb_port);
endclass : Environment
`endif
ovm_switch_8.tar
Browse the code in ovm_switch_8.tar
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
Seqncr Sequencer - Seqncr@14
rsp_export ovm_analysis_export - rsp_export@16
seq_item_export ovm_seq_item_pull_+ - seq_item_export@40
default_sequence string 19 ovm_random_sequence
count integral 32 -1
max_random_count integral 32 'd10
sequences array 5 -
[0] string 19 ovm_random_sequence
[1] string 23 ovm_exhaustive_sequ+
[2] string 19 ovm_simple_sequence
[3] string 23 Seq_device0_and_dev+
[4] string 19 Seq_constant_length
max_random_depth integral 32 'd4
num_last_reqs integral 32 'd1
num_last_rsps integral 32 'd1
----------------------------------------------------------------------
OVM_INFO @ 30: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Start of reset_dut() method
OVM_INFO @ 70: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
End of reset_dut() method
OVM_INFO @ 70: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Start of cfg_dut() method
OVM_INFO @ 110: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 0 Address 00
OVM_INFO @ 130: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 1 Address 01
OVM_INFO @ 150: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 2 Address 02
OVM_INFO @ 170: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Port 3 Address 03
OVM_INFO @ 190: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
End of cfg_dut() method
OVM_INFO @ 210: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Driving packet ...
OVM_INFO @ 590: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Driving packet ...
OVM_INFO @ 610: ovm_test_top.t_env.Rcvr0 [ovm_test_top.t_env.Rcvr0]
Received packet ...
OVM_INFO @ 610: ovm_test_top.t_env.Sbd [Scoreboard]
Sent packet and reeived packet mathed
OVM_INFO @ 970: ovm_test_top.t_env.Drvr [ovm_test_top.t_env.Drvr]
Driving packet ...
OVM_INFO @ 990: ovm_test_top.t_env.Rcvr0 [ovm_test_top.t_env.Rcvr0]
Received packet ...
OVM_INFO @ 990: ovm_test_top.t_env.Sbd [Scoreboard]
Sent packet and reeived packet mathed
OVM_INFO @ 1000: ovm_test_top.t_env.Sbd [Scoreboard]
Scoreboard Report
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
Sbd Scoreboard - Sbd@52
Drvr2Sb ovm_analysis_imp_s+ - Drvr2Sb@56
Rcvr2Sb ovm_analysis_imp_r+ - Rcvr2Sb@54
----------------------------------------------------------------------
Search ✔
Phase 6) We will develop a driver class. Packets are taken from the generator and
Verilog sent to DUT using driver.
Verification
Phase 7) We will develop receiver class. Receiver collects the packets coming from
Verilog Switch TB the output port of the DUT.
Basic Constructs
Phase 8) We will develop scoreboard class which does the comparison of the
expected packet with the actual packet received from the DUT.
OpenVera
Phase 9) We will develop coverage class based on the coverage plan. Coverage is
Constructs sampled using the driver callbacks.
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet Format:
OpenVera
Constructs Packet contains 3 parts. They are Header, data and frame check sequence.
Packet width is 8 bits and the length of the packet can be between 4 bytes to 259
Switch TB bytes.
RVM Switch TB
RVM Ethernet sample
Packet header:
Configuration:
Switch has four output ports. These output ports address have to be configured to a
unique address. Switch matches the DA field of the packet with this configured port
address and sends the packet on to that port. Switch contains a memory. This
memory has 4 locations, each can store 8 bits. To configure the switch port address,
memory write operation has to be done using memory interface. Memory address
(0,1,2,3) contains the address of port(0,1,2,4) respectively.
Interface Specification:
The Switch has one input Interface, from where the packet enters and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured. Switch also has a clock and asynchronous reset
signal.
MEMORY INTERFACE:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively.
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
All the signals are active high and are synchronous to the positive edge of clock
signal.
To configure a port address,
1. Assert the mem_en signal.
INPUT PORT
OUTPUT PORT
Switch sends the packets out using the output ports. There are 4 ports, each having
data, ready and read signals. All the signals are active high and are synchronous to
the positive edge of clock signal.
Signal list is
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
When the data is ready to be sent out from the port, switch asserts ready_* signal
high indicating that data is ready to be sent.
If the read_* signal is asserted, when ready_* is high, then the data comes out of the
port_* signal after one clock cycle.
RTL code:
RTL code is attached with the tar files. From the Phase 1, you can download the tar
files.
Search ✔
Coverage Plan
Specman E
Interview Questions 1) Cover all the port address configurations.
2) Cover all the packet lengths.
3) Cover all correct and incorrect length fields.
4) Cover good and bad FCS.
5) Cover all the above combinations.
Verification Environment
Search ✔
OpenVera //////////////////////////////////////////
Constructs // Interface declaration for the memory///
//////////////////////////////////////////
Switch TB
RVM Switch TB interface mem_interface(input bit clock);
RVM Ethernet sample parameter setup_time = 5ns;
parameter hold_time = 3ns;
Specman E wire [7:0] mem_data;
wire [1:0] mem_add;
Interview Questions wire mem_en;
wire mem_rd_wr;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
output mem_data;
output mem_add;
output mem_en;
output mem_rd_wr;
endclocking:cb
modport MEM(clocking cb,input clock);
endinterface :mem_interface
////////////////////////////////////////////
// Interface for the input side of switch.//
// Reset signal is also passed hear. //
////////////////////////////////////////////
interface input_interface(input bit clock);
parameter setup_time = 5ns;
parameter hold_time = 3ns;
wire data_status;
wire [7:0] data_in;
wire reset;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
output data_status;
output data_in;
endclocking:cb
modport IP(clocking cb,output reset,input clock);
endinterface:input_interface
/////////////////////////////////////////////////
// Interface for the output side of the switch.//
// output_interface is for only one output port//
/////////////////////////////////////////////////
interface output_interface(input bit clock);
parameter setup_time = 5ns;
parameter hold_time = 3ns;
wire [7:0] data_out;
wire ready;
wire read;
clocking cb@(posedge clock);
default input #setup_time output #hold_time;
input data_out;
input ready;
output read;
endclocking:cb
modport OP(clocking cb,input clock);
endinterface:output_interface
//////////////////////////////////////////////////
`endif
Testcase
Testcase is a program block which provides an entry point for the test and creates a
scope that encapsulates program-wide data. Currently this is an empty testcase which
just ends the simulation. Program block contains all the above declared interfaces as
arguments. This testcase has initial and final blocks.
`ifndef GUARD_TESTCASE
`define GUARD_TESTCASE
program testcase(mem_interface.MEM mem_intf,input_interface.IP input_intf,output_interface.OP output_intf[4
]);
`include "vmm.sv"
initial
begin
$display(" ******************* Start of testcase ****************");
#1000;
end
final
$display(" ******************** End of testcase *****************");
endprogram
`endif
Top Module
The modules that are included in the source text but are not instantiated are called
top modules. This module is the highest scope of modules. Generally this module is
named as "top" and referenced as "top module". Module name can be anything.
This top-level module will contain the design portion of the simulation.
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
mem_interface mem_intf(Clock);
input_interface input_intf(Clock);
output_interface output_intf[4](Clock);
5)Do the instance of testcase and pass all the above declared interfaces.
testcase TC (mem_intf,input_intf,output_intf);
switch DUT (.
7)Connect all the interfaces and DUT. The design which we have taken is in
verilog. So Verilog DUT instance is connected signal by signal.
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
`ifndef GUARD_TOP
`define GUARD_TOP
module top();
/////////////////////////////////////////////////////
// Clock Declaration and Generation //
/////////////////////////////////////////////////////
bit Clock;
initial
begin
#20;
forever #10 Clock = ~Clock;
end
/////////////////////////////////////////////////////
// Memory interface instance //
/////////////////////////////////////////////////////
mem_interface mem_intf(Clock);
/////////////////////////////////////////////////////
// Input interface instance //
/////////////////////////////////////////////////////
input_interface input_intf(Clock);
/////////////////////////////////////////////////////
// output interface instance //
/////////////////////////////////////////////////////
output_interface output_intf[4](Clock);
/////////////////////////////////////////////////////
// Program block Testcase instance //
/////////////////////////////////////////////////////
testcase TC (mem_intf,input_intf,output_intf);
/////////////////////////////////////////////////////
// DUT instance and signal connection //
/////////////////////////////////////////////////////
switch DUT (.clk(Clock),
.reset(input_intf.reset),
.data_status(input_intf.data_status),
.data(input_intf.data_in),
.port0(output_intf[0].data_out),
.port1(output_intf[1].data_out),
.port2(output_intf[2].data_out),
.port3(output_intf[3].data_out),
.ready_0(output_intf[0].ready),
.ready_1(output_intf[1].ready),
.ready_2(output_intf[2].ready),
.ready_3(output_intf[3].ready),
.read_0(output_intf[0].read),
.read_1(output_intf[1].read),
.read_2(output_intf[2].read),
.read_3(output_intf[3].read),
.mem_en(mem_intf.mem_en),
.mem_rd_wr(mem_intf.mem_rd_wr),
.mem_add(mem_intf.mem_add),
.mem_data(mem_intf.mem_data));
endmodule
`endif
vmm_switch_1.tar
Browse the code in vmm_switch_1.tar
Search ✔
Specman E
Interview Questions
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment extends vmm_env;
endclass
`endif
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
function new(virtual mem_interface.MEM mem_intf_new ,
virtual input_interface.IP input_intf_new ,
virtual output_interface.OP output_intf_new[4] );
super.new("Environment ");
In constructor methods, the interfaces which are arguments are connected to the
virtual interfaces of environment class.
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
Extend all the vmm_env virtual methods. Call the super.<method_name> in all the
vmm_env virtual method extensions.
Include `vmm_note() messages for identifying the simulation steps in the log file.
virtual function void gen_cfg();
super.gen_cfg();
Do the above for reset_dut(), cfg_dut(), start(), wait_for_end(), stop() cleanup() and
report() methods.
Run :
The run method is called from the testcase to start the simulation. run method calls
all the methods which are defined in the Environment class.
`ifndef GUARD_ENV
`define GUARD_ENV
class Environment extends vmm_env;
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
function new(virtual mem_interface.MEM mem_intf_new ,
virtual input_interface.IP input_intf_new ,
virtual output_interface.OP output_intf_new[4] );
super.new("Environment ");
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
`vmm_note(this.log, "Created env object");
endfunction : new
virtual function void gen_cfg();
super.gen_cfg();
`vmm_note(this.log,"Start of gen_cfg() method ");
`vmm_note(this.log,"End of gen_cfg() method ");
endfunction
virtual function void build();
super.build();
`vmm_note(this.log,"Start of build() method ");
`vmm_note(this.log,"End of build() method ");
endfunction
virtual task reset_dut();
super.reset_dut();
`vmm_note(this.log,"Start of reset_dut() method ");
`vmm_note(this.log,"End of reset_dut() method ");
endtask
virtual task cfg_dut();
super.cfg_dut();
`vmm_note(this.log,"Start of cfg_dut() method ");
`vmm_note(this.log,"End of cfg_dut() method ");
endtask
virtual task start();
super.start();
`vmm_note(this.log,"Start of start() method ");
`vmm_note(this.log,"End of start() method ");
endtask
virtual task wait_for_end();
super.wait_for_end();
`vmm_note(this.log,"Start of wait_for_end() method ");
`vmm_note(this.log,"End of wait_for_end() method ");
endtask
virtual task stop();
super.stop();
`vmm_note(this.log,"Start of stop() method ");
`vmm_note(this.log,"End of stop() method ");
endtask
virtual task cleanup();
super.cleanup();
`vmm_note(this.log,"Start of cleanup() method ");
`vmm_note(this.log,"End of cleanup() method ");
endtask
virtual task report();
`vmm_note(this.log,"Start of report() method \n\n\n");
$display("---------------------------------------------------------------------");
super.report();
$display("---------------------------------------------------------------------");
$display("\n\n");
`vmm_note(this.log,"End of report() method");
endtask
endclass
`endif
We will create a file Global.sv for global requirement. In this file, define all the port
address as macros in this file.
`ifndef GUARD_GLOBALS
`define GUARD_GLOBALS
`define P0 8'h00
`define P1 8'h11
`define P2 8'h22
`define P3 8'h33
`endif
Now We will update the testcase. Take an instance of the Environment class and call
the run method of the Environment class.
`ifndef GUARD_TESTCASE
`define GUARD_TESTCASE
`include "vmm.sv"
Environment env;
initial
begin
$display(" ******************* Start of testcase ****************");
env = new(mem_intf,input_intf,output_intf);
env.run();
end
final
$display(" ******************** End of testcase *****************");
endprogram
`endif
vmm_switch_2.tar
Browse the code in vmm_switch_2.tar
Search ✔
Verilog NOTE: Clocking block signals can be driven only using a non-blocking assignment.
Verification
Verilog Switch TB
In reset_dut() method.
Basic Constructs 1) Set all the DUT input signals to a known state. And reset the DUT.
mem_intf.cb.mem_en <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h0;
mem_intf.cb.mem_data <= `P0;
`vmm_note(this.log ,$psprintf(" Port 0 Address %h ",`P0));
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h1;
mem_intf.cb.mem_data <= `P1;
`vmm_note(this.log ,$psprintf(" Port 1 Address %h ",`P1));
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h2;
mem_intf.cb.mem_data <= `P2;
`vmm_note(this.log ,$psprintf(" Port 2 Address %h ",`P2));
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h3;
mem_intf.cb.mem_data <= `P3;
`vmm_note(this.log ,$psprintf(" Port 3 Address %h ",`P3));
@(posedge mem_intf.clock);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
repeat(10000) @(input_intf.clock);
vmm_switch_3.tar
Browse the code in vmm_switch_3.tar
Search ✔
6) Declare the packet field as rand. All fields are bit data types. All fields are 8 bit
Specman E packet array. Declare the payload as dynamic array.
Interview Questions
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 255]};}
9) Constrain the payload length to the length field based on the length type.
constraint length_kind_c {
(length_kind == GOOD_LENGTH) -> length == data.size;
(length_kind == BAD_LENGTH) -> length == data.size + 2 ; }
Use solve before to direct the randomization to generate first the payload dynamic
array size and then randomize length field.
constraint solve_size_length { solve data.size before length; }
10) Define a port_randomize method. In this method calculate the fcs based on the
fcs_kind.
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
virtual function byte cal_fcs;
integer i;
byte result ;
result = 0;
result = result ^ da;
result = result ^ sa;
result = result ^ length;
for (i = 0;i< data.size;i++)
result = result ^ data[i];
result = fcs ^ result;
return result;
endfunction : cal_fcs
virtual function vmm_data allocate();
Packet pkt;
pkt = new();
return pkt;
endfunction:allocate
13) Define psdisplay() method. psdisplay() method displays the current value of the
packet fields to a string.
virtual function string psdisplay(string prefix = "");
int i;
$write(psdisplay, " %s packet
#%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.data_id);
$write(psdisplay, " %s%s da:0x%h\n", psdisplay, prefix,this.da);
$write(psdisplay, " %s%s sa:0x%h\n", psdisplay, prefix,this.sa);
$write(psdisplay, " %s%s length:0x%h
(data.size=%0d)\n", psdisplay, prefix,this.length,this.data.size());
$write(psdisplay, " %s%s data[%0d]:0x%h", psdisplay, prefix,0,data[0]);
if(data.size() > 1)
$write(psdisplay, " data[%0d]:0x%h", 1,data[1]);
if(data.size() > 4)
$write(psdisplay, " .... ");
if(data.size() > 2)
$write(psdisplay, " data[%0d]:0x%h", data.size() -2,data[data.size() -2]);
if(data.size() > 3)
$write(psdisplay, " data[%0d]:0x%h", data.size() -1,data[data.size() -1]);
$write(psdisplay, "\n %s%s fcs:0x%h \n", psdisplay, prefix, this.fcs);
endfunction
14) Define copy() method. copy() method copies the current values of the object
instance.
15) Define Compare() method. Compares the current value of the object instance with
the specified object instance.
If the value is different, FALSE is returned.
if (this.length != cmp.length)
begin
diff = $psprintf("Different LEN values: %b != %b", this.length, cmp.length);
compare = 0;
return compare;
end
foreach(data[i])
if (this.data[i] != cmp.data[i])
begin
diff = $psprintf("Different data[%0d] values: 0x%h !=
0x%h",i, this.data[i], cmp.data[i]);
compare = 0;
return compare;
end
if (this.fcs != cmp.fcs)
begin
diff = $psprintf("Different FCS values: %b != %b", this.fcs, cmp.fcs);
compare = 0;
return compare;
end
endfunction:compare
Packing is commonly used to convert the high level data to low level data that can be
applied to DUT. In packet class various fields are generated. Required fields are
concatenated to form a stream of bytes which can be driven conveniently to DUT
interface by the driver.
virtual function int unsigned byte_pack(
ref logic [7:0] bytes[],
input int unsigned offset =0 ,
input int kind = -1);
byte_pack = 0;
bytes = new[this.data.size() + 4];
bytes[0] = this.da;
bytes[1] = this.sa;
bytes[2] = this.length;
foreach(data[i])
bytes[3+i] = data[i];
bytes[this.data.size() + 3 ] = fcs;
byte_pack = this.data.size() + 4;
endfunction:byte_pack
The unpack() method does exactly the opposite of pack method. Unpacking is
commonly used to convert a data stream coming from DUT to high level data packet
object.
virtual function int unsigned byte_unpack(
const ref logic [7:0] bytes[],
input int unsigned offset = 0,
input int len = -1,
input int kind = -1);
this.da = bytes[0];
this.sa = bytes[1];
this.length = bytes[2];
this.fcs = bytes[bytes.size() -1];
this.data = new[bytes.size() - 4];
foreach(data[i])
this.data[i] = bytes[i+3];
return bytes.size();
endfunction:byte_unpack
`vmm_channel(Packet)
`vmm_atomic_gen(Packet, "Packet Gen")
`ifndef GUARD_PACKET
`define GUARD_PACKET
class Packet extends vmm_data;
rand fcs_kind_t fcs_kind;
rand length_kind_t length_kind;
rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;
constraint payload_size_c { data.size inside { [1 : 255};}
constraint length_kind_c {
(length_kind == GOOD_LENGTH) -> length == data.size;
(length_kind == BAD_LENGTH) -> length == data.size + 2 ; }
constraint solve_size_length { solve data.size before length; }
function new();
super.new(this.log);
endfunction:new
function void post_randomize();
if(fcs_kind == GOOD_FCS)
fcs = 8'b0;
else
fcs = 8'b1;
fcs = cal_fcs();
endfunction : post_randomize
virtual function vmm_data allocate();
Packet pkt;
pkt = new();
return pkt;
endfunction:allocate
virtual function string psdisplay(string prefix = "");
int i;
$write(psdisplay, " %s packet
#%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.data_id);
$write(psdisplay, " %s%s da:0x%h\n", psdisplay, prefix,this.da);
$write(psdisplay, " %s%s sa:0x%h\n", psdisplay, prefix,this.sa);
$write(psdisplay, " %s%s length:0x%h
(data.size=%0d)\n", psdisplay, prefix,this.length,this.data.size());
$write(psdisplay, " %s%s data[%0d]:0x%h", psdisplay, prefix,0,data[0]);
if(data.size() > 1)
$write(psdisplay, " data[%0d]:0x%h", 1,data[1]);
if(data.size() > 4)
$write(psdisplay, " .... ");
if(data.size() > 2)
$write(psdisplay, " data[%0d]:0x%h", data.size() -2,data[data.size() -2]);
if(data.size() > 3)
$write(psdisplay, " data[%0d]:0x%h", data.size() -1,data[data.size() -1]);
$write(psdisplay, "\n %s%s fcs:0x%h \n", psdisplay, prefix, this.fcs);
endfunction
virtual function vmm_data copy(vmm_data to = null);
Packet cpy;
// Copying to a new instance?
if (to == null)
cpy = new;
else
// Copying to an existing instance. Correct type?
if (!$cast(cpy, to))
begin
`vmm_fatal(this.log, "Attempting to copy to a non packet instance");
copy = null;
return copy;
end
super.copy_data(cpy);
cpy.da = this.da;
cpy.sa = this.sa;
cpy.length = this.length;
cpy.data = new[this.data.size()];
foreach(data[i])
begin
cpy.data[i] = this.data[i];
end
cpy.fcs = this.fcs;
copy = cpy;
endfunction:copy
virtual function bit compare(input vmm_data to,output string diff,input int kind
= -1);
Packet cmp;
compare = 1; // Assume success by default.
diff = "No differences found";
if (!$cast(cmp, to))
begin
`vmm_fatal(this.log, "Attempting to compare to a non packet instance");
compare = 0;
diff = "Cannot compare non packets";
return compare;
end
// data types are the same, do comparison:
if (this.da != cmp.da)
begin
diff = $psprintf("Different DA values: %b != %b", this.da, cmp.da);
compare = 0;
return compare;
end
if (this.sa != cmp.sa)
begin
diff = $psprintf("Different SA values: %b != %b", this.sa, cmp.sa);
compare = 0;
return compare;
end
if (this.length != cmp.length)
begin
diff = $psprintf("Different LEN values: %b != %b", this.length, cmp.length);
compare = 0;
return compare;
end
foreach(data[i])
if (this.data[i] != cmp.data[i])
begin
diff = $psprintf("Different data[%0d] values: 0x%h !=
0x%h",i, this.data[i], cmp.data[i]);
compare = 0;
return compare;
end
if (this.fcs != cmp.fcs)
begin
diff = $psprintf("Different FCS values: %b != %b", this.fcs, cmp.fcs);
compare = 0;
return compare;
end
endfunction:compare
virtual function int unsigned byte_pack(
ref logic [7:0] bytes[],
foreach(data[i])
bytes[3+i] = data[i];
bytes[this.data.size() + 3 ] = fcs;
byte_pack = this.data.size() + 4;
endfunction:byte_pack
virtual function int unsigned byte_unpack(
const ref logic [7:0] bytes[],
input int unsigned offset = 0,
input int len = -1,
input int kind = -1);
this.da = bytes[0];
this.sa = bytes[1];
this.length = bytes[2];
this.fcs = bytes[bytes.size() -1];
this.data = new[bytes.size() - 4];
foreach(data[i])
this.data[i] = bytes[i+3];
return bytes.size();
endfunction:byte_unpack
endclass
/////////////////////////////////////////////////////////
//// Create vmm_channel and vmm_atomic_gen for packet////
/////////////////////////////////////////////////////////
`vmm_channel(Packet)
`vmm_atomic_gen(Packet, "Packet Gen")
Now we will write a small program to test our packet implantation. This program
block is not used to verify the DUT.
Write a simple program block and do the instance of packet class. Randomize the
packet and call the display method to analyze the generation. Then pack the packet
in to bytes and then unpack bytes and then call compare method to check all the
methods.
program test;
end
else
$display(" *** Randomization Failed ***");
endprogram
vmm_switch_4.tar
Browse the code in vmm_switch_4.tar
Randomization Sucessesfull.
Pkt1 packet #0.0.0
Pkt1 da:0x00
Pkt1 sa:0x40
Pkt1 length:0xbe (data.size=190)
Pkt1 data[0]:0xf7 data[1]:0xa6 .... data[188]:0x49 data[189]:0x79
Pkt1 fcs:0x1a
Search ✔
Verilog
Verification 1) In Environment class, declare a Packet_atomic_gen instance.
Verilog Switch TB
Packet_atomic_gen atomic_gen;
Basic Constructs
2) Declare a Packet_channel instance.
atomic_gen.start_xactor();
atomic_gen.stop_xactor();
`ifndef GUARD_ENV
`define GUARD_ENV
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Packet_atomic_gen atomic_gen;
Packet_channel gen2drvr_chan;
gen2drvr_chan = new("gen2drvr","chan");
atomic_gen = new("atomic_gen",0,gen2drvr_chan);
atomic_gen.stop_after_n_insts = 10;
mem_intf.cb.mem_rd_wr <= 1;
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h0;
mem_intf.cb.mem_data <= `P0;
`vmm_note(this.log ,$psprintf(" Port 0 Address %h ",`P0));
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h1;
mem_intf.cb.mem_data <= `P1;
`vmm_note(this.log ,$psprintf(" Port 1 Address %h ",`P1));
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h2;
mem_intf.cb.mem_data <= `P2;
`vmm_note(this.log ,$psprintf(" Port 2 Address %h ",`P2));
@(posedge mem_intf.clock);
mem_intf.cb.mem_add <= 8'h3;
mem_intf.cb.mem_data <= `P3;
`vmm_note(this.log ,$psprintf(" Port 3 Address %h ",`P3));
@(posedge mem_intf.clock);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;
atomic_gen.start_xactor();
atomic_gen.stop_xactor();
endclass
`endif
vmm_switch_5.tar
Browse the code in vmm_switch_5.tar
Search ✔
Verilog
Verification
Verilog Switch TB
1) Extend vmm_xactor_callbacks to define Driver_callbacks. In this class, declare 2
Basic Constructs methods pre_trans() and post_trans(). pre_trans() method is called before driving the
packet transaction and post_trans() method will be called after driving the packet
transaction.
OpenVera
class Driver_callbacks extends vmm_xactor_callbacks;
Constructs
Switch TB // Called before a transaction is executed
RVM Switch TB virtual task pre_trans(Packet tr);
endtask: pre_trans
RVM Ethernet sample
// Called after a transaction has been executed
virtual task post_trans(Packet tr);
Specman E endtask: post_trans
class Driver extends vmm_xactor;
2) Declare a virtual input_interface of the switch. We will connect this to the Physical
interface of the top module same as what we did in environment class.
virtual input_interface.IP input_intf;
Packet_channel gen2drv_chan;
4) Define a channel "drv2sb_chan" which is used to send the packets to the score
board.
Packet_channel drv2sb_chan;
4) Define new constructor with arguments, virtual input interface and channels
"gen2drv_chan" and "drv2sb_chan".
In the constructor, call the parent constructor and pass the instance name and
stream_id.
Connect the channel and virtual interfaces which are passed as constructor arguments
to the class members.
function new(string inst,
int stream_id = -1,
virtual input_interface.IP input_intf_new,
Packet_channel gen2drv_chan = null,
Packet_channel drv2sb_chan = null);
super.new("driver",inst,stream_id);
this.input_intf = input_intf_new;
if(gen2drv_chan == null)
`vmm_fatal(log,"gen2drv_channel is null");
else
this.gen2drv_chan = gen2drv_chan;
if(drv2sb_chan == null)
`vmm_fatal(log,"drvr2sb_channel is null");
else
this.drv2sb_chan = drv2sb_chan;
`vmm_note(log,"Driver created ");
endfunction
4)Define drive() method. This method drives the packet to the dut.
task drive(Packet pkt);
logic [7:0] pack[];
int pkt_len;
pkt_len = pkt.byte_pack(pack,0,0);
@(posedge input_intf.clock);
for (int i=0;i< pkt_len - 1;i++)
begin
@(posedge input_intf.clock);
input_intf.cb.data_status <= 1 ;
input_intf.cb.data_in <= pack[i];
end
@(input_intf.clock);
input_intf.cb.data_status <= 0 ;
input_intf.cb.data_in <= pack[pkt_len -1];
@(input_intf.clock);
this.drv2sb_chan.put(pkt);
endtask
super.main();
`vmm_note(this.log," started main task ");
5) In main() method, start a forever thread, which gets the packets from the
forever begin
Packet pkt;
wait_if_stopped_or_empty(this.gen2drv_chan);
this.gen2drv_chan.get(pkt);
`vmm_trace(this.log, "Starting transaction...");
`vmm_debug(this.log, pkt.psdisplay(" "));
`vmm_callback(Driver_callbacks,pre_trans(pkt));
drive(pkt);
`vmm_callback(Driver_callbacks,post_trans(pkt));
`ifndef GUARD_DRIVER
`define GUARD_DRIVER
class Driver_callbacks extends vmm_xactor_callbacks;
endclass:Driver_callbacks
class Driver extends vmm_xactor;
virtual input_interface.IP input_intf;
Packet_channel gen2drv_chan;
Packet_channel drv2sb_chan;
function new(string inst,
int stream_id = -1,
virtual input_interface.IP input_intf_new,
Packet_channel gen2drv_chan = null,
Packet_channel drv2sb_chan = null);
super.new("driver",inst,stream_id);
this.input_intf = input_intf_new;
if(gen2drv_chan == null)
`vmm_fatal(log,"gen2drv_channel is null");
else
this.gen2drv_chan = gen2drv_chan;
if(drv2sb_chan == null)
`vmm_fatal(log,"drvr2sb_channel is null");
else
this.drv2sb_chan = drv2sb_chan;
`vmm_note(log,"Driver created ");
endfunction
task drive(Packet pkt);
logic [7:0] pack[];
int pkt_len;
pkt_len = pkt.byte_pack(pack,0,0);
@(posedge input_intf.clock);
for (int i=0;i< pkt_len - 1;i++)
begin
@(posedge input_intf.clock);
input_intf.cb.data_status <= 1 ;
input_intf.cb.data_in <= pack[i];
end
@(input_intf.clock);
input_intf.cb.data_status <= 0 ;
input_intf.cb.data_in <= pack[pkt_len -1];
@(input_intf.clock);
this.drv2sb_chan.put(pkt);
endtask
task main();
super.main();
`vmm_note(this.log," started main task ");
forever begin
Packet pkt;
wait_if_stopped_or_empty(this.gen2drv_chan);
this.gen2drv_chan.get(pkt);
`vmm_trace(this.log, "Starting transaction...");
`vmm_debug(this.log, pkt.psdisplay(" "));
`vmm_callback(Driver_callbacks,pre_trans(pkt));
drive(pkt);
`vmm_callback(Driver_callbacks,post_trans(pkt));
end
endtask
endclass
`endif
Now we will take the instance of the driver in the environment class.
1) Declare a channel "drvr2sb_chan" which will be used to connect the scoreboard and
driver.
Packet_channel drvr2sb_chan;
Driver drvr;
drvr2sb_chan = new("drvr2sb","chan");
4) In build method, construct the driver object. Pass the input_intf and drvr2sb_chan
channel and gen2drvr_chan channel.
drvr = new("Drvr",0,input_intf,gen2drvr_chan,drvr2sb_chan);
5) To start sending the packets to the DUT, call the start method of "drvr" in the start
method of Environment class.
drvr.start();
drvr.stop_xactor();
`ifndef GUARD_ENV
`define GUARD_ENV
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Packet_atomic_gen atomic_gen;
Driver drvr;
Packet_channel gen2drvr_chan;
Packet_channel drvr2sb_chan;
super.new("Environment ");
this.mem_intf = mem_intf_new ;
this.input_intf = input_intf_new ;
this.output_intf = output_intf_new ;
`vmm_note(this.log, "Created env object");
endfunction : new
drvr2sb_chan = new("drvr2sb","chan");
drvr = new("Drvr",0,input_intf,gen2drvr_chan,drvr2sb_chan);
atomic_gen = new("atomic_gen",0,gen2drvr_chan);
atomic_gen.stop_after_n_insts = 10;
`vmm_note(this.log,"End of build() method ");
endfunction
drvr.start_xactor();
drvr.stop_xactor();
endclass
`endif
vmm_switch_6.tar
Browse the code in vmm_switch_6.tar
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs 1) Extend vmm_xactor and define Receiver class.
class Receiver extends vmm_xactor;
OpenVera 1) Declare a virtual output_interface. We will connect this to the Physical interface of
Constructs the top module, same as what we did in environment class.
Switch TB
virtual output_interface.OP output_intf;
RVM Switch TB
RVM Ethernet sample 2) Declare a channel "rcvr2sb_chan" which is used to send the packets to the score
board
function new(string inst = "class",
int unsigned stream_id = -1,
virtual output_interface.OP output_intf_new,
Packet_channel rcvr2sb_chan);
super.new("Receiver",inst,stream_id);
this.output_intf = output_intf_new ;
if(rcvr2sb_chan == null)
`vmm_fatal(log,"rcvr2sb_channel is null");
else
this.rcvr2sb_chan = rcvr2sb_chan;
endfunction : new
forever
begin
repeat(2) @(posedge output_intf.clock);
wait(output_intf.cb.ready)
output_intf.cb.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin
bytes = new[bytes.size + 1](bytes);
bytes[bytes.size - 1] = output_intf.cb.data_out;
@(posedge output_intf.clock);
end
bytes[bytes.size - 1] = output_intf.cb.data_out;
output_intf.cb.read <= 0;
@(posedge output_intf.clock);
`vmm_note(this.log,"Received a packet ");
pkt = new();
pkt.byte_unpack(bytes);
pkt.display("rcvr");
rcvr2sb_chan.put(pkt);
bytes.delete();
end
class Receiver extends vmm_xactor;
virtual output_interface.OP output_intf;
Packet_channel rcvr2sb_chan;
function new(string inst = "class",
int unsigned stream_id = -1,
virtual output_interface.OP output_intf_new,
Packet_channel rcvr2sb_chan);
super.new("Receiver",inst,stream_id);
this.output_intf = output_intf_new ;
if(rcvr2sb_chan == null)
`vmm_fatal(log,"rcvr2sb_channel is null");
else
this.rcvr2sb_chan = rcvr2sb_chan;
endfunction : new
task main();
logic [7:0] bytes[];
Packet pkt;
super.main();
`vmm_note(this.log," started main task ");
forever
begin
repeat(2) @(posedge output_intf.clock);
wait(output_intf.cb.ready)
output_intf.cb.read <= 1;
repeat(2) @(posedge output_intf.clock);
while (output_intf.cb.ready)
begin
bytes = new[bytes.size + 1](bytes);
bytes[bytes.size - 1] = output_intf.cb.data_out;
@(posedge output_intf.clock);
end
bytes[bytes.size - 1] = output_intf.cb.data_out;
output_intf.cb.read <= 0;
@(posedge output_intf.clock);
`vmm_note(this.log,"Received a packet ");
pkt = new();
pkt.byte_unpack(bytes);
pkt.display("rcvr");
rcvr2sb_chan.put(pkt);
bytes.delete();
end
endtask : main
endclass
`endif
Now we will take the instance of the receiver in the environment class.
1) Declare a channel "rcvr2sb_chan" which will be used to connect the scoreboard and
receiver.
Packet_channel rcvr2sb_chan;
Receiver rcvr[4];
rcvr2sb_chan = new("rcvr2sb","chan");
4) In build method, construct the receiver object. Pass the output_intf and
rcvr2sb_chan. There are 4 output interfaces and receiver objects. We will connect
one receiver for one output interface.
foreach(rcvr[i])
rcvr[i] = new($psprintf("Rcvr-%0d",i),i,output_intf[i],rcvr2sb_chan);
rcvr[0].start_xactor();
rcvr[1].start_xactor();
rcvr[2].start_xactor();
rcvr[3].start_xactor();
6) Call the stop_xactor() method of the receiver object in the stop() method of the
Environment .
rcvr[0].stop_xactor();
rcvr[1].stop_xactor();
rcvr[2].stop_xactor();
rcvr[3].stop_xactor();
`ifndef GUARD_ENV
`define GUARD_ENV
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Packet_atomic_gen atomic_gen;
Driver drvr;
Receiver rcvr[4];
Packet_channel gen2drvr_chan;
Packet_channel drvr2sb_chan;
Packet_channel rcvr2sb_chan;
endfunction
rcvr2sb_chan = new("rcvr2sb","chan");
atomic_gen = new("atomic_gen",0,gen2drvr_chan);
atomic_gen.stop_after_n_insts = 10;
drvr = new("Drvr",0,input_intf,gen2drvr_chan,drvr2sb_chan);
foreach(rcvr[i])
rcvr[i] = new($psprintf("Rcvr-%0d",i),i,output_intf[i],rcvr2sb_chan);
rcvr[0].start_xactor();
rcvr[1].start_xactor();
rcvr[2].start_xactor();
rcvr[3].start_xactor();
rcvr[0].stop_xactor();
rcvr[1].stop_xactor();
rcvr[2].stop_xactor();
rcvr[3].stop_xactor();
endclass
`endif
vmm_switch_7.tar
Browse the code in vmm_switch_7.tar
Search ✔
Verilog
Verification
Verilog Switch TB
1) Declare 2 channels drvr2sb_chan and rcvr2sb_chan.
Basic Constructs
Packet_channel drvr2sb_chan;
Packet_channel rcvr2sb_chan;
OpenVera
Constructs 2) Declare a constructor method with drvr2sb_chan , rcvr2sb_chan , a string for
instance name and stream_id as arguments.
Switch TB
RVM Switch TB function new(string inst = "class",
int unsigned stream_id = -1,
RVM Ethernet sample Packet_channel drvr2sb_chan = null,
Packet_channel rcvr2sb_chan = null);
Specman E
3) Call the super.new() method and Connect the channels of the constructor to the
Interview Questions channels of the scoreboard.
super.new("sb",inst,stream_id);
if(drvr2sb_chan == null)
`vmm_fatal(this.log,"drvr2sb_channel is not constructed");
else
this.drvr2sb_chan = drvr2sb_chan;
if(rcvr2sb_chan == null)
`vmm_fatal(this.log,"rcvr2sb_channel is not constructed");
else
this.rcvr2sb_chan = rcvr2sb_chan;
`vmm_note(log,"Scoreboard created ");
4) Define vmm_xactor main() method. First call the super.main() method and then do
the following steps forever.
Wait until there is a packet is in "rcvr2sb_chan". Then pop the packet from channel.
rcvr2sb_chan.get(pkt_rcv);
$display(" %0d : Scorebooard : Scoreboard received a packet from receiver
",$time);
drvr2sb_chan.get(pkt_exp);
Compare both packets and assert an error if the comparison fails using `vmm_error.
if(pkt_rcv.compare(pkt_exp,msg))
$display(" %0d : Scoreboard :Packet Matched ",$time);
else
`vmm_error(this.log,$psprintf(" Packet MissMatched \n %s ",msg));
class Scoreboard extends vmm_xactor;
Packet_channel drvr2sb_chan;
Packet_channel rcvr2sb_chan;
function new(string inst = "class",
int unsigned stream_id = -1,
Packet_channel drvr2sb_chan = null,
Packet_channel rcvr2sb_chan = null);
super.new("sb",inst,stream_id);
if(drvr2sb_chan == null)
`vmm_fatal(this.log,"drvr2sb_channel is not constructed");
else
this.drvr2sb_chan = drvr2sb_chan;
if(rcvr2sb_chan == null)
`vmm_fatal(this.log,"rcvr2sb_channel is not constructed");
else
this.rcvr2sb_chan = rcvr2sb_chan;
`vmm_note(log,"Scoreboard created ");
endfunction:new
task main();
Packet pkt_rcv,pkt_exp;
string msg;
super.main();
forever
begin
rcvr2sb_chan.get(pkt_rcv);
$display(" %0d : Scoreboard : Scoreboard received a packet from receiver ",$time);
drvr2sb_chan.get(pkt_exp);
if(pkt_rcv.compare(pkt_exp,msg))
$display(" %0d : Scoreboard :Packet Matched ",$time);
else
`vmm_error(this.log,$psprintf(" Packet MissMatched \n %s ",msg));
end
endtask : main
endclass
`endif
Now we will see how to connect the scoreboard in the Environment class.
Scoreboard sb;
2) Construct the scoreboard in the build() method. Pass the drvr2sb_chan and
rcvr2sb_chan channels to the score board constructor.
sb = new("Sb",0,drvr2sb_chan,rcvr2sb_chan);
sb.start_xactor();
sb.stop_xactor();
`ifndef GUARD_ENV
`define GUARD_ENV
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Packet_atomic_gen atomic_gen;
Driver drvr;
Receiver rcvr[4];
Scoreboard sb;
Packet_channel gen2drvr_chan;
Packet_channel drvr2sb_chan;
Packet_channel rcvr2sb_chan;
sb = new("Sb",0,drvr2sb_chan,rcvr2sb_chan);
sb.start_xactor();
sb.stop_xactor();
$display("\n\n");
`vmm_note(this.log,"End of report() method");
endtask
endclass
`endif
vmm_switch_8.tar
Browse the code in vmm_switch_8.tar
size 6 ****
Normal[NOTE] on Receiver(Rcvr-3) at 890:
Received a packet
rcvr packet #0.0.0
rcvr da:0x33
rcvr sa:0x6b
rcvr length:0x03 (data.size=2)
rcvr data[0]:0x32 data[1]:0x27
rcvr fcs:0x1c
Search ✔
length : coverpoint pkt.length;
OpenVera
b) All port address:
Constructs
Switch TB da : coverpoint pkt.da {
bins p0 = { `P0 };
RVM Switch TB
bins p1 = { `P1 };
RVM Ethernet sample bins p2 = { `P2 };
bins p3 = { `P3 }; }
fcs_kind : coverpoint pkt.fcs_kind;
all_cross: cross length,da,length_kind,fcs_kind;
function new();
switch_coverage = new();
endfunction : new
3) Write task which calls the sample method to cover the points.
task sample(packet pkt);
this.pkt = pkt;
switch_coverage.sample();
endtask:sample
class DrvrCovCallback extends Driver_callbacks;
Packet pkt;
covergroup switch_coverage;
length : coverpoint pkt.length;
da : coverpoint pkt.da {
bins p0 = { `P0 };
bins p1 = { `P1 };
bins p2 = { `P2 };
bins p3 = { `P3 }; }
length_kind : coverpoint pkt.length_kind;
fcs_kind : coverpoint pkt.fcs_kind;
all_cross: cross length,da,length_kind,fcs_kind;
endgroup
function new();
switch_coverage = new();
endfunction : new
virtual task post_trans(Packet pkt);
this.pkt = pkt;
switch_coverage.sample();
endtask: post_trans
endclass:DrvrCovCallback
`endif
DrvrCovCallback cov_cb;
cov_cb = new();
3) In the Build method, call the append_callback() of the drvr and pass the cov_cb
object.
drvr.append_callback(cov_cb);
`ifndef GUARD_ENV
`define GUARD_ENV
virtual mem_interface.MEM mem_intf ;
virtual input_interface.IP input_intf ;
virtual output_interface.OP output_intf[4] ;
Packet_atomic_gen atomic_gen;
Driver drvr;
Receiver rcvr[4];
Scoreboard sb;
DrvrCovCallback cov_cb;
Packet_channel gen2drvr_chan;
Packet_channel drvr2sb_chan;
Packet_channel rcvr2sb_chan;
atomic_gen = new("atomic_gen",0,gen2drvr_chan);
atomic_gen.stop_after_n_insts = 10;
drvr = new("Drvr",0,input_intf,gen2drvr_chan,drvr2sb_chan);
foreach(rcvr[i])
rcvr[i] = new($psprintf("Rcvr-%0d",i),i,output_intf[i],rcvr2sb_chan);
sb = new("Sb",0,drvr2sb_chan,rcvr2sb_chan);
cov_cb = new();
drvr.append_callback(cov_cb);
atomic_gen.start_xactor();
drvr.start_xactor();
rcvr[0].start_xactor();
rcvr[1].start_xactor();
rcvr[2].start_xactor();
rcvr[3].start_xactor();
sb.start_xactor();
`vmm_note(this.log,"End of start() method ");
endtask
endclass
`endif
vmm_switch_9.tar
Browse the code in vmm_switch_9.tar
Search ✔
Verilog Tlm:
Verification
All the verification components use TLM interfacess whether they are class based or
Verilog Switch TB module based. Main operations on the TLM or put,get and peek.
Basic Constructs
Initiator puts transaction to a target and can get trasaction from a target.
EXAMPLE
Declare a tlm_fifo:
tlm_fifo#(packet) gen2drv;
gen.put_port = gen2drv.blocking_put_export;
drvr.get_port = gen2drv.blocking_get_export;
Building Blocks
There are two types of bases class used for building AVM components.
1)avm_named_component
2)avm_verificatino_component.
Avm_transactors:
Avm transaction is base class for creating tranctions. In order to allow the avm and
tlm libraries to work, we need methods to print, compare and clone transactions.
For any given transaction, T, to do four things to use avm_transaction:
Inherit from avm_transaction
Implement the virtual function string convert2string. This is for messaging.
Implement a function bit comp( input T t ). Used by the comparators for checking in
scoreboard.
Implement a function T clone(). This used for tlm_fifos. clone() returns a copy() of
.this(its object handle).
Avm_env:
avm_env class is the top level of testbench. avm_env has do_test() method which
starts building and execution of the testbench components.
Avm_messaging:
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet format:
OpenVera
Constructs Packet : Header, data and frame check sequence. Packet width is 8 bits and the
Switch TB length of the packet can be between 4 bytes to 259 bytes.
RVM Switch TB Packet header:
RVM Ethernet sample Packet header contains three fields DA, SA and length.
DA: Destination address of the packet. It is 8 bits. The switch drives the packet to
respective ports based on this destination address of the packets.
SA: Source address of the packet from where it originate.
Specman E Length: This is the length of the data. It can be from 0 to 255.
Interview Questions
Data: Data should be in terms of bytes. It can be between 0 to 255 bytes.
FCS: This field contains the security check of the packet. It is calculated over the
header and data.
Configuration:
Dut has four output ports. These output ports have to be configure to a address. Dut
matches the DA field of the packet with this configured port address and sends the
packet on to that port. To configure the dut, a memory interface is provided. The
address of the ports should be unique. It is 8 bits wide. Memory address (0,1,2,3)
contains the address of port(0,1,2,4) respectively.
Interface Specification:
The dut has one input Interface, from where the packet enters the dut and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured.
Memory Interface:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively. If the DA feild in the packet matches with
the confugured address of any port ,then the packet comes out of that port.
Input Interface:
The status signal has to be high when data is when packet is sent on to the dut it has
to become low after sending last byte of the packet. 2 clocks gap should be
maintained between packets.
Output Interface:
There are 4 ports, each having data, ready and read signals.
When the data is ready to be sent out from the port, dut makes the ready signal high
indicating that data is ready to be sent.
If the read signal is made high when ready is high, then the data comes out of the
data signal.
Search ✔
end
end
end
endmodule //fifo
module port_fsm (clk,
reset,
write_enb,
ffee,
hold,
data_status,
data_in,
data_out,
mem0,
mem1,
mem2,
mem3,
addr);
input clk;
input reset;
input [7:0] mem0;
input [7:0] mem1;
input [7:0] mem2;
input [7:0] mem3;
output[3:0] write_enb;
input ffee;
input hold;
input data_status;
input[7:0] data_in;
output[7:0] data_out;
output [7:0] addr;
reg [7:0] data_out;
reg [7:0] addr;
reg [3:0] write_enb_r;
reg fsm_write_enb;
reg [3:0] state_r;
reg [3:0] state;
reg [7:0] parity;
reg [7:0] parity_delayed;
reg sus_data_in,error;
parameter ADDR_WAIT = 4'b0000;
parameter DATA_LOAD = 4'b0001;
parameter PARITY_LOAD = 4'b0010;
parameter HOLD_STATE = 4'b0011;
parameter BUSY_STATE = 4'b0100;
always@(negedge reset)
begin
error = 1'b0;
data_out = 8'b0000_0000;
addr = 8'b00000000;
write_enb_r = 3'b000;
fsm_write_enb = 1'b0;
state_r = 4'b0000;
state = 4'b0000;
parity = 8'b0000_0000;
parity_delayed = 8'b0000_0000;
sus_data_in = 1'b0;
end
assign busy = sus_data_in;
always @(data_status) begin : addr_mux
if (data_status == 1'b1) begin
case (data_in)
mem0 : begin
write_enb_r[0] = 1'b1;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem1 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b1;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem2 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b1;
write_enb_r[3] = 1'b0;
end
mem3 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b1;
end
default :write_enb_r = 3'b000;
endcase
// $display(" data_inii %d ,mem0 %d ,mem1 %d ,mem2 %d
mem3",data_in,mem0,mem1,mem2,mem3);
end //if
end //addr_mux;
always @(posedge clk) begin : fsm_state
state_r <= state;
end //fsm_state;
state = HOLD_STATE;
end //if
sus_data_in = 1'b0;
if ((data_status == 1'b1) &&
(hold == 1'b0)) begin
data_out = data_in;
fsm_write_enb = 1'b1;
end
else if ((data_status == 1'b0) &&
(hold == 1'b0)) begin
data_out = data_in;
fsm_write_enb = 1'b1;
end
else begin
fsm_write_enb = 1'b0;
end //if
end //end of case DATA_LOAD
HOLD_STATE : begin
if (hold == 1'b1) begin
state = HOLD_STATE;
end
else if ((hold == 1'b0) && (data_status == 1'b0)) begin
state = PARITY_LOAD;
end
else begin
state = DATA_LOAD;
end //if
if (hold == 1'b1) begin
sus_data_in = 1'b1;
fsm_write_enb = 1'b0;
end
else begin
fsm_write_enb = 1'b1;
data_out = data_in;
end //if
end //end of case HOLD_STATE
BUSY_STATE : begin
if (ffee == 1'b0) begin
state = BUSY_STATE;
end
else begin
state = DATA_LOAD;
end //if
if (ffee == 1'b0) begin
sus_data_in = 1'b1;
end
else begin
addr = data_in; // hans
data_out = data_in;
fsm_write_enb = 1'b1;
end //if
end //end of case BUSY_STATE
endcase
end //fsm_core
assign write_enb[0] = write_enb_r[0] & fsm_write_enb;
assign write_enb[1] = write_enb_r[1] & fsm_write_enb;
assign write_enb[2] = write_enb_r[2] & fsm_write_enb;
assign write_enb[3] = write_enb_r[3] & fsm_write_enb;
endmodule //port_fsm
module switch (clk,
reset,
data_status,
data,
port0,
port1,
port2,
port3,
ready_0,
ready_1,
ready_2,
ready_3,
read_0,
read_1,
read_2,
read_3,
mem_en,
mem_rd_wr,
mem_add,
mem_data);
input clk;
input reset;
input data_status;
input [7:0] data;
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
wire [7:0] data_out_0;
wire [7:0] data_out_1;
wire [7:0] data_out_2;
wire [7:0] data_out_3;
wire ll0;
wire ll1;
wire ll2;
wire ll3;
wire empty_0;
wire empty_1;
wire empty_2;
wire empty_3;
wire ffee;
wire ffee0;
wire ffee1;
wire ffee2;
wire ffee3;
wire ld0;
wire ld1;
wire ld2;
wire ld3;
wire hold;
wire [3:0] write_enb;
wire [7:0] data_out_fsm;
wire [7:0] addr;
reg [7:0]mem[3:0];
wire reset;
fifo queue_0 (.clk (clk),
.reset (reset),
.write_enb (write_enb[0]),
.read (read_0),
.data_in (data_out_fsm),
.data_out (data_out_0),
.empty (empty_0),
.full (ll0));
.reset (reset),
.write_enb (write_enb[2]),
.read (read_2),
.data_in (data_out_fsm),
.data_out (data_out_2),
.empty (empty_2),
.full (ll2));
always@(posedge clk)
begin
if(mem_en)
if(mem_rd_wr)
begin
mem[mem_add]=mem_data;
///$display("%d %d %d %d %d",mem_add,mem[0],mem[1],mem[2],mem[3]);
end
end
endmodule //router
Search ✔
Verilog
CODE: top.v
Verification `include "mem_env.sv"
Verilog Switch TB
module top();
Basic Constructs
.mem_en (intf.mem_en),
.mem_rd_wr (intf.mem_rd_wr),
.mem_add (intf.mem_add),
.mem_data (intf.mem_data));
Search ✔
endinterface:switch_if
`endif
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
if (!cfg.randomize())
avm_report_error("gen_cfg","Configuration Randomization Failed!\n");
cfg.display();
avm_report_message("gen_cfg"," Ending.... Gen_cfg \n");
pkt.do_cfg(cfg);
// connect all the virtual interfacess.
drvr.intf = intf;
rcvr_0.intf = intf;
rcvr_1.intf = intf;
rcvr_2.intf = intf;
rcvr_3.intf = intf;
// connect all the TLM interfacess
gen.put_port = gen2drv.blocking_put_export;
drvr.get_port = gen2drv.blocking_get_export;
drvr.put_sb = drv2sb.blocking_put_export;
rcvr_0.put_sb = rcv2sb.blocking_put_export;
sb.drv_port = drv2sb.blocking_get_export;
sb.rcv_port = rcv2sb.blocking_get_export;
endfunction
task execute;
Search ✔
Specman E
Interview Questions // Control field for GOOD/BAD
rand packet_kind_t packet_kind;
packet t = new();
t.copy( this );
return t;
endfunction
function void do_cfg(Configuration cfg);
this.mem[0]= cfg.da_port[0];
this.mem[1]= cfg.da_port[1];
this.mem[2]= cfg.da_port[2];
this.mem[3]= cfg.da_port[3];
$swrite(msg," packet new ::%x %x %x %x",mem[0],mem[1],mem[2],mem[3]);
avm_report_message("packet",msg);
endfunction
// as per avm, define convert2string
function string convert2string;
string psdisplay;
int i;
$write(psdisplay, "da:0x%h sa:0x%h len:0x%h \n",this.da,this.sa,this.len,);
for (i = 0; i < this.len; i++) $write(psdisplay, "%s data[%0d] 0x%h
\n", psdisplay,i, data[i]);
$write(psdisplay,"%s parity :0x%h \n",psdisplay,this.parity);
convert2string = psdisplay;
endfunction
function void copy(input packet to = null);
\n", this.da, this.sa, this.len);
avm_report_message("packet",msg);
data = new [len - 4];
parity = bytes.pop_back();
foreach (data[i]) data[i] = bytes.pop_front();
endfunction
function byte parity_cal();
integer i;
byte result ;
result = result ^ this.da;
result = result ^ this.sa;
result = result ^ this.len;
for (i = 0;i<this.len;i++)
begin
result = result ^ this.data[i];
end
return result;
endfunction
//post randomize fun to cal parity
function void post_randomize();
data = new[len];
foreach(data[i])
data[i] = $random();
parity = parity ^ parity_cal();
endfunction
function void pre_randomize();
data.delete();
endfunction
begin
$swrite(diff,"Different data[%0d] values: 0x%h !=
0x%h",i, to.data[i], cmp.data[i]);
compare = 0;
avm_report_error("packet",diff);
return compare;
end
if (to.parity != cmp.parity)
begin
$swrite(diff,"Different PARITY values: %b != %b", to.parity, cmp.parity);
compare = 0;
avm_report_error("packet",diff);
return compare;
end
return 1;
endfunction
function int unsigned byte_pack(ref logic [7:0] bytes[],
input int unsigned offset ,
input int kind);
byte_pack = 0;
bytes = new[this.len + 4];
bytes[0] = this.da;
bytes[1] = this.sa;
bytes[2] = this.len;
foreach(data[i])
bytes[3+i] = data[i];
bytes[this.len + 3 ] = parity;
byte_pack = this.len + 4;
endfunction
endclass
`endif
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
task run;
Verilog endtask
Verification
endclass
Verilog Switch TB `endif
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog task run;
Verification
Verilog Switch TB reset_dut();
Basic Constructs cfg_dut();
forever
begin
get_port.get(pkt);
OpenVera $display("consumer: sendging %s packet\n", pkt.convert2string);
Constructs drive(pkt);
Switch TB avm_report_message("Driver","Puting packet to score board");
put_sb.put(pkt);
RVM Switch TB @(negedge intf.clock);
RVM Ethernet sample
end
endtask
Specman E
Interview Questions
task drive(packet pkt);
logic [7:0] pack[];
int pkt_len;
pkt_len = pkt.byte_pack(pack,0,0);
$swrite(this.msg,"Packed packet length %d \n",pkt_len);
avm_report_message("Driver",this.msg);
@(negedge intf.clock);
for (int i=0;i< pkt_len - 1;i++)
begin
@(negedge intf.clock);
intf.data_status <= 1 ;
intf.data_in <= pack[i];
end
@(negedge intf.clock);
intf.data_status <= 0 ;
intf.data_in <= pack[pkt_len -1];
@(negedge intf.clock);
endtask
task reset_dut();
avm_report_message("reset_dut"," Starting... reset_dut \n");
@(negedge intf.clock);
avm_report_message("reset_dut"," Starting... reset_dut \n");
intf.data_status <= 0;
intf.data_in <= 0;
intf.read <= 0;
intf.mem_data <= 0;
intf.mem_add <= 0;
intf.reset <= 0;
intf.mem_en <= 0;
intf.mem_rd_wr <= 0;
@(negedge intf.clock);
#2 intf.reset <= 1;
@(negedge intf.clock);
#2 intf.reset <= 0;
@(negedge intf.clock);
@(negedge intf.clock);
avm_report_message("reset_dut"," Ending... reset_dut \n");
endtask
task cfg_dut() ;
avm_report_message("cfg_dut"," Starting... cfg_dut \n");
for(int i = 0;i<4 ;i++)
begin
intf.mem_en <= 1;
@(negedge intf.clock);
intf.mem_rd_wr <= 1;
@(negedge intf.clock);
intf.mem_add <= i;
intf.mem_data <= cfg.da_port[i];
end
@(negedge intf.clock);
intf.mem_en <= 0;
intf.mem_rd_wr <= 0;
intf.mem_add <= 0;
intf.mem_data <= 0;
endtask
endclass
Search ✔
pkt.unpack(received_bytes);
received_bytes = {};
OpenVera rcv_pkt = new pkt;
Constructs put_sb.put(rcv_pkt);
Switch TB end
RVM Switch TB endtask
RVM Ethernet sample
endclass
Specman E
Interview Questions
Search ✔
avm_report_message("sb","Scoreboard created");
Verilog endfunction
Verification
Verilog Switch TB task run();
Basic Constructs
avm_report_message("sb"," STARTED main task ");
fork
forever
OpenVera begin
Constructs drv_port.get(drv_pkt);
Switch TB this.no_drv_pkt++;
$swrite(msg,"Recieved packet no from driver %d size of
RVM Switch TB queue%d\n",no_rcv_pkt,exp_que.size());
RVM Ethernet sample avm_report_message("sb",msg);
exp_que.push_front(drv_pkt);
Specman E end
Interview Questions join_none
forever
begin
rcv_port.get(rcv_pkt);
this.no_rcv_pkt++;
exp_pkt = exp_que.pop_back();
else
avm_report_error("sb"," Packet mismatch ");
end
endtask
endclass
`endif
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
0:000234ac
Specman E 1:00023ca5
Interview Questions 2:000b3c34
3:00023a4a
4:000234ca
5:000b3234
module readmemh_demo;
reg [31:0] Mem [0:11];
`include "data.v"
integer k;
initial begin
#10;
$display("Contents of Mem after reading data file:");
for (k=0; k<6; k=k+1) $display("%d:%h",k,Mem[k]);
end
endmodule
RESULT:
0:000234ac
1:00023ca5
2:000b3c34
3:00023a4a
4:000234ca
5:000b3234
Search ✔
With the above style of testbench, the controllability is less and hard to change the
code to add new features like to convert the above code to alternate read and write
operation, its very difficult.
Search ✔
initial
Specman E repeat(10)
Interview Questions begin
write($random,$random);
read($random,data);
end
initial
begin
write(10,20);
read (10,data);
end
Search ✔
Specman E
Interview Questions
Stimulus Generator:
In order to test the model of some design, a verification engineer must apply test
patterns to the input ports and observe the output ports over time to decide whether
the inputs were transformed to the expected outputs. The generator component
generates input vectors. For simple memory stimulus generator generates read, write
operations, address and data to be stored in the address if its write operation.
Modern generators generate random, biased, and valid stimuli. In verilog $random
does this job. The randomness is important to achieve a high distribution over the
huge space of the available input stimuli. To this end, users of these generators
intentionally under-specify the requirements for the generated tests. It is the role of
the generator to randomly fill this gap. This mechanism allows the generator to
create inputs that reveal bugs not being searched for directly by the user. Generators
also bias the stimuli toward design corner cases to further stress the logic. Biasing and
randomness serve different goals and there are tradeoffs between them, hence
different generators have a different mix of these characteristics. Since the input for
the design must be valid and many targets should be maintained, many generators use
the Constraint Satisfaction Problem technique to solve the complex testing
requirements. SystemVerilog, Vera, SystemC and Specman have " constraints " to
specify The legality of the design inputs. In verilog ,to constrain the memory address
to be between 0 to 63, {$random} % 64 is used. The model-based generators use this
model to produce the correct stimuli for the target design. The stimulus generator
should be intelligent and easily controllable.
The Bus Functional Model (BFM) for a device interacts with the DUT by both driving
and sampling the DUT signals. A bus functional model is a model that provides a task
or procedural interface to specify certain bus operations for a defined bus protocol.
For a memory DUT, transactions usually take the form of read and write operations.
Bus functional models are easy to use and provide good performance. It has to follow
the timing protocol of the DUT interface. BFM describes the functionality and provides
a cycle accurate interface to DUT. It models external behavior of the device. For re
usability, the implementation of the BFM functionality should be kept as independent
of the communication to the BFM as it can be.
Driver
Driver is a types of BFM. The drivers translate the stimuli produced by the generator
into the actual inputs for the design under verification. Generators create inputs at a
high level of abstraction; namely, as transactions like read write operation. The
drivers convert this input into actual design inputs which is at a low level like bits ,as
defined in the specification of the designs interface. If the generator generates read
operation, then read task is called, in that, the DUT input pin "read_write" is asserted.
Reciver
Receiver is also a type of BFM. The output of the DUT is collected. The output of the
DUT is available in a low level format. Let<92>s take a packet protocol. The interface
has "start of the packet" and "end of packet" signal to indicate the packet arrival. The
receiver starts collecting the packet looking at the signal "start of packet" and does
this job until "end of the packet".
Protocol Monitor:
Protocol monitor do not drive any signals, monitor the DUT outputs, identifies all the
transactions and report any protocol violations. The monitor converts the state of the
design and its outputs to a transaction abstraction level so it can be stored in a 'score-
boards' database to be checked later on. Again let<92>s take a packet protocol. The
monitor gets the information from the packet like, length of the packet, address of
the packet etc.
Scoreboard:
done on a memory with address 101 and data 202,asfter some cycles, if a read is done
at address 101,what should be the data?.The score board recorded the address and
data when write operation is done. Get the data stored at address of 101 in
scoreboard and compare with the output of the DUT in checker. Scoreboard also has
expected logic if needed. Take an 2 input and gate. The expect logic does the " and "
operation on the two inputs and stores the output.
Checker:
Checker is part of score board. The checker validates that the contents of the 'score-
boards' are legal. There are cases where the generator creates expected results, in
addition to the inputs. In these cases, the checker must validate that the actual
results match the expected ones.
Coverage:
Coverages are of two types, Functional coverage and code coverage. Code coverage is
not part of Testbench. Functional Coverage is part of test bench. Functional coverage
cannot be done in Verilog.
Code Coverage:
Code coverage, in short, is all about how thoroughly your tests exercise your code
base. The intent of tests, of course, is to verify that your code does what it's
expected to, but also to document what the code is expected to do. Taken further,
code coverage can be considered as an indirect measure of quality -- indirect because
we're talking about the degree to what our tests cover our code, or simply, the
quality of tests. In other words, code coverage is not about verifying the end product's
quality.
Functional Coverage:
Functional is the metric which shows how much we have verified. It shows how many
possible scenarios are possible and how many are covered. Take a memory. If the
memory address is 64 byte depth, and if the address is generated randomly, we are
not sure that every location is covered. Functional coverages gives report how many
address are possible and how may we have covered.
Search ✔
Specman E
Interview Questions
Search ✔
endmodule
RESULTS:
End of simulation time is 50000 , total number of clocks seen is 12500 expected is
10000
Total number of clocks are 12500 and the expected are 1000.There are 25 % of more
clocks than expected. The reason is half clock period is 2 insted of 2.5.
Make sure that CLOCK_PERIOD is evenly divided by two. If CLOCK_PERIOD is odd, the
reminder is truncated the frequency of the clock generated in not what expected. If
integer division is replaced by real division, the result is rounded off according to the
specified resolution.
EXAMPLE:
module Tb();
reg clock;
integer no_of_clocks;
parameter CLOCK_PERIOD = 5;
initial no_of_clocks = 0;
initial clock = 1'b0;
always #(CLOCK_PERIOD/2.0) clock = ~clock;
always@(posedge clock)
no_of_clocks = no_of_clocks +1 ;
initial
begin
#50000;
$display("End of simulation time is %d , total number of clocks seen is %d
expected is %d",$time,no_of_clocks,($time/5));
$finish;
end
endmodule
RESULTS:
End of simulation time is 50000 , total number of clocks seen is 8333 expected is
10000
Look at the result, total number of clock seen are 8333, where the rest of the clocks
have gone? There is some improvement than earlier example. But the results are not
proper. Well that is because of `timeprecision. By default time precision is 1ns/1ns.
Half of the clock period is 2.5 . It is rounded of to 3 . So total time period is 6 and
resulted 8333 clocks( 50000/6) instead of (50000/5). 2.5 can be rounded to 3 or 2 .
LRM is specific about this. So try out this example on your tool. You may see 12500.
Delay unit is specified using 'timescale, which is declared as `timescale time_unit base
/ precision base
--time_unit is the amount of time a delay of 1 represents. The time unit must be 1 10
or 100
--base is the time base for each unit, ranging from seconds to femtoseconds, and
must be: s ms us ns ps or fs
--precision and base represent how many decimal points of precision to use relative
to the time units.
Time precision plays major role in clock generators. For example, to generate a clock
with 30% duty cycle and time period 5 ns ,the following code has some error.
EXAMPLE:
`timescale 1ns/100ps
module Tb();
reg clock;
integer no_of_clocks;
parameter CLOCK_PERIOD = 5;
initial clock = 1'b0;
always
begin
#(CLOCK_PERIOD/3.0) clock = 1'b0;
#(CLOCK_PERIOD - CLOCK_PERIOD/3.0) clock = 1'b1;
end
initial no_of_clocks = 0;
always@(posedge clock)
no_of_clocks = no_of_clocks +1 ;
initial
begin
#50000;
$display(" End of simulation time is %d , total number of clocks seen is %d
expected is %d",$time,no_of_clocks,($time/5));
$finish;
end
endmodule
RESULTS:
End of simulation time is 50000 , total number of clocks seen is 9999 expected is
10000
Now CLOCK_PERIOD/3.0 is 5/3 which is 1.666. As the time unit is 1.0ns, the delay is
1.666ns. But the precision is 100ps. So 1.666ns is rounded to 1.700ns only.
and when (CLOCK_PERIOD - CLOCK_PERIOD/3.0) is done, the delay is 3.300ns instead
of 3.333.The over all time period is 5.If the clock generated is implemented without
taking proper care, this will be the biggest BUG in testbench.
All the above clock generators have hard coded duty cycle. The following example
shows the clock generation with parameterizable duty cycle. By changing the
duty_cycle parameter, different clocks can be generated. It is beneficial to use
parameters to represent the delays, instead of hard coding them. In a single
testbench, if more than one clock is needed with different duty cycle, passing duty
cycle values to the instances of clock generators is easy than hard coding them.
EXAMPLE:
parameter CLK_PERIOD = 10;
parameter DUTY_CYCLE = 60; //60% duty cycle
parameter TCLK_HI = (CLK_PERIOD*DUTY_CYCLE/100);
parameter TCLK_LO = (CLK_PERIOD-TCLK_HI);
reg clk;
initial
clk = 0;
always
begin
#TCLK_LO;
clk = 1'b1;
#TCLK_HI;
clk = 1'b0;
end
Make sure that parameter values are properly dividable. The following example
demonstrates how the parameter calculations results. A is 3 and when it is divided by
2,the result is 1.If integer division is replaced by real division, the result is rounded
off according to the specified resolution. In the following example is result of real
number division.
EXAMPLE:
module Tb();
parameter A = 3;
parameter B = A/2;
parameter C = A/2.0;
initial
begin
$display(" A is %e ,B is %e ,C is %e ",A,B,C);
end
endmodule
RESULTS:
EXAMPLE:
initial clock = 1'b0;
always clock = #1 ~clock;
jitter = $random() % range;
assign jittered_clock = #(jitter) clock;
With the above approace,over all clock period is increased. A better approach for
clock divider is as follows
EXAMPLE:
parameter DELAY = TIMEPERIOD/2.0 - range/2.0;
initial clock = 1'b0;
always
begin
jitter = $dist_uniform(seed,0,jitter_range);
#(DELAY + jitter) clock = ~clock;
end
Clock dividers and multipliers are needed when more than one clock is needed to be
generated from base clock and it should be deterministic. Clock multipliers are simple
to design. A simple counter does this job. Clock division is little bit tricky. TO design a
lock divider i.e a frequency multiplier, first the time period has to be captured and
then it is used to generate another clock. With the following approach, the jitter in
the base clock is carried to derived clock.
always@(posedge base_clock)
begin
T2 = $realtime;
period = T2 - T1;
T1 = T2;
end
Search ✔
Optimization:
Specman E
Interview Questions Some tools support optimization at this level. This is optional step.
Initialization :
Initial values preset in the declarations statement are assigned to signals / variables.
Execution
Every process is executed until it suspends. Signal values are updated only after the
process suspends. Simulator accepts simulation commands like (run, assign, watch),
which control the simulation of the system and specify the desired simulator
output. Simulation ends when all signals have been updated and new values have
been assigned to signals. This design hierarchy is stored in a simulation snapshot. The
snapshot is the representation of your design that the simulator uses to run the
simulation.
Simulation Process :
Search ✔
Specman E
Interview Questions
Search ✔
All three system tasks take a file name as a parameter. The file name has to be
Specman E supplied as a string enclosed in quotation marks.
Interview Questions
The $save system task saves the complete state into the host operating system file
specified as a parameter.
The $incsave system task saves only what has changed since the last invocation of
$save. It is not possible to do an incremental save on any file other than the one
produced by the last $save.
The $restart system task restores a previously saved state from a specified file.
Restarting from an incremental save is similar to restarting from a full save, except
that the name of the incremental save file is specified in the restart command. The
full save file that the incremental save file was based upon shall still be present, as it
is required for a successful restart. If the full save file has been changed in any way
since the incremental save was performed, errors will result.
Take care while using Pli application . Since PLI application may have some other form
of simulation snapshot storage, the simulation tool doesn't have the control on them.
$save system task, creates a checkpoint file and PLI tr routines are there to save the
PLI snapshot.
Search ✔
Specman E
Interview Questions
Search ✔
STATEMENT 1 :: time is 8
STATEMENT 2 :: delay for 8
EXAMPLE:
`timescale 10ns/1ns
module tim();
reg i;
initial
begin
i=0;
#7.7212;
i=1;
$display("STATEMENT 1 :: time is ",$stime);
#7.123;
$finish;
end
endmodule
module try;
time delay_time = 7.721;
initial begin
$display("STATEMENT 2 :: delay for %0t",delay_time );
end
endmodule
RESULTS:
STATEMENT 1 :: time is 8
STATEMENT 2 :: delay for 80
EXAMPLE:
`timescale 10ns/1ps
module tim();
reg i;
initial
begin
i=0;
#7.7212;
i=1;
$display("STATEMENT 1 :: time is ",$stime);
#7.123;
$finish;
end
endmodule
module try;
time delay_time = 7.721;
initial begin
$display("STATEMENT 2 :: delay for %0t",delay_time );
end
endmodule
RESULTS:
STATEMENT 1 :: time is 8
STATEMENT 2 :: delay for 80000
In the timescale statement, the first value is the time unit and the second is the
precision for the simulation. So with the time unit, when the simulator displays a
value, you just have to multiply the value by this time unit to get the real time. With
a 10ns time unit, when a delay of #7.7212, that means that it is 77.212ns delay.
Now the second one (time precision) specify with which precision time values are
rounded. Asking for a 77.212ns delay is possible only with a 1ps precision. That's what
you can see with reg i. It toggles at 77ns with a 1ns precision and 77.212 with a 1ps
precision.
For the STATEMENT 1, $stime returns an integer scaled to timesale unit, that's why
results are always 8 which is 7.7212 rounded up to 8.
Now for STATEMENT 2, the way %t is printed depends on $timeformat. It seems that in
this case, 7.7212 is first rounded to an integer => 8 and then printed according to your
time precision.
Im not sure of this topic. If some one finds mistake in my understanding, please mail
me at gopi@testbench.in
Each module can have separate time scale. The smallest time_precision argument of
all the timescale compiler directives in the design determines the precision of the
time unit of the simulation.
Lets take an example. There are two modules. Module_1 is instance od Module_2.
Module_1 has timescale of 1 ns/1ps. Module_2 has time scale of 1ns / 10ps. The
smallest resolution is 1ps. This is taken as simulator resolution but each module
evaluates according to its precision mentioned.
Lets take another example. There are two modules. Module_1 is instance of
Module_2. Module_1 does not have any time scale. Module_2 is having time scale of
1ns/100 ps. As there is no time scale for Module_1 ,the simulator takes precision and
time unit of 100 ps i.e `timescale 100 ps/100 ps.
$Time Vs $Realtime
$time round offs the time to nearby integer where as $realtime does not. So when
you are using real valued delays, then use $realtime instead of $time , else there may
be a misunderstanding during debugging.
The $printtimescale system task displays the time unit and precision for a particular
module. When no argument is specified, $printtimescale displays the time unit and
precision of the module that is the current scope. When an argument is specified,
$printtimescale displays the time unit and precision of the module passed to it.
EXAMPLE:
`timescale 1 ms / 1 us
module a_dat;
initial
$printtimescale(b_dat.c1);
endmodule
`timescale 10 fs / 1 fs
module b_dat;
c_dat c1 ();
endmodule
`timescale 1 ns / 1 ns
module c_dat;
endmodule
RESULTS:
The units number argument shall be an integer in the range from 0 to -15. This
argument represents the time
unit as shown in table
Syntax : $timeformat(time unit, precision number, suffix string, and minimum field
width);
EXAMPLE:
`timescale 1 ms / 1 ns
module cntrl;
initial
$timeformat(-9, 5, " ns", 10);
endmodule
`timescale 1 fs / 1 fs
module a1_dat;
reg in1;
integer file;
buf #10000000 (o1,in1);
initial begin
file = $fopen("a1.dat");
#00000000 $fmonitor(file,"%m: %t in1=%d o1=%h", $realtime,in1,o1);
#10000000 in1 = 0;
#10000000 in1 = 1;
end
endmodule
RESULTS:
EXAMPLE:
`timescale 1 ms / 1 ns
module cntrl;
initial
$timeformat(-9, 5, " ns", 10);
endmodule
`timescale 1 ps / 1 ps
module a2_dat;
reg in2;
integer file2;
buf #10000 (o2,in2);
initial begin
file2=$fopen("a2.dat");
#00000 $fmonitor(file2,"%m: %t in2=%d o2=%h",$realtime,in2,o2);
#10000 in2 = 0;
#10000 in2 = 1;
end
endmodule
RESULTS:
Search ✔
Fallowing example illustrates how to initialize a memory array from data stored as
hexadecimal values in a data file, Simulate this file directly to see the results.
Note: The data file must reside in the same directory as the .v file for the module in
this example.
reg [31:0] Mem [0:11];
initial $readmemh("data.txt",Mem);
integer k;
initial begin
#10;
$display("Contents of Mem after reading data file:");
for (k=0; k<6; k=k+1) $display("%d:%h",k,Mem[k]);
end
endmodule
RESULT:
0:000234ac
1:00023ca5
2:000b3c34
3:00023a4a
4:000234ca
5:000b3234
With the above approach,its not possible to list all the combinations manually if the
number of vectors get increases.
Search ✔
initial
$monitor("address = %d;",address);
endmodule
RESULT:
address = 303379748;
address = -1064739199;
address = -2071669239;
address = -1309649309;
address = 112818957;
We have seen how to generate random numbers. But the numbers range from - (2**32
-1) to 2 **32. Most of the time, the requirement don't need this range. For example,
take a memory. The address starts from 0 to some 1k or 1m.Generating a random
address which DUT is not supporting is meaningless. In verilog there are no constructs
to constraint randomization. Fallowing example demonstrated how to generate
random number between 0 to 10.Using % operation, the remainder of any number is
always between 0 to 10.
EXAMPLE:
module Tb();
integer add_1;
initial
begin
repeat(5)
begin
#1;
add_1 = $random % 10;
end
end
initial
$monitor("add_1 = %d",add_1);
endmodule
RESULT:
add_1 = 8;
add_1 = 4294967287;
add_1 = 4294967295;
add_1 = 9;
add_1 = 9;
OOPS!...... The results are not what is expected. The reason is $random generates
negative numbers also. The following example demonstrates proper way of generating
a random number between 0 to 10. Concatenation operator returns only bit vector.
Bit vectors are unsigned, so the results are correct as we expected. Verilog also has
$unsigned systemtask to convert signed numbers to signed number. This can also be
used to meet the requirements. The following example shows the usage of
concatenation operator and $unsigned.
EXAMPLE:
module Tb();
integer add_2;
reg [31:0] add_1;
integer add_3;
initial
begin
repeat(5)
begin
#1;
add_1 = $random % 10;
add_2 = {$random} %10 ;
add_3 = $unsigned($random) %10 ;
end
end
initial
$monitor("add_3 = %d;add_2 = %d;add_1 = %d",add_3,add_2,add_1);
endmodule
RESULT:
The above example shows the generation of numbers from 0 to N.Some specification
require the range to start from non Zero number. MIN + {$random} % (MAX - MIN ) will
generate random numbers between MIN and MAX.
EXAMPLE:
module Tb();
integer add;
initial
begin
repeat(5)
begin
#1;
add = 40 + {$random} % (50 - 40) ;
$display("add = %d",add);
end
end
endmodule
RESULT:
add = 48
add = 47
add = 47
add = 47
add = 47
Now how to generate a random number between two ranges? The number should be
between MIN1 and MAX1 or MIN2 and MAX2.The following example show how to
generate this specification.
EXAMPLE:
module Tb();
integer add;
initial
begin
repeat(5)
begin
#1;
if($random % 2)
add = 40 + {$random} % (50 - 40) ;
else
add = 90 + {$random} % (100 - 90) ;
$display("add = %d",add);
end
end
endmodule
RESULT:
add = 97
add = 47
add = 47
add = 42
add = 49
All the random number generates above generate numbers of 32 vector. Not always
the requirements are 32 bit .For example, to generate a 5 bit and 45 bit vector
random number, the following method can be used.
EXAMPLE:
module Tb();
reg [4:0] add_1;
reg [44:0] add_2;
initial
begin
repeat(5)
begin
add_1 = $random ;
add_2 = {$random,$random};
$display("add_1 = %b,add_2 = %b ",add_1,add_2);
end
end
endmodule
RESULTS:
Some protocols require a random number which is multiple some number. For
example, Ethernet packet is always in multiples of 8bits,and PCIExpress packets are
multiples of 4byts .Look at the following example. It generates a random number
which is multiple of 3 and 5.
EXAMPLE:
module Tb();
integer num_1,num_2,tmp;
initial
begin
repeat(5)
begin
#1;
tmp = {$random} / 3;
num_1 = (tmp) * 3;
tmp = {$random} / 3;
num_2 = (tmp) * 5;
$display("num_1 = %d,num_2 = %d",num_1,num_2);
end
end
endmodule
RESULT:
All the above example show that the random numbers are integers only. In verilog
there is not special construct to generate a random real number. The following
method shows the generation of random real number.
EXAMPLE:
module Tb();
integer num_1,num_2,num_3;
real r_num;
initial
begin
repeat(5)
begin
#1;
num_1 = $random;
num_2 = $random;
num_3 = $random;
r_num = num_1 + ((10)**(-(num_2)))*(num_3);
$display("r_num = %e",r_num);
end
end
endmodule
RESULT:
r_num = -2.071669e+03
r_num = 2641.189059e+013
r_num = 976361.598336e+01
r_num = 57645.126096e+02
r_num = 24589.097015e+0
To generate random real number , system function $bitstoreal can also be used.
EXAMPLE:
module Tb();
real r_num;
initial
begin
repeat(5)
begin
#1;
r_num = $bitstoreal({$random,$random});
$display("r_num = %e",r_num);
end
end
endmodule
RESULTS:
r_num = 1.466745e-221
r_num = -6.841798e-287
r_num = 2.874848e-276
r_num = -3.516622e-64
r_num = 4.531144e-304
If you want more control over randomizing real numbers in terms of sign, exponential
and mantissa, use $bitstoreal() as shown in example below. For positive numbers, use
sgn = 0 etc.
EXAMPLE:
module Tb();
reg sgn;
reg [10:0] exp;
reg [51:0] man;
real r_num;
initial
begin
repeat(5)
begin
sgn = $random;
exp = $random;
man = $random;
r_num = $bitstoreal({sgn,exp,man});
$display("r_num = %e",r_num);
end
end
endmodule
RESULTS:
r_num = 3.649952e+193
r_num = -1.414950e-73
r_num = -3.910319e-149
r_num = -4.280878e-196
r_num = -4.327791e+273
EXAMPLE:
module Tb();
integer num,i,j,index;
integer arr[9:0];
reg ind[9:0];
reg got;
initial
begin
index=0;
for(i=0;i<10;i=i+1)
begin
arr[i] = i;
ind[i] = 1;
end
for(j = 0;j<10 ;j=j+1)
begin
got = 0;
while(got == 0)
begin
index = { $random() } % 10;
if(ind[index] == 1)
begin
ind[index] = 0;
got = 1;
num = arr[index];
end
end
$write("| num=%2d |",num);
end
end
endmodule
RESULT:
Random number system function has a argument called seed. The seed parameter
controls the numbers that $random returns such that different seeds generate
different random streams. The seed parameter shall be either a reg, an integer, or a
time variable. The seed value should be assigned to this variable prior to calling
$random. For each system function, the seed parameter is an in-out parameter; that
is, a value is passed to the function
and a different value is returned.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
for(j = 0;j<4 ;j=j+1)
begin
seed = j;
$display(" seed is %d",seed);
for(i = 0;i < 10; i=i+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
end
$display(" ");
end
end
endmodule
RESULT:
seed is 0
| num= 8 || num= 7 || num= 7 || num= 7 || num= 7 || num= 7 || num= 5 || num= 2
|| num= 1 || num= 9 |
seed is 1
| num= 8 || num= 8 || num= 2 || num= 2 || num= 6 || num= 3 || num= 8 || num= 5
|| num= 5 || num= 5 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 3
| num= 8 || num= 2 || num= 2 || num= 3 || num= 8 || num= 6 || num= 1 || num= 4
|| num= 3 || num= 9 |
The $random function has its own implicit variable as seed when the used is not giving
explicitly giving seed. The following example shows that seed = 0 and implicit seed
are having same sequence. It means that the implicitly taken seed is also 0.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
seed = 0;
RESULT:
seed is 0
| num= 8 || num= 7 || num= 7 || num= 7 || num= 7 || num= 7 || num= 5 || num= 2
|| num= 1 || num= 9 |
No seed is given
| num= 8 || num= 7 || num= 7 || num= 7 || num= 7 || num= 7 || num= 5 || num= 2
|| num= 1 || num= 9 |
The system functions shall always return the same value given the same seed. This
facilitates debugging by making the operation of the system repeatable. The argument
for the seed parameter should be an integer variable that is initialized by the user and
only updated by the system function. This ensures the desired distribution is achieved.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
for(j = 0;j<4 ;j=j+1)
begin
seed = 2;
$display(" seed is %d",seed);
for(i = 0;i < 10; i=i+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
end
$display(" ");
end
end
endmodule
RESULT:
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
seed is 2
| num= 8 || num= 1 || num= 0 || num= 5 || num= 0 || num= 8 || num= 6 || num= 7
|| num= 1 || num= 6 |
Seed is inout port. Random number system function returns a random number and
also returns a random number to seed inout argument also. The results of the
following example demonstrates how the seed value is getting changed.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
seed = 0;
for(j = 0;j<10 ;j=j+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
$display(" seed is %d ",seed);
end
end
endmodule
RESULT:
From the above results we can make a table of seed values and return values of
$random. If a seed is taken from the table, then rest of the sequence has to follow
sequence in table.
In the following example, the seed is 837833973, which is the 4 th seed from the
above table.
EXAMPLE:
module Tb();
integer num,seed,i,j;
initial
begin
seed = 837833973;
for(j = 0;j<10 ;j=j+1)
begin
num = { $random(seed) } % 10;
$write("| num=%2d |",num);
$display(" seed is %d ",seed);
end
end
endmodule
RESULTS:
From the above example we can come to conclusion that $random is not giving a
random number. It is randomizing seed and returning corresponding number for that
seed.
Total possible seed values are 4294967295. Is it possible for $random to generate all
the seeds? . Lets say ,if the seed gets repeated after 10 iterations, then after the 10
iterations, same values are repeated. So $random is circulating inside a chain of 10
numbers.
The following example demonstrates how $random misses many seeds. I tried to
display the seeds between 0 to 20 in the chain formed by initial seed of 0. Results
show that total possible seeds are 4294967295 , and number of seeds possible in seed
chain are 4030768279 , so we are missing some seeds. Look at the seeds between 0 to
20. Seed == 1 is missing.
EXAMPLE:
module Tb();
integer num,seed,j;
reg [0:31] i;
initial
begin
i = 0;
seed = 1;
while (seed != 0)
begin
if(i == 0)
seed = 0;
i = i + 1;
num = $random(seed);
if(seed < 20 && seed > 0)
$display(" seed is %d after values %d ",seed,i);
end
$display(" seed is one after this number of random numbers %0d total numbers
available are %d",i,{32'hffff_ffff});
end
endmodule
RESULTS:
Now I tried to simulate with seed== 1 . Its interesting to know that some how the
sequence is able to enter this chain which is formed with seed==0 and there is no seed
value 1 in this chain and my simulation hanged. So aborted the simulation and parter
results show that the initial seed = 1 with enter the chain formed by seed 0.
EXAMPLE:
module Tb();
integer num,seed,j;
reg [0:31] i;
initial
begin
i = 0;
seed = 0;
while (seed != 1)
begin
if(i == 0)
seed = 1;
i = i + 1;
num = $random(seed);
if(seed < 20 && seed > 0)
$display(" seed is %d after values %d ",seed,i);
end
$display(" seed is one after this number of random numbers %0d total numbers
available are %d",i,{32'hffff_ffff});
end
endmodule
RESULTS:
Verilog also has other system functions to generate random numbers. Each of these
functions returns a pseudo-random number whose characteristics are described by the
function name.
Following are the Verilog random number generator system functions:
$random
$dist_chi_square
$dist_erlang
$dist_exponential
$dist_normal
$dist_poisson
$dist_t
$dist_uniform
All parameters to the system functions are integer values. For the exponential ,
Poisson , chi-square , t , and erlang functions, the parameters mean, degree of
freedom, and k_stage must be greater than 0 .
The degree of freedom parameter used with the $dist_chi_square and $dist_t
functions is an integer input that helps determine the shape of the density function.
Larger numbers spread the returned values over a wider range.
EXAMPLE:
module Tb();
integer num_1,num_2,seed;
initial
begin
seed = 10;
repeat(5)
begin
#1;
num_1 = $dist_uniform(seed,20,25);
num_2 = $dist_uniform(seed,50,55);
$display("num_1 = %d,num_2 = %d",num_1,num_2);
end
end
endmodule
RESULTS:
num_1 = 20,num_2 = 50
num_1 = 23,num_2 = 55
num_1 = 22,num_2 = 54
num_1 = 25,num_2 = 51
num_1 = 23,num_2 = 55
As I discussed $random changes its seed , Lets see whether $dist_uniform is also doing
the same.
EXAMPLE:
module Tb();
integer num_1,num_2,seedd,seedr;
initial
begin
seedd = 10;
seedr = 10;
repeat(5)
begin
#1;
num_1 = $dist_uniform(seedd,20,25);
num_2 = 20 + ({$random(seedr)} % 6);
$display("num_1 = %d,num_2 = %d,seedd = %d seedr =
%d",num_1,num_2,seedd,seedr);
end
end
endmodule
RESULTS:
Look at the results... Its interesting to note that $random and $dist_uniform have
EXAMPLE:
module Tb();
integer num,seed;
integer num_20,num_21,num_22,num_23,num_24,num_25;
initial
begin
seed = 10;
num_20 = 0;num_21 = 0;num_22 = 0;num_23 = 0;num_24 = 0;num_25 =0;
repeat(6000)
begin
num = $dist_uniform(seed,20,25);
if(num == 20 )
num_20 = num_20 + 1;
if(num == 21)
num_21 = num_21 + 1;
if(num == 22)
num_22 = num_22 + 1;
if(num == 23)
num_23 = num_23 + 1;
if(num == 24)
num_24 = num_24 + 1;
if(num == 25)
num_25 = num_25 + 1;
end
$display("num_20 = %0d;num_21 = %0d;num_22 = %0d;num_23 = %0d;num_24 =
%0d;num_25 = %0d",num_20,num_21,num_22,num_23,num_24,num_25);
end
endmodule
RESULTS:
EXAMPLE:
module Tb();
integer num;
integer num_20,num_21,num_22,num_23,num_24,num_25;
initial
begin
seed = 10;
num_20 = 0;num_21 = 0;num_22 = 0;num_23 = 0;num_24 = 0;num_25 =0;
repeat(6000)
begin
num = 20 +( {$random() } %6 );
if(num == 20 )
num_20 = num_20 + 1;
if(num == 21)
num_21 = num_21 + 1;
if(num == 22)
num_22 = num_22 + 1;
if(num == 23)
num_23 = num_23 + 1;
if(num == 24)
num_24 = num_24 + 1;
if(num == 25)
num_25 = num_25 + 1;
end
$display("num_20 = %0d;num_21 = %0d;num_22 = %0d;num_23 = %0d;num_24 =
%0d;num_25 = %0d",num_20,num_21,num_22,num_23,num_24,num_25);
end
endmodule
RESULTS:
EXAMPLE:
module Tb();
integer num_1,num_2,seedd,seedr;
initial
begin
seedd = 10;
seedr = 10;
repeat(5)
begin
#1;
num_1 = $dist_uniform(seedd,20,25);
num_2 = 20 + ({$random(seedr)} % 6);
$display("num_1 = %d,num_2 = %d",num_1,num_2);
end
end
endmodule
RESULTS:
num_1 = 20,num_2 = 22
num_1 = 20,num_2 = 20
num_1 = 23,num_2 = 22
num_1 = 25,num_2 = 21
num_1 = 22,num_2 = 23
Till now what we have seen is $random has uniform distribution over integer values. It
means that distribution should be uniform across all the bits in 32 bit vector also. The
following example shows that bits positions 2,3,4,11,12,13 have equal probability of
getting 0. For demonstration I showed some indexes only. Try out rest of them and
see that results is same for all the bis.
EXAMPLE:
module Tb();
integer num;
integer num_2,num_3,num_4,num_11,num_12,num_13;
initial
begin
seed = 10;
num_2 = 0;num_3 = 0;num_4 = 0;num_11 = 0;num_12 = 0;num_13 =0;
repeat(6000)
begin
num = $random();
if(num[2] == 0 )
num_2 = num_2 + 1;
if(num[3] == 0)
num_3 = num_3 + 1;
if(num[4] == 0)
num_4 = num_4 + 1;
if(num[11] == 0)
num_11 = num_11 + 1;
if(num[12] == 0)
num_12 = num_12 + 1;
if(num[13] == 1)
num_13 = num_13 + 1;
end
$display("num_2 = %0d;num_3 = %0d;num_4 = %0d;num_11 = %0d;num_12 =
%0d;num_13 = %0d",num_2,num_3,num_4,num_11,num_12,num_13);
end
endmodule
RESULTS:
The distribution is uniform for system function $random. Suppose if the requirement
is to generate random numbers for more than one variable, and all the variables
should have uniform distribution, then use different seeds for each variable.
Otherwise distribution is distributed on all the variables as overall. But for lower bits,
the distribution is same as shown in example.
EXAMPLE:
module Tb();
integer seed;
reg [1:0] var_1,var_2,var3,var4;
integer num_2,num_3,num_1,num_0;
integer cou_2,cou_3,cou_1,cou_0;
initial
begin
seed = 10;
num_2 = 0;num_3= 0;num_1= 0;num_0= 0;
cou_2= 0;cou_3= 0;cou_1= 0;cou_0= 0;
repeat(40000)
begin
var_1 = $random();
var3 = $random();
var4 = $random();
var_2 = $random();
if(var_1 == 0 )
num_0 = num_0 + 1;
if(var_1 == 1 )
num_1 = num_1 + 1;
if(var_1 == 2 )
num_2 = num_2 + 1;
if(var_1 == 3 )
num_3 = num_3 + 1;
if(var_2 == 0 )
cou_0 = cou_0 + 1;
if(var_2 == 1 )
cou_1 = cou_1 + 1;
if(var_2 == 2 )
cou_2 = cou_2 + 1;
if(var_2 == 3 )
cou_3 = cou_3 + 1;
end
$display("num_2 = %0d;num_3= %0d;num_1= %0d;num_0=
%0d;",num_2,num_3,num_1,num_0);
$display("cou_2= %0d;cou_3= %0d;cou_1= %0d;cou_0=
%0d;",cou_2,cou_3,cou_1,cou_0);
end
endmodule
RESULTS:
Use system time as seed, so the same TB simulated at different times have different
random sequences and there is more probability of finding bugs. The following is c
code useful in PLI to get system time in to verilog.
#include <stdio.h>
#include <time.h>
char *get_time_string(int mode24);
int get_systime() {
time_t seconds;
seconds = time (NULL);
return seconds;
}
Verilog 1995, every simulator has its own random number generation algorithm.
Verilog 2001 , The standard made that every simulator has to follow same algorithm.
So the same random number sequence can seen on different simulators for same
seed.
Don't expect that the same sequence is generated on all the simulators. They are only
following same algorithm. The reason is, race condition. Look at the following
example, both the statements num_1 and num_2 are scheduled to execute at same
simulation time. The order of execution is not known. Some simulators take num_1 as
the first statement to execute and some other num_2 .If the TB is built without any
race condition to $random function calls, then the same random sequence can be
generated on different simulators.
EXAMPLE:
initial
# 10 num_1 = $random;
initial
#10 num_2 = $random;
Search ✔
EXAMPLE:
initial
begin
in = 1;
out <= in;
end
EXAMPLE
initial
begin
out <= in;
in = 1;
end
Sometimes unexpected output gives clue to search for race. Even if race condition is
existing in code, and if the output is correct, then one may not realize that there
exists race condition in their code. This type of hidden race conditions may come out
during the following situation.
Some simulators have special options which reports where exactly the race condition
is exists. Linting tools can also catch race condition.
There are many details which is unspecified between simulators. The problem will be
realized when you are using different simulators. If you are limited to design
guidelines then there is less chance for race condition but if you are using Verilog
with all features for Testbench, then it is impossible to avoid. Moreover the language
which you are using is parallel but the processor is sequential. So you cant prevent
race condition.
Write-Write Race:
EXAMPLE:
always @(posedge clk)
a = 1;
always @(posedge clk)
a = 5;
Here you are seeing that one block is updating value of a while another also. Now
which always block should go first. This is nondeterministic in IEEE standard and left
that work to the simulator algorithm.
Read-Write Race:
it occurs when same register is read in one block and writes in another.
EXAMPLE:
always @(posedge clk)
a = 1;
always @(posedge clk)
b = a;
Here you are seeing that in one always block value is assign to a while simultaneously
its value is assign to b means a is writing and read parallel. This type of race
condition can easily solved by using nonblocking assignment.
EXAMPLE
always @(posedge clk)
a <= 1;
always @(posedge clk)
b <= a;
1) Function calls
EXAMPLE:
function incri();
begin
pkt_num = pkt_num + 1;
end
endfunction
always @(...)
sent_pkt_num = incri();
always @(...)
sent_pkt_num_onemore = incri();
2) Fork join
EXAMPLE:
fork
a =0;
b = a;
join
3) $random
EXAMPLE:
always @(...)
$display("first Random number is %d",$random());
always @(...)
4) Clock race
EXAMPLE
initial
clk = 0;
always
clk = #5 ~clk;
If your clock generator is always showing "X" then there is a race condition. There is
one more point to be noted in above example. Initial and always starts executes at
time zero.
EXAMPLE:
reg a = 0;
initial
a = 1;
In test bench , if driving is done at posedge and reading in DUT is done at the same
time , then there is race. To avoid this, write from the Testbench at negedge or
before the posedge of clock. This makes sure that the DUT samples the signal without
any race.
EXAMPLE:
module DUT();
input d;
input clock;
output q;
always @(posedge clock)
q = d;
endmodule
module testbench();
DUT dut_i(d,clk,q);
initial
begin
@(posedge clk)
d = 1;
@(posedge clock)
d = 0;
end
endmodule
Event Terminology:
Every change in value of a net or variable in the circuit being simulated, as well as
the named event, is considered an update event. Processes are sensitive to update
events. When an update event is executed, all the processes that are sensitive to that
event are evaluated in an arbitrary order. The evaluation of a process is also an
event, known as an evaluation event.
In addition to events, another key aspect of a simulator is time. The term simulation
time is used to refer to the time value maintained by the simulator to model the
actual time it would take for the circuit being simulated. The term time is used
interchangeably with simulation time in this section. Events can occur at different
times. In order to keep track of the events and to make sure they are processed in the
correct order, the events are kept on an event queue, ordered by simulation time.
Putting an event on the queue is called scheduling an event.
The Verilog event queue is logically segmented into five different regions. Events are
added to any of the five regions but are only removed from the active region.
1) Events that occur at the current simulation time and can be processed in any order.
These are the
active events.
1.1 evaluation of blocking assignment.
1.2 evaluation of RHS of nonblocking assignment.
1.3 evaluation of continuous assignment.
1.4 evaluation of primitives I/Os
1.5 evaluation of $display or $write
2) Events that occur at the current simulation time, but that shall be processed after
all the active events are processed. These are the inactive events.
#0 delay statement.
3) Events that have been evaluated during some previous simulation time, but that
shall be assigned at this simulation time after all the active and inactive events are
processed. These are the nonblocking assign update events.
4) Events that shall be processed after all the active, inactive, and non blocking
assign update events are processed. These are the monitor events.
$strobe and $monitor
5) Events that occur at some future simulation time. These are the future events.
Future events are divided into future inactive events, and future non blocking
assignment update events.
Determinism
1) Statements within a begin-end block shall be executed in the order in which they
appear in that begin-end block. Execution of statements in a particular begin-end
block can be suspended in favor of other processes in the model; however, in no case
shall the statements in a begin-end block be executed in any order other than that in
which they appear in the source.
2) Non blocking assignments shall be performed in the order the statements were
executed.
initial begin
a <= 0;
a <= 1;
end
When this block is executed, there will be two events added to the non blocking
assign update queue. The previous rule requires that they be entered on the queue in
source order; this rule requires that they be taken from the queue and performed in
source order as well. Hence, at the end of time step 1, the variable a will be assigned
0 and then 1.
Nondeterminism
One source of nondeterminism is the fact that active events can be taken off the
queue and processed in any order. Another source of nondeterminism is that
statements without time-control constructs in behavioral blocks do not have to be
executed as one event. Time control statements are the # expression and @
expression constructs. At any time while evaluating a behavioral statement, the
simulator may suspend execution and place the partially completed event as a
pending active event on the event queue. The effect of this is to allow the
interleaving of process execution. Note that the order of interleaved execution is
nondeterministic and not under control of the user.
Race condition may occurs between DUT and testbench. Sometimes verification
engineers are not allowed to see the DUT, Sometimes they don't even have DUT to
verify. Consider the following example. Suppose a testbench is required to wait for a
specific response from its DUT. Once it receives the response, at the same simulation
time it needs to send a set of stimuli back to the DUT.
Most Synchronous DUT works on the posedge of clock. If the Testbench is also taking
the same reference, then we may unconditionally end in race condition. So it<92>s
better to choose some other event than exactly posedge of cock. Signals are stable
after the some delay of posedge of clock. Sampling race condition would be proper if
it is done after some delay of posedge of clock. Driving race condition can be avoided
if the signal is driven before the posedge of clock, so at posedge of clock ,the DUT
samples the stable signal. So engineers prefer to sample and drive on negedge of
clock, this is simple and easy to debug in waveform debugger also.
Search ✔
One of the ways to reduce the amount of work is the ability to leverage components
Specman E from one environment to the next. The concept of modularization is to break up a
Interview Questions complex problem into manageable pieces, which has many benefits including
increasing the quality, maintainability, and reusability of the environment.
Search ✔
EXAMPLE:task
module traffic_lights;
reg clock, red, amber, green;
parameter on = 1, off = 0, red_tics = 350,
amber_tics = 30, green_tics = 200;
initial red = off;
initial amber = off;
initial green = off;
A=f1(B)+f2(C);
and f1 and f2 had delays of say 5 and 10? When would B and C be sampled, or global
inside f1 and f2 be sampled? How long does then entire statement block? This is going
to put programmers in a bad situation. So languages gurus made that tasks can't
return .
The answer is same as above. But in Open Vera, delays are allowed in function. A
function returns a value and therefore can be used as a part of any expression. This
does not allow any delay in the function.
Constant Function:
Constant function calls are used to support the building of complex calculations of
values at elaboration time. A constant function call shall be a function invocation of a
constant function local to the calling module where the arguments to the function are
constant expressions.
EXAMPLE:constant function.
module ram_model (address, write, chip_select, data);
parameter data_width = 8;
parameter ram_depth = 256;
localparam adder_width = clogb2(ram_depth);
input [adder_width - 1:0] address;
input write, chip_select;
inout [data_width - 1:0] data;
Tasks and functions without the optional keyword automatic are static , with all
declared items being statically allocated. These items shall be shared across all uses
of the task and functions executing concurrently. Task and functions with the optional
keyword automatic are automatic tasks and functions. All items declared inside
automatic tasks and functions are allocated dynamically for each invocation.
Automatic task items and function items cannot be accessed by hierarchical
references.
EXAMPLE:
module auto_task();
task automatic disp;
input integer a;
input integer d;
begin
#(d) $display("%t d is %d a is %d", $time,d,a);
end
endtask
initial
#10 disp(10,14);
initial
#14 disp(23,18);
initial
#4 disp(11,14);
initial
#100 $finish;
endmodule
RESULTS:
18 d is 14 a is 11
24 d is 14 a is 10
32 d is 18 a is 23
EXAMPLE:
module tryfact;
// define the function
function automatic integer factorial;
input [31:0] operand;
integer i;
if (operand >= 2)
factorial = factorial (operand - 1) * operand;
else
factorial = 1;
endfunction
// test the function
integer result;
integer n;
initial begin
for (n = 0; n <= 7; n = n+1) begin
result = factorial(n);
$display("%0d factorial=%0d", n, result);
end
end
endmodule // tryfact
RESULTS:
0 factorial=1
1 factorial=1
2 factorial=2
3 factorial=6
4 factorial=24
5 factorial=120
6 factorial=720
7 factorial=5040
Search ✔
Fork/Join Recap:
Fork/join is a parallel block. Statements shall execute concurrently. Delay values for
each statement shall be considered relative to the simulation time of entering the
block. Delay control can be used to provide time-ordering for assignments Control
shall pass out of the block when the last time-ordered statement executes. The timing
controls in a fork-join block do not have to be ordered sequentially in time.
EXAMPLE:
module fork_join();
integer r ;
initial
fork
#50 r = 35;
#100 r = 24;
#150 r = 00;
#200 r = 7;
#250 $finish;
join
initial
$monitor("%t , r is %d",$time,r);
endmodule
RESULTS:
50 , r is 35
100 , r is 24
150 , r is 0
200 , r is 7
As the statements are parallel running, there is race condition between some
statements. In the following example, first statement after delay of 50 + 100, r is 24
and in second statement at 150 r is 00. But only the statement which is executed last
overrides previous value.
EXAMPLE:
module fork_join();
integer r ;
initial
fork
begin
#50 r = 35;
#100 r = 24;
end
#150 r = 00;
#200 r = 7;
#250 $finish;
join
initial
$monitor("%t , r is %d",$time,r);
endmodule
RESULTS:
50 , r is 35
150 , r is 24
200 , r is 7
Fork/Join None
In the fork join, the parent process continues to execute after all the fork/join
processes are completed. To continue the parent process concurrently with all the
processes spawned by the fork use this trick. This is as simple as above nonblocking
task example. Just use fork/join the always block as shown below.
EXAMPLE:
module tb();
event e;
initial
begin
#1 ->e;
#5 $display(" Statement after blocking_task at %t ",$time);
#40 $finish;
end
always@(e)
begin
fork
blocking_task_1();
blocking_task_2();
join
end
task blocking_task_1();
begin
#10;
$display(" statement inside blocking task_1 at %t",$time);
end
endtask
task blocking_task_2();
begin
#20;
$display(" statement inside blocking task_2 at %t",$time);
end
endtask
endmodule
RESULTS
Fork/Join Any
If you want to continue the parent process after finishing any of the child process,
then block the parent process until an event if triggered by the forked threads.
EXAMPLE:
module tb();
event e,ee;
initial
begin
#1 ->e;
@(ee);
Search ✔
Execution will continue with the next statement after the end statement when the
disable is executed.
Break
The break statement as in C can be emulated with disable as shown in the following
example:
EXAMPLE:
begin: break
for (i=0; i<16; i=i+1) begin
...
if (exit)
disable break;
...
end
end
Continue
EXAMPLE:
for (i=0; i<16; i=i+1) begin: name
...
if (abort)
disable name;
...
end
Search ✔
module TB();
wire aa,bb;
reg clk;
DUT dut(clk,aa,bb);
always
#5 clk = ~clk;
initial
#400 $finish;
initial
begin
clk = 0;
$display(" TESTBENCH STARTED");
wait(aa == 1) ;
watchdog();
wait( aa == 1);
watchdog();
end
task watchdog();
begin
$display(" WATCHDOG : started at %0d ",$time);
fork : watch_dog
begin
wait( bb == 1);
$display(" bb is asserted time:%0d",$time);
$display(" KICKING THE WATCHDOG ");
disable watch_dog;
end
begin
repeat(4)@(negedge clk);
$display(" bb is not asserted time:%0d",$time);
$display(" WARNING::WATCHDOG BITED ");
disable watch_dog;
end
join
end
endtask
endmodule
RESULTS:
TESTBENCH STARTED
WATCHDOG : started at 105
bb is asserted time:135
KICKING THE WATCHDOG
WATCHDOG : started at 245
bb is not asserted time:280
WARNING::WATCHDOG BITED
Statement " disable watch_dog " is the trick hear. If that statement is not there, the
statement " wait(b == 1) " is waiting and the simulation goes hang. This watchdog is
just giving a warning about bite. You can also assert a ERROR message and call $finish
to stop simulation.
Search ✔
Compile with +define+TYPE_1
Specman E Then simulate,result is
Interview Questions
RESULT:
TYPE_1 message
Compile with +define+TYPE_2
Then simulate,result is
RESULT:
TYPE_2 message
In the above example, When TYPE_1 switch is given, statement " $display(" TYPE_1
message "); " is only compile and statement " $display(" TYPE_2 message "); " is not
compiled.
Similarly for TYPE_2 switch. It wont take much time to compile this small example.
Compilation time is not small for real time verification environment. Compiler takes
time for each change of conditional compilation switches.
Simulation directives are simple. This is archived by `define macros. The following
example demonstrated the same functionality as the above example.
EXAMPLE:
module switches();
initial
begin
if($test$plusargs("TYPE_1"))
$display(" TYPE_1 message ");
else
if($test$plusargs("TYPE_2"))
$display(" TYPE_2 message ");
end
endmodule
RESULT:
TYPE_1 message
RESULT:
TYPE_2 message
This system function searches the list of plusargs (like the $test$plusargs system
function) for a user specified plusarg string. The string is specified in the first
argument to the system function as either a string or a register which is interpreted
as a string. If the string is found, the remainder of the string is converted to the type
specified in the user_string and the resulting value stored in the variable provided. If
a string is found, the function returns a non-zero integer. If no string is found
matching, the function returns the integer value zero and the variable provided is not
modified.
%d decimal conversion
%o octal conversion
%h hexadecimal conversion
%b binary conversion
%e real exponential conversion
%f real decimal conversion
%g real decimal or exponential conversion
%s string (no conversion)
The first string, from the list of plusargs provided to the simuator, which matches the
plusarg_string portion of the user_string specified shall be the plusarg string available
for conversion. The remainder string of the matching plusarg (the remainder is the
part of the plusarg string after the portion which matches the users plusarg_string)
shall be converted from a string into the format indicated by the format string and
stored in the variable provided. If there is no remaining string, the value stored into
the variable shall either be a zero (0) or an empty string value.
Example
module valuetest();
integer i;
real r;
reg [11:0] v;
reg [128:0] s;
initial
begin
if($value$plusargs("STRING=%s",s))
$display(" GOT STRING ");
if($value$plusargs("INTG=%d",i))
$display(" GOT INTEGER ");
if($value$plusargs("REAL=%f",r))
$display(" GOT REAL ");
if($value$plusargs("VECTOR=%b",v))
$display(" GOT VECTOR ");
$display( " String is %s ",s);
$display(" Integer is %d ",i);
$display(" Realnum is %f ",r);
$display(" Vector is %b ",v);
end
endmodule
Compilation :
command filename.v
Simulation :
command +STRING=rrf +INTG=123 +REAL=1.32 +VECTOR=10101
RESULTS:
GOT STRING
GOT INTEGER
GOT REAL
GOT VECTOR
String is rrf
Integer is 123
Realnum is 1.320000e+00
Vector is 000000010101
Search ✔
#10; // so delay to make sure that counter increments for the last triggered
error.
if( error == 0)
$dsplay("************ TEST PASSED ***************");
else
$dsplay("************ TEST FAILED ***************");
end
endtask
endmodule
Waveform Viewer:
For post process debug, Waveform viewer needs VCD(value change dump) file. A value
change dump (VCD) file contains information about value changes on selected
variables in the design stored by value change dump system tasks. Two types of VCD
files exist:
This clause describes how to generate both types of VCD files and their format.
The steps involved in creating the four state VCD file are listed below .
a) Insert the VCD system tasks in the Verilog source file to define the dump file name
and to specify the variables to be dumped.
b) Run the simulation.
A VCD file is an ASCII file which contains header information, variable definitions, and
the value changes for all variables specified in the task calls. Several system tasks can
be inserted in the source description to create and control the VCD file.
The $dumpfile task shall be used to specify the name of the VCD file.
EXAMPLE:
initial
$dumpfile ("my_dump_file");
Executing the $dumpvars task causes the value change dumping to start at the end of
the current simulation time unit. To suspend the dump, the $dumpoff task may be
invoked. To resume the dump, the $dumpon task may be invoked.
Due to dumping the value changes to a file,there is simulation over head. Not all the
time the dumping is required. So controlling mechanism to dump VCD files needs to
be implemented.
EXAMPLE:
`ifdef DUMP_ON
$dumpon;
`endif
Log File:
Log file keeps track of the operation in text format. Using Display system tasks,
proper information can be sent to log files. The display group of system tasks are
divided into three categories: the display and write tasks, strobed monitoring tasks,
and continuous monitoring tasks.
These are the main system task routines for displaying information. The two sets of
tasks are identical except that $display automatically adds a newline character to the
end of its output, whereas the $write task does not.
The system task $strobe provides the ability to display simulation data at a selected
time. That time is the
end of the current simulation time, when all the simulation events that have occurred
for that simulation
time, just before simulation time is advanced.
Sending message to log file is useful for debugging. But what messages are useful to
send and not. Sometimes only few messages are required to send to log file, other
times very detailed messages. If the number of messages are more, the simulation
time is more. So messaging should be controllable.
EXAMPLE:
always@(error)
begin
`ifdef DEBUG
$display(" ERROR : at %d ",$time);
`endif
end
With the above approach only one level of controlling is achieved. Messages can be
conveyed with wide range of severity levels. Following is the message controlling
system I used in my projects. This has 3 levels of controllability and 3 severity levels.
INFO:
The messages is used to convey simple information.
WARNING:
This message conveys that some this is bad but doesn't stop the simulation.
ERROR:
This messages indicate that some error has occurred. Simulation can be terminated.
DEBUG:
These messages are for debugging purpose.
NOTE: %m prints hierarchy path.
EXAMPLE:
By default ,messages INFO, WARN and EROR are logged. When a special switch is
used, Debug messages are logged. This example also removes lot of manly coding.
EXAMPLE:
`ifndef DEBUG
`define SHOW 0
`else
`define SHOW 1
`endif
module msg();
initial
begin
#10;
`INFO("UR MESSAGE GOES HEAR");
`WARN("UR MESSAGE GOES HEAR");
`EROR("UR MESSAGE GOES HEAR");
`DBUG("UR MESSAGE GOES HEAR");
end
endmodule
The above results show that DEBUG messages can be disable if not needed.
EXAMPLE:
module top();
reg debug = 0;
initial
if($test$plusargs("DEBUG"))
#0 debug = 1;
initial
begin
#10;
`INFO("UR MESSAGE GOES HEAR");
`WARN("UR MESSAGE GOES HEAR");
`EROR("UR MESSAGE GOES HEAR");
`DBUG("UR MESSAGE GOES HEAR");
end
endmodule
When simulation is done without +DEBUG
RESULTS:
This is simple trick and very useful. By passing some comments to waveform,
debugging becomes easy. Just declare a string and keep updating the comments.
There is no slandered way to pass comments to waveform debugger but some tools
have their own methods to do this job.
EXAMPLE:
module pass_comments();
reg [79 : 0] Comment; // holds 10 characters.
reg [7:0] status;
initial
begin
#10 status = 8'b10101010;
comment = Preambel;
#10 status = 8'b10101011;
comment = Startofpkt;
end
endmodule
The reg " Comment " holds string. This strings can be viewed in waveform debugger.
$Display N $Strobe
EXAMPLE:
module disp_stro;
reg a;
initial begin
a = 0;
a <= 1;
$display(" $display a=%b", a);
$strobe (" $strobe a=%b", a);
#1 $display("#1 $display a=%b", a);
#1 $finish;
end
endmodule
RESULTS:
$display a=0
$strobe a=1
#1 $display a=1
One of the important question in debugging is who should do the RTL debugging?
Verification engineer or the RTL designer?
I personally like to debug the RTL as verification engineer. This is a great opportunity
to know RTL methodology. This also improves my understanding ability of RTL.
Sometimes test fails because of the Verification environment, before I go and ask RTL
designer, I am sure that there is no bug in my environment. By debugging RTL, the bug
report is more isolated and designer can fix it sooner. Designer is fast enough to catch
cause of the bug, as he knows more about the RTL then verification engineer.
Verification and Designer should sit together and debug the issue, if the bug is in RTL,
verification engineer can file the bug, if it is in Testbench, no need to file it.
Search ✔
As seen in example those statements only will execute whose condition is satisfied.
Statement coverage will only consider those statements.
Block/Segment Coverage:
The nature of the statement and block coverage looks somewhat same. The
difference is that block which is covered by begin-end, if-else or always, those group
of statements which is called block counted by the block coverage.
Branch coverage will report the true or false of the branch like if-else, case and the
ternary operator (? :) statements. In bellow branch of casez, sequences of statements
are given. Their execution is depending upon the implementation of stimulus. The
default branch in case statement in RTL is not exercised mostly because the Design
guidelines insist to mention all the branches of the case statement.
case (state)
idle : casez (bus_req)
4'b0000 : next = idle;
4'b1??? : next = grant1;
4'b01?? : next = grant2;
4'b001? : next = grant3;
4'b0001 : next = grant4;
default : next = idle;
endcase
As per the case selectivity list it will check all the statements are reached or not?
Path Coverage:
Due to conditional statements like if-else, case in the design different path is created
which diverts the flow of stimulus to the specific path.
Expression Coverage:
It is the ratio of no. of cases checked to the total no. of cases present. Suppose one
expression having Boolean expression like AND or OR, so entries which is given to that
expression to the total possibilities is called expression coverage.
In above example it analyzes the right and side of the expression and counts how
many times it executed. The expression which involves the Boolean expression for
that expression coverage will make its truth table with number of times it executed.
If any expression is uncovered then table will come with plane line.
Toggle Coverage:
It makes assures that how many time reg, net and bus toggled? Toggle coverage could
be as simple as the ratio of nodes toggled to the total number of nodes.
X or Z --> 1 or H
X or Z --> 0 or L
1 or H --> X or Z
0 or L --> X or Z
Above example shows the signal changes from one level to another. Toggle coverage
will show which signal did not change the state. Toggle coverage will not consider
zero-delay glitches. All types of transitions mentioned above are not interested. Only
1->0 and 0->1 are much important. This is very useful in gate level simulation.
Variable Coverage:
After the one step of toggle coverage variable coverage comes. Both the coverage
looks same but there is a minor different between them is toggle coverage works on
gate level but it fail on large quantity. For entity like bus we use variable coverage.
Events are typically associated with the change of a signal. Event coverage checks the
process whenever the individual signal inside the sensitivity list changes.
EXAMPLE:
always @(a or b or c)
if ((a & b) | c)
x = 1'b 1;
else
x = 1'b 0;
As per the change in above sensitivity list whether the process is triggered or not.
Parameter Coverage:
It works on the specification which is defined in the design process. If you have
implemented 30bit design instead of 32bit, here code coverage check for the
functionality while if your design is parameterized then parameter coverage will give
error which shows size mismatch.
Functional Coverage:
Fsm Coverage :
It is the most complex type of coverage, because it works on the behavior of the
design. In this coverage we look for how many times states are visited, transited and
how many sequence are covered. Thats the duty of FSM coverage.
State Coverage:
It gives the coverage of no. of states visited over the total no. of states. Suppose you
have N number of states and state machines transecting is in between only N-2 states
then coverage will give alert that some states are uncovered. It is advised that all the
states must be covered.
Transition Coverage:
It will count the no. of transition from one state to another and it will compare it
with other total no. of transition. Total no. of transition is nothing but all possible no.
of transition which is present in the finite state machine. Possible transition = no. of
states * no. of inputs.
Sequence Coverage:
suppose your finite state machine detects the particular sequences. So there is more
than 1 possibilities of sequences through which your desired output can be achieved.
So here sequence coverage will check which sequence is covered and which is missed?
This is a small and corner problem but stimulus should be such a way that all the
possibilities must be covered.
Tool Support:
Coverage does not know anything about what design supposed to do. There is no way
to find what is missing in the code. It can only tell quality of the implementation.
Sometime we get the bug because of the incorrectly written RTL code. If we found
that all the lines of the code are used, it doesn't mean that we have tasted all the
lines. Sometimes we want the 2nd input of the mux but due to mistake in stimulus if
it has taken 1st during that cycle. So whether we got he correct data or not? This
cannot tell by coverage. Thats depend on us weather we are feeding correct stimulus
or not?
Search ✔
Specman E
Interview Questions
Search ✔
EXAMPLE
// Display mcd value before and after the opening the file.
module fopenclose();
integer mcd,number;
initial
begin
$display("value of mcd before opening the file %b " , mcd);
Fdisplay
$display has its own counterparts. Those are $fdisplay, $fdisplayb, $fdisplayo,
$fdisplayh. Instead of writing on screen they are writing on the specific file with is
pointed by the mcd. $fdisplay write in decimal format, $fdisplay in binary, $fdisplay
in octal and $fdisplayh in hex format. so no need to put %d-b-o-h.
EXAMPLE
// file open close example with all $fdisplay
module fopenclose();
integer mcd,number;
initial
begin
mcd = $fopen("temp.txt"); // mcd = multi_channel_descriptor
repeat(7)
begin
number = $random;
$fdisplay(mcd, "Number is ", number);
end
$fclose(mcd);
end
endmodule
RESULT
Number is 303379748
Number is -1064739199
Number is -2071669239
Number is -1309649309
Number is 112818957
Number is 1189058957
Number is -1295874971
EXAMPLE $displayb
module fopenclose();
integer mcd,number;
initial
begin
Number is 00010010000101010011010100100100
Number is 11000000100010010101111010000001
Number is 10000100100001001101011000001001
Number is 10110001111100000101011001100011
Number is 00000110101110010111101100001101
Number is 01000110110111111001100110001101
Number is 10110010110000101000010001100101
EXAMPLE c. $displayo
module fopenclose();
integer mcd,number;
initial
begin
mcd = $fopen("temp.txt"); // mcd = multi_channel_descriptor
repeat(7)
begin
number = $random;
$fdisplayo(mcd, "Number is ", number);
end
$fclose(mcd);
end
endmodule
RESULT
Number is 02205232444
Number is 30042257201
Number is 20441153011
Number is 26174053143
Number is 00656275415
Number is 10667714615
Number is 26260502145
EXAMPLE. $displayh
module fopenclose();
integer mcd,number;
initial
begin
mcd = $fopen("temp.txt"); // mcd = multi_channel_descriptor
repeat(7)
begin
number = $random;
$fdisplayh(mcd, "Number is ", number);
end
$fclose(mcd);
end
endmodule
RESULT
Number is 12153524
Number is c0895e81
Number is 8484d609
Number is b1f05663
Number is 06b97b0d
Number is 46df998d
Number is b2c28465
In below example we will see that how we will come to know that file is closed or
not?? so even after closing the file I will try to write in that file, for that it should
give error.
EXAMPLE
module fopenclose();
integer mcd,number;
initial
begin
$display("value of mcd before opening the file %b " , mcd);
mcd = $fopen("xyz.txt");
$display("value of mcd after opening the file %b " , mcd);
repeat(7)
begin
number = $random ;
$fdisplay(mcd, " Number is ", number);
end
$fclose(mcd);
$fdisplay("value of mcd after closing the file %b ",
mcd);
end
endmodule
RESULT
Fmonitor
Like $display; $monitor and $strobe also have counterparts. They also write in
decimal, binary, octal and hexadecimal.
EXAMPLE
// file open close example with $fmonitor
module monitortask();
integer mcd,number;
initial
begin
#0;
mcd = $fopen("abc.txt");
$monitoron;
repeat(7)
begin
#1 number = $random ;
end
$monitoroff;
$fclose(mcd);
end
initial
$fmonitorh(mcd, " Number is ", number);
endmodule
RESULT
Number is 12153524
Number is c0895e81
Number is 8484d609
Number is b1f05663
Number is 06b97b0d
Number is 46df998d
Due to initial-initial race condition we have to put the #0 delay in first initial block
and $monitoron-$monitoroff system task, otherwise it is not able to
cache the updated value of integer "number" because "number" is updated in
active(1st) event while monitor in system task(3rd) event in the event queue.
Fwrite
Like $display; $write also have counterparts. They also write in decimal,binary, octal
and hexadecimal.
EXAMPLE
// file open close example with $fwrite
module writetask();
integer mcd1,mcd2,number,pointer;
initial
begin
$display("value of mcd1 before opening the file %b " , mcd1);
$display("value of mcd2 before opening the file %b " , mcd2);
mcd1 = $fopen("xyz.txt");
mcd2 = $fopen("pqr.txt");
$display("value of mcd1 after opening the file %b " , mcd1);
$display("value of mcd2 after opening the file %b " , mcd2);
repeat(7)
begin
pointer = $random;
number = $random % 10;
$fwriteo(mcd1, " Number is ", number);
$fwriteh(mcd2, " Pointer is ", pointer);
end
$fclose(mcd1);
$fclose(mcd2);
end
endmodule
One of the reasons behind writing this example is to show how the integers are
getting different value as per the number of files are opened.
RESULT
In file xyz.txt
Mcd
Simultaneously writing same data to two different file. This example shows how to
set up multi channel descriptors. In this example, two different channels are opened
using the $fopen function. The two multi channel descriptors that are returned by the
function are then combined in a bit-wise or operation and assigned to the integer
variable "broadcast". The "broadcast" variable can then be used as the first parameter
in a file output task to direct output to all two channels at once.
EXAMPLE
module writetask();
integer mcd1,mcd2,broadcast,number;
initial
begin
mcd1 = $fopen("lsbbit1.txt");
mcd2 = $fopen("lsbbit2.txt");
broadcast = mcd1 |mcd2 ;
repeat(7)
begin
number = $random;
$fdisplayh(broadcast," Number is ", number);
end
$fclose(mcd1);
$fclose(mcd2);
end
endmodule
RESULT
In lsbbit1.txt
Number is 12153524
Number is c0895e81
Number is 8484d609
Number is b1f05663
Number is 06b97b0d
Number is 46df998d
Number is b2c28465
In lsbbit2.txt
Number is 12153524
Number is c0895e81
Number is 8484d609
Number is b1f05663
Number is 06b97b0d
Number is 46df998d
Number is b2c28465
To create a descriptor that directs output to the standard output that is monitor
screen as well as both the files, the "broadcast" variable is a bit-wise
logical or with the constant 1, which effectively writes to both files as well as monitor
screen.
EXAMPLE
module writetask();
integer mcd1,mcd2,broadcast,number;
initial
begin
mcd1 = $fopen("lsbbit1.txt");
mcd2 = $fopen("lsbbit2.txt");
broadcast = 1 | mcd1 | mcd2 ;
repeat(7)
begin
number = $random;
$fdisplayh(broadcast," Number is ", number);
end
$fclose(mcd1);
$fclose(mcd2);
end
endmodule
endmodule
RESULT
Number is 12153524
Number is c0895e81
Number is 8484d609
Number is b1f05663
Number is 06b97b0d
Number is 46df998d
Number is b2c28465
The $swrite family of tasks are based on the $fwrite family of tasks, and accept the
same type of arguments as the tasks upon which they are based, with one exception:
The first parameter to $swrite shall be a reg variable to which the resulting string
shall be written, instead of a variable specifying the file to which to write the
resulting string.
The system task $sformat is similar to the system task $swrite, with a one major
difference. Unlike the display and write family of output system tasks, $sformat
always interprets its second argument, and only its second argument as a format
string. This format argument can be a static string, such as "data is %d" , or can be a
reg variable whose content is interpreted as the format string. No other arguments
are interpreted as format strings. $sformat supports all the format specifies supported
by $display.
EXAMPLE:
$sformat(string, "Formatted %d %x", a, b);
Search ✔
# 10 ;
get_key(1);
repeat(4)
# 10 $display(" PROCESS 1 GOT KEYS : OTHERS CANT WRITE MESSAGE TO LOG ");
put_keys(1);
end
initial
begin
# 10 ;
get_key(2);
repeat(4)
# 10 $display(" PROCESS 2 GOT KEYS : OTHERS CANT WRITE MESSAGE TO LOG ");
put_keys(2);
end
endmodule
RESULTS:
In this home, some of them are not interested to wait until they got the key. So they
want tp progress to other works without waiting for keys.
The following example shows, if keys are not available, the process don't wait.
EXAMPLE:
module sema();
integer keys;
initial
keys = 1;
task get_key();
input integer i;
begin
if ( keys == 0)
begin
$display(" KEY IS NOT AVAILABLE : WAITING FOR KEYS : process %d",i);
wait(keys == 1);
end
$display(" GOT THE KEY : GET SET GO :process %d",i);
keys = 0;
end
endtask
function get_key_dont_wait();
input integer i;
reg got;
begin
got =0;
if ( keys == 0)
$display(" KEY IS NOT AVAILABLE : LEAVING WITHOUT WAITING FOR KEYS : process
%d",i);
else
begin
$display(" GOT THE KEY : GET SET GO :process %d",i);
keys = 0;
got = 1;
end
get_key_dont_wait = got;
end
endfunction
task put_keys();
input integer i;
begin
keys = 1 ;
$display(" PROCESS %d gave the key back ",i);
end
endtask
initial
begin
# 10 ;
get_key(1);
repeat(4)
# 10 $display(" PROCESS 1 GOT KEYS : OTHERS CANT WRITE MESSAGE TO LOG ");
put_keys(1);
end
initial
begin
# 10 ;
if(get_key_dont_wait(2))
begin
repeat(4)
# 10 $display(" PROCESS 2 GOT KEYS : OTHERS CANT WRITE MESSAGE TO LOG ");
put_keys(2);
end
else
$display(" IM not interested to wait ");
end
endmodule
RESULTS:
After some days, they got new car to home. Now they have two cars, at once 2
members can go on drive. Looking at the following code. The keys are initialized to 2.
Two processes are running at once.
EXAMPLE:
module sema();
integer keys;
initial
keys = 2;
task get_key();
input integer i;
begin
if ( keys == 0)
begin
$display(" KEY IS NOT AVAILABLE : WAITING FOR KEYS : process %d",i);
wait(keys > 0);
end
$display(" GOT THE KEY : GET SET GO :process %d",i);
keys = keys - 1;
end
endtask
function get_key_dont_wait();
input integer i;
reg got;
begin
got =0;
if ( keys == 0)
$display(" KEY IS NOT AVAILABLE : LEAVING WITHOUT WAITING FOR KEYS : process
%d",i);
else
begin
$display(" GOT THE KEY : GET SET GO :process %d",i);
keys = keys - 1;
got = 1;
end
get_key_dont_wait = got;
end
endfunction
task put_keys();
input integer i;
begin
keys = keys + 1 ;
$display(" PROCESS %d gave the key back ",i);
end
endtask
initial
begin
# 10 ;
get_key(1);
repeat(4)
# 10 $display(" PROCESS 1 GOT KEYS : IM ALOS RUNNING ");
put_keys(1);
end
initial
begin
# 10 ;
if(get_key_dont_wait(2))
begin
repeat(4)
# 10 $display(" PROCESS 2 GOT KEYS : IM ALSO RUNNING ");
put_keys(2);
end
else
$display(" IM not interested to wait ");
end
endmodule
RESULTS:
Search ✔
Search ✔
1) Take an instance of module TEST in top.v file. Define the module definition in test
cases.
EXAMPLE: top.v
module top();
// DUT instance, clock generator and TB components
// some tasks
task write()
begin
// some logic
end
endtask
task read()
begin
// some logic
end
endtask
TEST tst();
end
EXAMPLE: testcase_1.v
// Do 10 write operations
module TEST();
initial
repeat(10)
top.write();
endmodule
EXAMPLE: testcase_2.v
// Do 10 read operations
module TEST();
initial
repeat(10)
top.read();
endmodule
2) use `include test.v file. This needs a small script to copy the testcase file to test
file. The compilation command is same. But copy command which copies the testcase
to test.v file is different.
EXAMPLE: top.v
module top();
// DUT instance, clock generator and TB components
// some tasks
task write()
begin
// some logic
end
endtask
task read()
begin
// some logic
end
endtask
`include test.v
end
EXAMPLE: testcase_1.v
// Do 10 write operations
initial
repeat(10)
top.write();
EXAMPLE: testcase_2.v
// Do 10 read operations
initial
repeat(10)
top.read();
2) With the above two approaches, for each test case, we have to do individual
compilation. In this method, compile once and use simulation command to test with
individual test case.
This needs a small script to convert all the test cases to single intermediate file.
compilation command is same. During simulation by giving the test case file name, we
can include particular testcase.
During simulation ,
for each test case, use
run_command +testcase_1
run_coomand +testcase_2
EXAMPLE: top.v
module top();
// DUT instance, clock generator and TB components
// some tasks
task write()
begin
// some logic
end
endtask
task read()
begin
// some logic
end
endtask
`include test.v
end
EXAMPLE: testcase_1.v
// Do 10 write operations
repeat(10)
top.write();
EXAMPLE: testcase_2.v
// Do 10 read operations
repeat(10)
top.read();
Intermediate file generated contains all the testcase contents with some extra logic as
shown.
initial
begin
if($test$plusargs("testcase_1")
begin // testcase_1 contents
// Do 10 write operations
repeat(10)
top.write();
end
if($test$plusargs("testcase_2")
begin // testcase_2 contents
// Do 10 read operations
repeat(10)
top.read();
end
end
Search ✔
EXAMPLE:
Specman E always@(error)
Interview Questions begin
no_of_errors = num_of_errors +1 ;
`ifndef CONTINUE_ON_ERROR
`ifndef NO_OF_ERR
`define NO_OF_ERR 0
`endif
if(`NO_OF_ERR < no_of_erros)
terminate();
`endif
end
Search ✔
Specman E
Interview Questions
Search ✔
3) The Shadow registers by default should contain default values from register
specification. A task should be provided to compare each register in shadow registers
and DUT. After reset, just call this task before doing any changes to DUT registers.
This will check the default values of the registers.
4) Methods should be provided for read or write operation to dut registers using name
and also address. Named methods are handy and readable mainly from test cases.
While address based methods are good while writing to bulk locations( using for loop
etc...).
5) Every register in Testbench may have these information.
// Comments which describes the register information.
Address of register.
Offset of register.
Width of register.
Reset value.
Access permissions.
Register value.
Register name as string.( Name should be self descriptive and same as in DUT. This
string is used in printing while debugging.)
Some are methods which are used for register in functional verification .
Read function.
Write task.
Update task.
Print task.
Check function.
write_random task.
All the above methods should be accessible by name and also by address.
Update task:
Interrupt and status registers in Testbench should be updated by update task. These
registers should contain the expected values. When check function is called, the
check reads the register values in DUT and compares with the expected value in
shadow registers.
Check task:
Check task compares the DUT and shadow registers. Care should be taken while using
back door access, as they are not cycle accurate. Config registers are compared for
what is configured and what is in the register. Interrupt and status registers are
compared with what is in DUT with the expected values.
Access permission:
Each register in test bench should maintain the permissions. This permissions are used
in write, read, check methods.
By default the type of permission is read/write. If you are using any scripts, if you
don't mention any permission, then it should be considered as read/write.
Search ✔
module nand_gate(a,b,c);
input a,b;
output c;
endmodule
This looks easy to do, as there are 3 inputs only. Real time projects doesnt have this
much less. One may probable spend half day to connect all the ports. Sometime later
if there is change in any of the ports, then all the instances needs to be changed.
Using parameterized macros, this job can be done easily. The directive <91>define
creates a macro for text substitution. This directive can be used both inside and
outside module definitions. After a text macro is defined, it can be used in the source
description by using the (<91>) character, followed by the macro name. The compiler
shall substitute the text of the macro for the string `macro_name. All compiler
directives shall be considered predefined macro names; it shall be illegal to redefine
a compiler directive as a macro name.
A text macro can be defined with arguments. This allows the macro to be customized
for each use individually. If a one-line comment (that is, a comment specified with
the characters //) is included in the text, then the comment shall not become part of
the substituted text.
EXAMPLE:
<91>define max(a,b)((a) > (b) ? (a) : (b))
n = <91>max(p+q, r+s) ;
CODE:
`define GATE(M) M\
_gate M\
_g (.a(M\
_a), .b(M\
_b), .c(M\
_c));
`define SIG and_\
S, or_\
S,xor_\
S,nand_\
S; \
module top();
wire `SIG(a)
wire `SIG(b)
wire `SIG(c)
`GATE(and)
`GATE(or)
`GATE(xor)
`GATE(nand)
endmodule
Search ✔
Specman E
Interview Questions
Search ✔
Specman E
Interview Questions
Search ✔
endmodule
Specman E `endif
Interview Questions
EXAMPLE: yyy.v file
`include "xxx.v"
`ifndef YYY
`define YYY
module yyy()
endmodule
`endif
Colourful Messages:
Look at the picture. Do you want to make your Linux terminal colorful like this, while
you run your verilog code?
Copy the following code and simulate in batch mode in Linux. What you can see is
colorful messages from verilog.
CODE:
module colour();
initial
begin
$write("%c[1;34m",27);
$display("*********** This is in blue ***********");
$write("%c[0m",27);
$display("%c[1;31m",27);
$display("*********** This is in red ***********");
$display("%c[0m",27);
$display("%c[4;33m",27);
$display("*********** This is in brown ***********");
$display("%c[0m",27);
$display("%c[5;34m",27);
$display("*********** This is in green ***********");
$display("%c[0m",27);
$display("%c[7;34m",27);
$display("*********** This is in Back ground color ***********");
$display("%c[0m",27);
end
endmodule
This works only in Linux or Unix terminals. To get required colors, ("%c[1;34m",27);
should be used to print once. Ordinary messages following this messages continue to
be the color specified.
1 set bold
2 set half-bright (simulated with color on a color display)
4 set underscore (simulated with color on a color display)
5 set blink
7 set reverse video
`define display_blue $write("%c[0m",27); $write("%c[1;34m",27); $display
`define display_red $write("%c[0m",27); $write("%c[1;31m",27); $display
`define display_green $write("%c[0m",27); $write("%c[1;32m",27); $display
EXAMPLE:
module color();
initial
begin
`display_blue(" ******** this is blue ********** ");
`display_red(" ******** this is red ********** ");
`display_green(" ******** this is green ********** ");
end
endmodule
Debugging Macros
Most tools don't support Debugging Macros. The compilation error information is not
enough to find the exactly line where the bug is. In simulation/Compilation steps ,
the first step is Macro preprocessing. The macro preprocessing step performs textual
substitutions of macros defined with `define statements, textual inclusion with
`include statements, and conditional compilation by `ifdef and `ifndef statements.
EXAMPLE:
`define SUM(A,B) A + B ;
module example();
integer a,b,c;
initial
a = SUM(b,c);
endmodule
Run the above example and check where the error is.
The find the exact cause of error, simply use the C pre-processor.
cpp file_name.v
NOTE: cpp cannot understand `define. Before using cpp, covert all `define to
#define.
RESULTS
# 1 "fine_name.v"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "fine_name.v"
module example();
integer a,b,c;
initial
a = b + c ;;
endmodule
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet format:
OpenVera Packet contains Header, data and frame check sequence. Packet width is 8 bits and
Constructs the length of the packet can be between 4 bytes to 259 bytes.
Switch TB
Packet header:
RVM Switch TB Packet header contains three fields DA, SA and length.
RVM Ethernet sample DA: Destination address of the packet. It is 8 bits. The switch drives the packet to
respective ports based on this destination address of the packets.
SA: Source address of the packet from where it originate.
Length: This is the length of the data. It can be from 0 to 255.
Specman E
Interview Questions Data: Data should be in terms of bytes. It can be between 0 to 255 bytes.
FCS: This field contains the security check of the packet. It is calculated over the
header and data.
Configuration:
Dut has four output ports. These output ports have to be configure to a address. Dut
matches the DA field of the packet with this configured port address and sends the
packet on to that port. To configure the dut, a memory interface is provided. The
address of the ports should be unique. It is 8 bits wide. Memory address (0,1,2,3)
contains the address of port(0,1,2,4) respectively.
Interface Specification:
The dut has one input Interface, from where the packet enters the dut and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured.
Memory Interface:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively. If the DA feild in the packet matches with
the confugured address of any port ,then the packet comes out of that port.
Input Interface:
The status signal has to be high when data is when packet is sent on to the dut it has
to become low after sending last byte of the packet.
When the dut is busy, and if it is not in a position to accept any more data, it will
assert busy signal. Data which is sent during this busy signal is lost if input is driving
when busy is high
Output Interface:
There are 4 ports, each having data, ready and read signals.
When the data is ready to be sent out from the port, dut makes the ready signal high
indicating that data is ready to be sent.
If the read signal is made high when ready is high, then the data comes out of the
data signal.
Search ✔
end
end
endmodule //fifo
module port_fsm (clk,
reset,
write_enb,
ffee,
hold,
data_status,
data_in,
data_out,
mem0,
mem1,
mem2,
mem3,
addr);
input clk;
input reset;
input [7:0] mem0;
input [7:0] mem1;
input [7:0] mem2;
input [7:0] mem3;
output[3:0] write_enb;
input ffee;
input hold;
input data_status;
input[7:0] data_in;
output[7:0] data_out;
output [7:0] addr;
reg [7:0] data_out;
reg [7:0] addr;
reg [3:0] write_enb_r;
reg fsm_write_enb;
reg [3:0] state_r;
reg [3:0] state;
reg [7:0] parity;
reg [7:0] parity_delayed;
reg sus_data_in,error;
parameter ADDR_WAIT = 4'b0000;
parameter DATA_LOAD = 4'b0001;
parameter PARITY_LOAD = 4'b0010;
parameter HOLD_STATE = 4'b0011;
parameter BUSY_STATE = 4'b0100;
always@(negedge reset)
begin
error = 1'b0;
data_out = 8'b0000_0000;
addr = 8'b00000000;
write_enb_r = 3'b000;
fsm_write_enb = 1'b0;
state_r = 4'b0000;
state = 4'b0000;
parity = 8'b0000_0000;
parity_delayed = 8'b0000_0000;
sus_data_in = 1'b0;
end
assign busy = sus_data_in;
always @(data_status) begin : addr_mux
if (data_status == 1'b1) begin
case (data_in)
mem0 : begin
write_enb_r[0] = 1'b1;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem1 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b1;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem2 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b1;
write_enb_r[3] = 1'b0;
end
mem3 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b1;
end
default :write_enb_r = 3'b000;
endcase
// $display(" data_inii %d ,mem0 %d ,mem1 %d ,mem2 %d
mem3",data_in,mem0,mem1,mem2,mem3);
end //if
end //addr_mux;
always @(posedge clk) begin : fsm_state
state_r <= state;
end //fsm_state;
end //if
sus_data_in = 1'b0;
if ((data_status == 1'b1) &&
(hold == 1'b0)) begin
data_out = data_in;
fsm_write_enb = 1'b1;
end
else if ((data_status == 1'b0) &&
(hold == 1'b0)) begin
data_out = data_in;
fsm_write_enb = 1'b1;
end
else begin
fsm_write_enb = 1'b0;
end //if
end //end of case DATA_LOAD
HOLD_STATE : begin
if (hold == 1'b1) begin
state = HOLD_STATE;
end
else if ((hold == 1'b0) && (data_status == 1'b0)) begin
state = PARITY_LOAD;
end
else begin
state = DATA_LOAD;
end //if
if (hold == 1'b1) begin
sus_data_in = 1'b1;
fsm_write_enb = 1'b0;
end
else begin
fsm_write_enb = 1'b1;
data_out = data_in;
end //if
end //end of case HOLD_STATE
BUSY_STATE : begin
if (ffee == 1'b0) begin
state = BUSY_STATE;
end
else begin
state = DATA_LOAD;
end //if
if (ffee == 1'b0) begin
sus_data_in = 1'b1;
end
else begin
addr = data_in; // hans
data_out = data_in;
fsm_write_enb = 1'b1;
end //if
end //end of case BUSY_STATE
endcase
end //fsm_core
assign write_enb[0] = write_enb_r[0] & fsm_write_enb;
assign write_enb[1] = write_enb_r[1] & fsm_write_enb;
assign write_enb[2] = write_enb_r[2] & fsm_write_enb;
assign write_enb[3] = write_enb_r[3] & fsm_write_enb;
endmodule //port_fsm
module switch (clk,
reset,
data_status,
data,
port0,
port1,
port2,
port3,
ready_0,
ready_1,
ready_2,
ready_3,
read_0,
read_1,
read_2,
read_3,
mem_en,
mem_rd_wr,
mem_add,
mem_data);
input clk;
input reset;
input data_status;
input [7:0] data;
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
wire [7:0] data_out_0;
wire [7:0] data_out_1;
wire [7:0] data_out_2;
wire [7:0] data_out_3;
wire ll0;
wire ll1;
wire ll2;
wire ll3;
wire empty_0;
wire empty_1;
wire empty_2;
wire empty_3;
wire ffee;
wire ffee0;
wire ffee1;
wire ffee2;
wire ffee3;
wire ld0;
wire ld1;
wire ld2;
wire ld3;
wire hold;
wire [3:0] write_enb;
wire [7:0] data_out_fsm;
wire [7:0] addr;
reg [7:0]mem[3:0];
wire reset;
fifo queue_0 (.clk (clk),
.reset (reset),
.write_enb (write_enb[0]),
.read (read_0),
.data_in (data_out_fsm),
.data_out (data_out_0),
.empty (empty_0),
.full (ll0));
.write_enb (write_enb[2]),
.read (read_2),
.data_in (data_out_fsm),
.data_out (data_out_2),
.empty (empty_2),
.full (ll2));
always@(posedge clk)
begin
if(mem_en)
if(mem_rd_wr)
begin
mem[mem_add]=mem_data;
///$display("%d %d %d %d %d",mem_add,mem[0],mem[1],mem[2],mem[3]);
end
end
endmodule //router
Search ✔
Verilog
Verification
Verilog Switch TB Top Module:
Basic Constructs Top module contains the instance of the Dut and verification environment.
It also has the clock generator. For more information about clock generation, go
through TB_CONCEPTS in this website. Do reset and Confgure the dut port address.
OpenVera
Constructs CODE: top
module top();
Switch TB reg clock;
RVM Switch TB wire packet_valid;
wire [7:0] data;
RVM Ethernet sample wire [7:0] data_0;
wire [7:0] data_1;
wire [7:0] data_2;
Specman E wire [7:0] data_3;
wire ready_0;
Interview Questions wire ready_1;
wire ready_2;
wire ready_3;
wire read_0;
wire read_1;
wire read_2;
wire read_3;
reg reset;
reg mem_en;
reg mem_rd_wr;
reg [7:0] mem_data;
reg [1:0] mem_add;
reg [7:0] mem[3:0];
//Clock generator
initial
clock = 0;
always
begin
#5 clock = !clock;
end
mem_data = mem[0];
@(negedge clock);
mem_rd_wr = 1;
mem_add = 1;
mem_data = mem[1];
@(negedge clock);
mem_rd_wr = 1;
mem_add = 2;
mem_data = mem[2];
@(negedge clock);
mem_rd_wr = 1;
mem_add = 3;
mem_data = mem[3];
@(negedge clock);
mem_en=0;
mem_rd_wr = 0;
mem_add = 0;
mem_data = 0;
end
endmodule //top
Search ✔
task randomize();
OpenVera begin
Constructs uid = uid +1;
Switch TB parity_type= {$random}%2;// 0 and 1 are selected randomly
payload_size={$random}%3;// 0,1,2 are selected randomly
RVM Switch TB Da = top.mem[({$random}%3)];//{$random}%3;// 0,1,2,3 are selected randomly
RVM Ethernet sample Sa = $random;
if(payload_size== `SMALL)
len = {$random}%10;
else if(payload_size== `MEDIUM)
Specman E len = 10+{$random}%10;
Interview Questions else if(payload_size==`LARGE)
len = 20+{$random()}%10;
else len = {$random()}%10;
if(parity_type==0)
parity=8'b0;
else
parity=8'b1;
end
endtask
task packing();
integer i;
begin
pkt[0]=Da;
pkt[1]=Sa;
pkt[2]=len;
$display("[PACKING] pkt[0] is Da %b %d Sa %b %d len %b %d
",pkt[0],Da,Sa,Sa,len,len);
for (i = 0;i<len+3;i=i+1)
pkt[i+3]=$random();
pkt[3] = uid;
pkt[i+3]=parity ^ parity_cal(0);
end
endtask
// parity_calc()
//
// Return the byte resulting from xor-ing among all data bytes
// and the byte resulting from concatenating addr and len
//////////////////////////////////////////////////////////////
function [0:7] parity_cal(input dummy);
integer i;
reg [0:7] result ;
begin
result = 8'hff;
for (i = 0;i<len+4;i=i+1)
begin
result = result ^ pkt[i];
end
parity_cal=result;
end
endfunction
endmodule
Search ✔
Specman E
Interview Questions task drive_packet() ;
integer i;
begin
$display("DRIVER Starting to drive packet to port %0d len %0d ",gen.Da,gen.len);
repeat(4)@(negedge clock);
for (i=0;i<gen.len+4;i=i+1)
begin
@ (negedge clock);
packet_valid = 1 ;
data[7:0] = gen.pkt[i];
end
@ (negedge clock);
packet_valid = 0 ;
@(negedge clock);
end
endtask
endmodule
Search ✔
task unpacking;
reg [7:0]rec_parity;
reg [7:0]rec_paclen;
reg [7:0]separate;
reg [7:0]rec_data[0:63];
begin
rec_paclen=mem[2];
rec_parity=mem[rec_paclen+3];
rec_address=mem[0];
$display("rec_parity=%b rec_paclen=%0d %b, rec_address=%b header
%b",rec_parity,rec_paclen, rec_paclen, rec_address,mem[0]);
end
endtask
task checker(input integer size);
integer i;
begin
$display("[CHECKER] Checker started for pkt_no %d ",top.tb.sb.pkt_no );
if(rec_address!=top.mem[port])
begin
->top.tb.error;
// Check whether the packet is coming on the proper port or not
$display("[CHECKER] ERROR PKT RECIVED ON PORT %d,PKT ADDRESS is
%d",top.mem[port],rec_address);
end
for(i=0;i<size;i=i+1)
// get the packet from score board and comare the recived packet with the sent
packet.
if(top.tb.sb.sent_pkt[i][top.tb.sb.pkt_no]!== mem[i])
begin
$display("[CHECKER] ERROR at %d pkt no %d ",i,top.tb.sb.pkt_no);
$display("[CHECKER] at %d sentbyte %b rcevbyte
%b",i,top.tb.sb.sent_pkt[i][top.tb.sb.pkt_no], mem[i]);
->top.tb.error;
end
else
begin
$display("[CHECKER] at %d sentbyte %b rcevbyte
%b",i,top.tb.sb.sent_pkt[i][top.tb.sb.pkt_no], mem[i]);
end
top.tb.sb.pkt_no=top.tb.sb.pkt_no+1;
end
endtask
endmodule
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
// Driver instance
driver dv(clock,packet_valid,data,busy);
.port(0)
);
receiver rec1(.clk(clock),.data(data_1), .ready(ready_1),
.read(read_1),
.port(1)
);
receiver rec2(.clk(clock),.data(data_2), .ready(ready_2),
.read(read_2),
.port(2)
);
receiver rec3(.clk(clock),.data(data_3), .ready(ready_3),
.read(read_3),
.port(3)
);
$finish;
end
endtask
endmodule
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Verilog Memory : Verilog allows for two dimensional arrays which typically get used for
Verification memory spaces. For example reg[7:0] m[63:0]; declares m to be a two-dimensional
array consisting of 64 eight-bit words. You can access any word as m[2] for example
Verilog Switch TB but you do not get access to the bits in the word unless you copy the word to another
Basic Constructs 8-bit reg variable.
Strings : Strings are delimited by " ... ", and cannot be on multiple lines.
OpenVera "hello world"; // legal string
Constructs
Switch TB Number : Numbers in verilog are in the following format.
The size is always specified as a decimal number. If no is specified then the default
RVM Switch TB size is at least 32bits and may be larger depending on the machine. Valid base formats
RVM Ethernet sample are 'b , 'B , 'h , 'H 'd , 'D , 'o , 'O for binary, hexadecimal, decimal, and octal. Numbers
consist of strings of digits (0-9, A-F, a-f, x, X, z, Z). The X's mean unknown, and the
Z's mean high impedance If no base format is specified the number is assumed to be a
decimal number. Some examples of valid numbers are:
Specman E
Interview Questions
EXAMPLE: Unsized constant numbers
659 // is a decimal number
'h 837FF // is a hexadecimal number
'o7460 // is an octal number
4af // is illegal (hexadecimal format requires <92>h)
reg [11:0] a, b, c, d;
initial begin
a = 'h x; // yields xxx
b = 'h 3x; // yields 03x
c = 'h z3; // yields zz3
d = 'h 0z3; // yields 0z3
end
reg [84:0] e, f, g;
e = 'h5; // yields {82{1'b0},3'b101}
f = 'hx; // yields {85{1'hx}}
g = 'hz; // yields {85{1'hz}}
27_195_000
16'b0011_0101_0001_1111
32'h 12ab_f001
1.2
0.1
2394.26331
1.2E12 (the exponent symbol can be e or E)
1.30e-2
0.1e-0
23E10
29E-2
236.123_763_e-12 (underscores are ignored)
Search ✔
OpenVera Vectors
Constructs
Switch TB
A net or reg declaration without a range specification shall be considered 1 bit wide
RVM Switch TB and is known as a scalar. Multiple bit net and reg data types shall be declared by
RVM Ethernet sample specifying a range, which is known as a vector.
EXAMPLES:
Specman E wand w; // a scalar net of type wand
Interview Questions tri [15:0] busa; // a three-state 16-bit bus
trireg (small) storeit; // a charge storage node of strength small
reg a; // a scalar reg
reg[3:0] v; // a 4-bit vector reg made up of (from most to
// least significant) v[3], v[2], v[1], and v[0]
reg signed [3:0] signed_reg; // a 4-bit vector in range -8 to 7
reg [-1:4] b; // a 6-bit vector reg
wire w1, w2; // declares two wires
reg [4:0] x, y, z; // declares three 5-bit regs
Memories
A one dimensional array with elements of type reg is also called a memory. These
memories can be used to model read-only memories (ROMs), random access memories
(RAMs), and reg files. Each reg in the array is known as an element or word and is
addressed by a single array index. An n-bit reg can be assigned a value in a single
assignment, but a complete memory cannot. To assign a value to a memory word, an
index shall be specified. The index can be an expression. This option provides a
mechanism to reference different memory words, depending on the value of other
variables and nets in the circuit. For example, a program counter reg could be used
to index into a RAM.
EXAMPLE:
reg [7:0] mema[0:255]; // declares a memory mema of 256 8-bit
// registers. The indices are 0 to 255
reg arrayb[7:0][0:255]; // declare a two dimensional array of
// one bit registers
wire w_array[7:0][5:0]; // declare array of wires
integer inta[1:64]; // an array of 64 integer values
time chng_hist[1:1000] // an array of 1000 time values
Net Types
wire , tri , tri0 , supply0 , wand, triand, tri1, supply1, wor, trior, trireg.
Search ✔
Easy Labs : SV
Easy Labs : UVM Operator Name
- Unary Minus
Easy Labs : OVM
Easy Labs : VMM
Relational Operators
AVM Switch TB
VMM Ethernet sample Relational operators compare two operands and return a logical value, i. e., TRUE(1)
or FALSE(0). If any bit is unknown, the relation is ambiguous and the result is
unknown.
Verilog
Verification Operator Name
Verilog Switch TB
> Greater than
Basic Constructs >= Greater than or equal
< Less than
<= Less than or equal
== Logical equality
OpenVera != Logical inequality
Constructs
Switch TB
Logical Operators
RVM Switch TB
RVM Ethernet sample
Logical operators operate on logical operands and return a logical value, i. e.,
TRUE(1) or FALSE(0). Used typically in if and while statements. Do not confuse logical
operators with the bitwise Boolean operators. For example , ! is a logical NOT and ~ is
Specman E a bitwise NOT. The first negates, e. g., !(5 == 6) is TRUE. The second complements
Interview Questions the bits, e. g., ~{1,0,1,1} is 0100.
Operator Name
! Logical negation
&& Logical AND
|| Logical OR
Bitwise Operators
Bitwise operators operate on the bits of the operand or operands. For example, the
result of A & B is the AND of each corresponding bit of A with B. Operating on an
unknown (x) bit results in the expected value. For example, the AND of an x with a
FALSE is an x. The OR of an x with a TRUE is a TRUE.
Operator Name
~ Bitwise negation
& Bitwise AND
| Bitwise OR
^ Bitwise XOR
~& Bitwise NAND
~| Bitwise NOR
~^ or ^~ Equivalence Bitwise NOT XOR
Unary reduction operators produce a single bit result from applying the operator to all
of the bits of the operand. For example, &A will AND all the bits of A.
Operator Name
& AND reduction
| OR reduction
^ XOR reduction
~& NAND reduction
~| NOR reduction
~^ XNOR reduction
Other Operators
Operator Name
=== Case equality
!== Case inequality
{ , } Concatenation
<< Shift left
>> Shift right
?: Conditional
Shift left : Vacated bit positions are filled with zeros, e. g., A = A << 2; shifts A
two bits to left with zero fill.
Operator Precedence
The precedence of operators is shown below. The top of the table is the highest
precedence and the bottom is the lowest. Operators on the same line have the same
precedence and associate left to right in an expression. Parentheses can be used to
change the precedence or clarify the situation. We strongly urge you to use
parentheses to improve readability.
Search ✔
endmodule
EXAMPLE:
rega = 0;
rega[3] = 1; // a bit-select
rega[3:5] = 7; // a part-select
mema[address] = 8'hff; // assignment to a mem element
{carry, acc} = rega + regb; // a concatenation
EXAMPLE:
module evaluates2 (out);
output out;
reg a, b, c;
initial begin
a = 0;
b = 1;
c = 0;
end
always c = #5 ~c;
always @(posedge c) begin
a <= b; // evaluates, schedules,
b <= a; // and executes in two steps
end
endmodule
The procedural continuous assignments (using keywords assign and force) are
procedural statements that allow expressions to be driven continuously onto variables
or nets.
The left-hand side of the assignment in the assign statement shall be a variable
reference or a concatenation of variables. It shall not be a memory word (array
reference) or a bit-select or a part-select of a variable. In contrast, the left-hand
side of the assignment in the force statement can be a variable reference or a net
reference. It can be a concatenation of any of the above. Bit-selects and part-selects
of vector variables are not allowed.
The assign procedural continuous assignment statement shall override all procedural
assignments to a variable. The deassign procedural statement shall end a procedural
continuous assignment to a variable. The value of the variable shall remain the same
until the reg is assigned a new value through a procedural assignment or a procedural
continuous assignment.
EXAMPLE:
module dff (q, d, clear, preset, clock);
output q;
input d, clear, preset, clock;
reg q;
always @(clear or preset)
if (!clear)
assign q = 0;
else if (!preset)
assign q = 1;
else
deassign q;
always @(posedge clock)
q = d;
endmodule
Another form of procedural continuous assignment is provided by the force and release
procedural statements. These statements have a similar effect to the assign-deassign
pair, but a force can be applied to nets as well as to variables. The left-hand side of
the assignment can be a variable, a net, a constant bit-select of a vector net, a part-
select of a vector net, or a concatenation. It cannot be a memory word (array
reference) or a bit-select or a part-select of a vector variable.
A force procedural statement on a net overrides all drivers of the net gate outputs,
module outputs, and continuous assignments until a release procedural statement is
executed on the net. Releasing a variable that currently has an active procedural
continuous assignment shall re-establish that assignment.
EXAMPLE:
module test;
reg a, b, c, d;
wire e;
and and1 (e, a, b, c);
initial begin
$monitor("%d d=%b,e=%b", $stime, d, e);
assign d = a & b & c;
a = 1;
b = 0;
c = 1;
#10;
force d = (a | b | c);
force e = (a | b | c);
#10 $stop;
release d;
release e;
#10 $finish;
end
endmodule
Results:
0 d=0,e=0
10 d=1,e=1
20 d=0,e=0
Delays
Delays are not synthesysable. In a delayed assignment Dt time units pass before the
statement is executed and the left-hand assignment is made. With intra-assignment
delay, the right side is evaluated immediately but there is a delay of Dt before the
result is place in the left hand assignment. If another procedure changes a right-hand
side signal during Dt, it does not effect the output. Delays are not supported by
synthesis tools.
This is the most common delay used - sometimes also referred to as inter-assignment
delay control.
EXAMPLE:
It simply waits for the appropriate number of timesteps before executing the
command.
With this kind of delay, the value of x + y is stored at the time that the assignment is
executed, but this value is not assigned to q until after the delay period, regardless of
whether or not x or y have changed during that time.
EXAMPLE:
q = #10 x + y;
Search ✔
Verilog case (<expression>)
Verification <value1>: <statement>
<value2>: <statement>
Verilog Switch TB default: <statement>
Basic Constructs endcase
Specman E Forever
Interview Questions
Forever Continuously executes a statement or block till the end of simulation.
EXAMPLE:
initial
clock =0;
forever
#10 clock = ~clock;
end
Repeat
EXAMPLE:
parameter size = 8, longsize = 16;
reg [size:1] opa, opb;
reg [longsize:1] result;
begin : mult
reg [longsize:1] shift_opa, shift_opb;
shift_opa = opa;
shift_opb = opb;
result = 0;
repeat (size) begin
if (shift_opb[1])
result = result + shift_opa;
shift_opa = shift_opa << 1;
shift_opb = shift_opb >> 1;
end
end
While
Executes a statement until an expression becomes false. If the expression starts out
false, the statement shall not be executed at all.
EXAMPLE:
begin : count1s
reg [7:0] tempreg;
count = 0;
tempreg = rega;
while (tempreg) begin
if (tempreg[0])
count = count + 1;
tempreg = tempreg >> 1;
end
end
For
EXAMPLE:
begin
initial_assignment;
while (condition) begin
statement
step_assignment;
end
end
Search ✔
Search ✔
CODE:
type[range] signal_name
The range is omitted for scalar variables but used for vectors.
The net types are typically used for input signals and for intermediate signals within
combinational logic. Variables are used for sequential circuits or for outputs which
are assigned a value within a sequential always block.
EXAMPLEs:
wire w; //w is a single net of type wire
wire[2:0] wVect; //Declares wVect[2], wVect[1], wVect[0]
tri[7:0] bus //An 8-bit tri state bus
integer i; //i is a 32-bit integer used for loop control
reg r; //r is a 1-bit register
reg[7:0] buf; //buf is an 8-bit register
reg[3:0] r1, r2 //r1 and r2 are both 4-bit registers
Search ✔
Search ✔
An always block is similar to the initial block, but the statements inside an always
Specman E block will repeated continuously, in a looping fashion, until stopped by $finish or
Interview Questions $stop.
NOTE: the $finish command actually terminates the simulation where as $stop.
merely pauses it and awaits further instructions. Thus $finish is the preferred
command unless you are using an interactive version of the simulator.
One way to simulate a clock pulse is shown in the example below. Note, this is not the
best way to simulate a clock. See the section on the forever loop for a better method.
EXAMPLE:
module pulse;
reg clock;
endmodule
Tasks and functions can bu used to in much the same manner but there are some
important differences that must be noted.
Functions
A function is unable to enable a task however functions can enable other functions.
A function will carry out its required duty in zero simulation time.
Within a function, no event, delay or timing control statements are permitted.
In the invocation of a function their must be at least one argument to be passed.
Functions will only return a single value and can not use either output or inout
statements.
Functions are synthesysable.
Disable statements canot be used.
Function canot have numblocking statements.
EXAMPLE:function
module function_calling(a, b,c);
input a, b ;
output c;
wire c;
function myfunction;
input a, b;
begin
myfunction = (a+b);
end
endfunction
Task
Tasks are capable of enabling a function as well as enabling other versions of a Task
Tasks also run with a zero simulation however they can if required be executed in a
non zero simulation time.
Tasks are allowed to contain any of these statements.
A task is allowed to use zero or more arguments which are of type output, input or
inout.
A Task is unable to return a value but has the facility to pass multiple values via the
output and inout statements.
Tasks are not synthesisable.
Disable statements can be used.
EXAMPLE:task
module traffic_lights;
reg clock, red, amber, green;
parameter on = 1, off = 0, red_tics = 350,
amber_tics = 30, green_tics = 200;
// initialize colors.
initial red = off;
initial amber =
Search ✔
Specman E
Interview Questions
Search ✔
Event :
Specman E
A event can be triggered explicitly. It can be used in an event expression to control
Interview Questions the execution of procedural statements.
Enumerated Types :
Enumerated types are a user-defined list of named integer constants. They can either
be defined in the global name space, or in a class.Elements within enumerated type
definitions are numbered consecutively, starting from 0.Each element may have an
optional explicit value assigned to it.
Default numbering
Ex : enum colors {red, green, blue, yellow, white, black};
Explicit numbering
Ex : enum instructions {add=10, sub, div, mul=4, jmp};
Class Scope enumration
Ex : class Bus { enum TRAFFIC = PCI, AHB, USB; }
Virtual Ports :
A virtual port is a user-defined data type that contains a set of port signal members
grouped together under a given user-defined port name.
port rcv_port
{
frame_n;
valid_n;
busy;
packet;
}
Arrays :
Fixed-Size Arrays:
Arrays whose size is fixed at compilation time are called fixed tsize arrays.The access
time is constant regardless of the number of elements in an array.Multi-dimensional
arrays are fixed-size arrays with multiple dimensions.
Dynamic Arrays :
integer array_ex[*];
new[] : The new[] operator is used to set or change the size of dynamic
arrays during runtime.
Associative Arrays :
When the size of the collection is unknown or the data space is sparse, associative
array are used.Associative arrays do not have any storage allocated until it is used,
and the index expression is not restricted to integral expressions, but can be of any
type.
Smart Queues :
Class :
The user-defined data type, class, is composed of data members of valid OpenVera
data types (known as properties) and tasks or functions (known as methods) for
manipulating the data members.The properties and methods, taken together, define
the contents and capabilities of a class instance or object.
Search ✔
front() :The front() method returns the first element in the list.
back() :The back() method returns the last element in the list.
data() :The data() method returns the data stored at a particular location:
EXAMPLE:Linked list
#include <VeraListProgram.vrh>
#include <ListMacros.vrh>
MakeVeraList(integer);
program main{
VeraList_integer List1;
VeraListIterator_integer itor;
List1 = new();
printf (" size of list is %d \n",List1.size());
List1.push_back(10);
List1.push_front(22);
printf (" size of list is %d \n",List1.size());
printf (" poping from list : %d \n",List1.front());
printf (" poping from list : %d \n",List1.front());
List1.pop_front();
List1.pop_front();
printf (" size of list is %d \n",List1.size());
List1.push_back(5);
List1.push_back(55);
List1.push_back(555);
List1.push_back(5555);
printf (" size of list is %d \n",List1.size());
itor = List1.start();
printf (" startn of list %d \n",itor.data());
itor.next();
printf (" second element of list is %d \n",itor.data());
itor.next();
printf (" third element of list is %d \n",itor.data());
itor.next();
printf (" fourth element of list is %d \n",itor.data());
itor = List1.erase(itor);
printf (" after erasing element,the itor element of list is %d \n",itor.data());
itor.prev();
printf(" prevoious element is %d \n",itor.data());
printf (" END OF PROGRAM\n");
}
RESULTS:
size of list is 0
size of list is 2
poping from list : 22
poping from list : 22
size of list is 0
size of list is 4
startn of list 5
second element of list is 55
Search ✔
Specman E
Interview Questions EXAMPLE :Arithmetic
program main {
integer a,b;
b = 10;
a = 22;
printf(" -(nagetion) is %0d \n",-(a) );
printf(" a + b is %0d \n",a+b);
printf(" a - b is %0d \n",a-b);
printf(" a * b is %0d \n",a*b);
printf(" a / b is %0d \n",a/b);
RESULTS
-(nagetion) is -22
a + b is 32
a - b is 12
a * b is 220
a / b is 2
a modules b is 2
Relational:
EXAMPLE :Relational
program main {
integer a,b;
b = 10;
a = 22;
printf(" a < b is %0d \n",a < b);
printf(" a > b is %0d \n",a >b);
printf(" a <= b is %0d \n",a <= b);
printf(" a >= b is %0d \n",a >= b);
}
RESULTS
a < b is 0
a > b is 1
a <= b is 0
a >= b is 1
Equality:
if (x == a)
printf("x equals a is TRUE.\n");
if (y == a)
printf("y equals a is TRUE.\n");
if (z == a)
printf("z equals a is TRUE.\n");
RESULTS
y equals a is TRUE.
RESULTS
--------------------------
== 0 1 x z
--------------------------
0 1 0 x x
1 0 1 x x
x x x x x
Search ✔
Bitwise :
EXAMPLE : Bitwise
program main {
reg a_1,a_0,a_x,a_z;
reg b_1,b_0,b_x,b_z;
a_1 = 'b1;a_0 = 'b0;a_x = 'bx;a_z = 'bz;
b_1 = 'b1;b_0 = 'b0;b_x = 'bx;b_z = 'bz;
printf("--------------------------\n");
printf (" ~ 0 1 x z \n");
printf("--------------------------\n");
printf (" %b %b %b %b \n",~b_0,~b_1,~b_x,~b_z);
printf("--------------------------\n");
printf("--------------------------\n");
printf (" & 0 1 x z \n");
printf("--------------------------\n");
printf (" 0 %b %b %b %b \n",a_0 & b_0,a_0 & b_1,a_0 & b_x,a_0 & b_z);
printf (" 1 %b %b %b %b \n",a_1 & b_0,a_1 & b_1,a_1 & b_x,a_1 & b_z);
printf (" x %b %b %b %b \n",a_x & b_0,a_x & b_1,a_x & b_x,a_x & b_z);
printf (" z %b %b %b %b \n",a_z & b_0,a_z & b_1,a_z & b_x,a_z & b_z);
printf("--------------------------\n");
printf("--------------------------\n");
printf (" &~ 0 1 x z \n");
printf("--------------------------\n");
printf (" 0 %b %b %b %b \n",a_0 &~ b_0,a_0 &~ b_1,a_0 &~ b_x,a_0 &~ b_z);
printf (" 1 %b %b %b %b \n",a_1 &~ b_0,a_1 &~ b_1,a_1 &~ b_x,a_1 &~ b_z);
printf (" x %b %b %b %b \n",a_x &~ b_0,a_x &~ b_1,a_x &~ b_x,a_x &~ b_z);
printf (" z %b %b %b %b \n",a_z &~ b_0,a_z &~ b_1,a_z &~ b_x,a_z &~ b_z);
printf("--------------------------\n");
printf("--------------------------\n");
printf (" | 0 1 x z \n");
printf("--------------------------\n");
printf (" 0 %b %b %b %b \n",a_0 | b_0,a_0 | b_1,a_0 | b_x,a_0 | b_z);
printf (" 1 %b %b %b %b \n",a_1 | b_0,a_1 | b_1,a_1 | b_x,a_1 | b_z);
printf (" x %b %b %b %b \n",a_x | b_0,a_x | b_1,a_x | b_x,a_x | b_z);
printf (" z %b %b %b %b \n",a_z | b_0,a_z | b_1,a_z | b_x,a_z | b_z);
printf("--------------------------\n");
printf (" |~ 0 1 x z \n");
printf("--------------------------\n");
printf (" 0 %b %b %b %b \n",a_0 |~ b_0,a_0 |~ b_1,a_0 |~ b_x,a_0 |~ b_z);
printf (" 1 %b %b %b %b \n",a_1 |~ b_0,a_1 |~ b_1,a_1 |~ b_x,a_1 |~ b_z);
printf (" x %b %b %b %b \n",a_x |~ b_0,a_x |~ b_1,a_x |~ b_x,a_x |~ b_z);
printf (" z %b %b %b %b \n",a_z |~ b_0,a_z |~ b_1,a_z |~ b_x,a_z |~ b_z);
printf("--------------------------\n");
printf("--------------------------\n");
printf (" ^ 0 1 x z \n");
printf("--------------------------\n");
printf (" 0 %b %b %b %b \n",a_0 ^ b_0,a_0 ^ b_1,a_0 ^ b_x,a_0 ^ b_z);
printf (" 1 %b %b %b %b \n",a_1 ^ b_0,a_1 ^ b_1,a_1 ^ b_x,a_1 ^ b_z);
printf (" x %b %b %b %b \n",a_x ^ b_0,a_x ^ b_1,a_x ^ b_x,a_x ^ b_z);
printf (" z %b %b %b %b \n",a_z ^ b_0,a_z ^ b_1,a_z ^ b_x,a_z ^ b_z);
printf("--------------------------\n");
printf (" ^~ 0 1 x z \n");
printf("--------------------------\n");
printf (" 0 %b %b %b %b \n",a_0 ^~ b_0,a_0 ^~ b_1,a_0 ^~ b_x,a_0 ^~ b_z);
printf (" 1 %b %b %b %b \n",a_1 ^~ b_0,a_1 ^~ b_1,a_1 ^~ b_x,a_1 ^~ b_z);
printf (" x %b %b %b %b \n",a_x ^~ b_0,a_x ^~ b_1,a_x ^~ b_x,a_x ^~ b_z);
printf (" z %b %b %b %b \n",a_z ^~ b_0,a_z ^~ b_1,a_z ^~ b_x,a_z ^~ b_z);
printf("--------------------------\n");
}
RESULTS
--------------------------
~ 0 1 x z
--------------------------
1 0 x x
--------------------------
--------------------------
& 0 1 x z
--------------------------
0 0 0 0 0
1 0 1 x x
x 0 x x x
z 0 x x x
--------------------------
--------------------------
&~ 0 1 x z
--------------------------
0 1 1 1 1
1 1 0 x x
x 1 x x x
z 1 x x x
--------------------------
--------------------------
| 0 1 x z
--------------------------
0 0 1 x x
1 1 1 1 1
x x 1 x x
z x 1 x x
--------------------------
|~ 0 1 x z
--------------------------
0 1 0 x x
1 0 0 0 0
x x 0 x x
z x 0 x x
--------------------------
--------------------------
^ 0 1 x z
--------------------------
0 0 1 x x
1 1 0 x x
x x x x x
z x x x x
--------------------------
^~ 0 1 x z
--------------------------
0 1 0 x x
1 0 1 x x
x x x x x
z x x x x
--------------------------
Reduction :
# & unary and
# ~& unary nand
# | unary or
# ~| unary nor
# ^ unary exclusive or
# ~^ unary exclusive nor
EXAMPLE : Reduction
program main {
reg [3:0] a_1,a_0,a_01xz,a_1xz,a_0xz,a_0dd1,a_even1;
a_1 = 4'b1111 ;
a_0 = 4'b0000 ;
a_01xz = 4'b01xz ;
a_1xz = 4'b11xz ;
a_0xz = 4'b00xz ;
a_0dd1 = 4'b1110 ;
a_even1 = 4'b1100 ;
printf("-------------------------------------------\n");
printf(" a_1 a_0 a_01xz a_1xz a_0xz \n");
printf("-------------------------------------------\n");
printf("& %b %b %b %b %b \n",&a_1,&a_0,&a_01xz,&a_1xz,&a_0xz);
printf("| %b %b %b %b %b \n",|a_1,|a_0,|a_01xz,|a_1xz,|a_0xz);
printf("~& %b %b %b %b
%b \n",~&a_1,~&a_0,~&a_01xz,~&a_1xz,~&a_0xz);
printf("~| %b %b %b %b
%b \n",~|a_1,~|a_0,~|a_01xz,~|a_1xz,~|a_0xz);
printf("-------------------------------------------\n");
printf(" a_ood1 a_even1 a_1xz\n");
printf("-------------------------------------------\n");
printf(" ^ %b %b %b \n",^a_0dd1,^a_even1,^a_1xz);
printf(" ~^ %b %b %b \n",~^a_0dd1,~^a_even1,~^a_1xz);
printf("-------------------------------------------\n");
}
RESULTS
-------------------------------------------
a_1 a_0 a_01xz a_1xz a_0xz
-------------------------------------------
& 1 0 0 x 0
| 1 0 1 1 x
~& 0 1 1 x 1
~| 0 1 0 0 x
-------------------------------------------
a_ood1 a_even1 a_1xz
-------------------------------------------
^ 1 0 x
~^ 0 1 x
-------------------------------------------
Search ✔
a_1 is 21 a_0 is 19
Conditional :
?: conditional
EXAMPLE : Conditional
program main {
integer i,j,sub;
for (i=0; i<3; i++)
for (j=3; j>0; j--){
sub = (i>j) ? i-j : j-i;
printf("i = %0d\t j = %0d\tsub = %0d\n", i,j,sub);
}
}
RESULTS
i= 0 j = 3 sub = 3
i= 0 j = 2 sub = 2
i= 0 j = 1 sub = 1
i= 1 j = 3 sub = 2
i= 1 j = 2 sub = 1
i= 1 j = 1 sub = 0
i= 2 j = 3 sub = 1
i= 2 j = 2 sub = 0
i= 2 j = 1 sub = 1
Set
in !in dist
EXAMPLE : Set
program main {
integer i;
i = 20;
if( i in {10,20,30})
printf(" I is in 10 20 30 ");
}
RESULTS
I is in 10 20 30
Replication :
EXAMPLE : Replication
program main {
reg [5:0] i;
i = { 3{2'b10}};
printf(" I is %b ",i);
}
RESULTS
I is 101010
Search ✔
Specman E
Interview Questions
Search ✔
EXAMPLE : forloop
program for_loop
{
integer count, i;
for(count = 0, i=0; i*count<50; i++, count++)
printf("Value i = %0d\n", i);
}
RESULTS
Value i = 0
Value i = 1
Value i = 2
Value i = 3
Value i = 4
Value i = 5
Value i = 6
Value i = 7
EXAMPLE : whileloop
program while_loop{
integer operator=0;
while (operator<5){
operator += 1;
printf("Operator is %0d\n", operator);
}
}
RESULTS
Operator is 1
Operator is 2
Operator is 3
Operator is 4
Operator is 5
EXAMPLE : dowhile
program test
{
integer i = 0;
do
{
printf("i = %0d \n", i);
i++;
} while (i < 10);
}
RESULTS
i= 0
i= 1
i= 2
i= 3
i= 4
i= 5
i= 6
i= 7
i= 8
i= 9
EXAMPLE : foeach
program example{
string names[$]={"Hello", "Vera"};
foreach (names, i) {
printf("Value at index %0d is %0s\n", i, names[i]);
}
}
RESULTS
EXAMPLE : randcase
program rand_case{
integer i;
repeat(10){
randcase
{
10: i=1;
20: i=2;
50: i=3;
}
printf(" i is %d \n",i);}
}
RESULTS
i is 3
i is 2
i is 3
i is 3
i is 3
i is 3
i is 1
i is 1
i is 1
i is 2
Search ✔
RESULTS
i is changed to 1 at 10
i is 0 at 15
i is changed to 2 at 20
i is 0 at 25
End of Program at 25
Pass By Reference :
In pass by reference functions and tasks directly access the specified variables passed
as arguments.Its like passing pointer of the variable.
task pass(var int i) {
delay(10);
i = 1;
printf(" i is changed to %d at %d\n",i,get_time(LO) );
delay(10);
i = 2;
printf(" i is changed to %d at %d\n",i,get_time(LO) );
}
task display(){
delay(15);
printf(" i is %d at %d\n",i,get_time(LO));
delay(10);
printf(" i is %d at %d\n",i,get_time(LO));
}
RESULTS
i is changed to 1 at 10
i is 1 at 15
i is changed to 2 at 20
i is 2 at 25
End of Program at 25
Default Arguments:
To handle common cases or allow for unused arguments, OpenVera allows you to
define default values for each scalar argument.When the subroutine is called, you can
omit an argument that has a default defined for it. Use an asterisk (*) as a
placeholder in the subroutine call.
program main{
integer i;
i=0;
display(1,4,6);
display(*,4,*);
display(*,8,4);
}
RESULTS
i si 1 k is 4 , datat is 000110
i si 0 k is 4 , datat is 000000
i si 0 k is 8 , datat is 000100
Optional Arguments:
To allow subroutines to evolve over time without having to change all of the existing
calls, OpenVera supports optional arguments.Optional arguments must have default
values.Any number of additional optional arguments can be created.Parentheses are
used to determine the depth level of an optional argument.
program main{
integer i;
i=0;
my_task(1,2,3);
my_task(1);
my_task(1,2);
}
RESULTS
a is 1, b is 2 c is 3
a is 1, b is 1 c is 1
a is 1, b is 2 c is 1
Subroutine Termination :
Normally, functions and tasks return control to the caller after the last statement of
the block is executed. OpenVera provides the return statement to manually pass
control back to the caller.
Search ✔
Specman E
Interview Questions
Search ✔
join none
printf(" time = %d Outside the main fork \n",get_time(LO) );
delay(40);
}
RESULTS
BEFORE fork time = 10
time = 10 Outside the main fork
time = 15 delay 5
time = 20 delay 10
time = 30 delay 20
program main {
delay(10);
BEFORE fork time = 10
time = 15 delay 5
time = 15 Outside the main fork
time = 20 delay 10
time = 30 delay 20
program main {
delay(10);
printf(" BEFORE fork time = %d \n",get_time(LO) );
fork {
delay (20);
printf("time = %d delay 20 \n ",get_time(LO) );
}
{
delay(10);
printf("time = %d delay 10 \n ",get_time(LO) );
}
{
delay(5);
printf("time = %d delay 5 \n ",get_time(LO) );
}
join all
printf(" time = %d Outside the main fork \n",get_time(LO) );
delay(40);
}
RESULTS
BEFORE fork time = 10
time = 15 delay 5
time = 20 delay 10
time = 30 delay 20
time = 30 Outside the main fork
When defining a fork/join block, encapsulating the entire fork inside braces ({})
results in the entire block being treated as a single thread, and the code executes
consecutively.
program main {
delay(10);
}
join any
printf(" time = %d Outside the main fork \n",get_time(LO) );
delay(40);
}
RESULTS
First fork time = 10
time = 15 delay 5
time = 17 delay 2
time = 17 Outside the main fork
time = 20 delay 10
time = 30 delay 20
Search ✔
RESULTS
time = 20: i is 0
time = 20: i is 1
time = 20: i is 2
END OF SIMUALTION
The solution shows that ,Using the shadow keyword forces the Vera compiler to create
a copy of the variable i local to each child process, which eliminates race conditions.
Any descendants of the child processes will also have a copy of the variable local to
that descendant.
Search ✔
program main {
me() ;
printf(" END of program \n");
}
RESULTS
Terminate:
The terminate statement terminates all active descendants of the current thread in
which it was called.If any of the child processes have other descendants, the
terminate command terminates them as well.
This example forks off several child processes within a task. After any of the child
processes is complete, the code continues to execute. Before the task is completed,
all remaining child processes are terminated.
task task1() {
delay(10);
printf(" before fork time = %d \n",get_time(LO) );
fork {
delay (20);
printf("time = %d delay 20\n ",get_time(LO) );
}
{
delay(10);
printf("time = %d delay 10\n ",get_time(LO) );
}
{
delay(5);
printf("time = %d delay 5\n ",get_time(LO) );
}
join any
fork {
delay(35);
printf("time = %d delay 35\n ",get_time(LO) );
}
{ delay(25)
printf("time = %d delay 25\n ",get_time(LO) );
}
{delay(15)
printf("time = %d delay 15\n ",get_time(LO) );
}
join none
// terminate;
delay(100);
}
program main {
task1();
printf(" Time = %d Task completed \n",get_time(LO) );
}
RESULTS
before fork time = 10
time = 15 delay 5
time = 20 delay 10
time = 30 delay 20
time = 30 delay 15
time = 40 delay 25
time = 50 delay 35
Time = 115 Task completed
task task1() {
delay(10);
printf(" before fork time = %d \n",get_time(LO) );
fork {
delay (20);
printf("time = %d delay 20\n ",get_time(LO) );
}
{
delay(10);
printf("time = %d delay 10\n ",get_time(LO) );
}
{
delay(5);
printf("time = %d delay 5\n ",get_time(LO) );
}
join any
fork {
delay(35);
printf("time = %d delay 35\n ",get_time(LO) );
}
{ delay(25)
printf("time = %d delay 25\n ",get_time(LO) );
}
{delay(15)
printf("time = %d delay 15\n ",get_time(LO) );
}
join none
terminate;
delay(100);
}
program main {
task1();
printf(" Time = %d Task completed \n",get_time(LO) );
}
RESULTS
before fork time = 10
time = 15 delay 5
Time = 115 Task completed
Both the solutions ahow that the task is completed at time 115 .When teriminate is
not used, all the chaild process execute,when teriminate is use,all the chaild
processes are teriminated.
Suspend_thread:
The suspend_thread() system task is used to temporarily suspend the current thread.It
suspends the current thread and allows other ready concurrent threads to run. When
all ready threads have had one chance to block, the suspended thread resumes
execution.
program main {
call();
delay(40);
printf(" END OF SIMUALTION \n");
}
task call(){
shadow integer i; // using shadow variable
delay(10);
for(i = 0; i < 3; i++) {
fork
{
delay(10);
printf(" time = %0d: i is %0d \n",get_time(LO),i);
printf( " Suspending the thread \n");
// suspend_thread();
printf( " After Suspending the thread \n");
printf(" time = %0d: i is %0d \n",get_time(LO),i);
}
join none
}
}
RESULTS
time = 20: i is 0
Suspending the thread
After Suspending the thread
time = 20: i is 0
time = 20: i is 1
Suspending the thread
After Suspending the thread
time = 20: i is 1
time = 20: i is 2
Suspending the thread
After Suspending the thread
time = 20: i is 2
END OF SIMUALTION
program main {
call();
delay(40);
printf(" END OF SIMUALTION \n");
}
task call(){
shadow integer i; // using shadow variable
delay(10);
for(i = 0; i < 3; i++) {
fork
{
delay(10);
printf(" time = %0d: i is %0d \n",get_time(LO),i);
printf( " Suspending the thread \n");
suspend_thread();
printf( " After Suspending the thread \n");
printf(" time = %0d: i is %0d \n",get_time(LO),i);
}
join none
}
RESULTS
time = 20: i is 0
Suspending the thread
time = 20: i is 1
Suspending the thread
time = 20: i is 2
Suspending the thread
After Suspending the thread
time = 20: i is 0
After Suspending the thread
time = 20: i is 1
After Suspending the thread
time = 20: i is 2
END OF SIMUALTION
The solution shows that all the child threads are suspended until all the calls are
made and then reumed.
Search ✔
Search ✔
join none
}
RESULTS
#include "vera_defines.vrh"
program main {
event event1,event2;
call();
sync(ALL,event1,event2);
printf(" time : %0d After sync \n",get_time(LO) );
delay(40);
printf(" END OF SIMUALTION \n");
}
task call(){
fork{
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event1);
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event2);
}
join none
}
RESULTS
#include "vera_defines.vrh"
program main {
event event1,event2;
call();
sync(ORDER,event2,event1);
printf(" time : %0d After sync \n",get_time(LO) );
delay(40);
printf(" END OF SIMUALTION \n");
}
task call(){
fork{
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event2);
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event1);
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event2);
}
join none
}
RESULTS
#include "vera_defines.vrh"
program main {
event event1,event2;
bit check_bit;
call();
check_bit = sync(CHECK,event1);
printf(" time : %0d After sync check_bit is %d \n",get_time(LO),check_bit);
delay(40);
printf(" END OF SIMUALTION \n");
}
task call(){
fork{
trigger(ON,event1);
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event1);
delay(10);
printf("time : %0d , triggering event1 \n",get_time(LO) );
trigger(event2);
}
join
RESULTS
Search ✔
RESULTS
EXAMPLE :ONE_BLAST
#include "vera_defines.vrh"
program vshell
{
event event1, event2, event3;
fork
call_task1();
call_task2();
join none
#150;
printf(" END of program");
}
task call_task1 ()
{
printf("In task call_task1 Sync all events at time %d\n",get_time(LO) );
#30;
sync(ALL,event2,event3);
printf("In task call_task1 Synced at time %d\n", get_time(LO) );
}
task call_task2()
{
printf("In task call_task2 triggering events at time %d\n",get_time(LO) );
#40;
trigger(ONE_BLAST, event2);
#20;
printf("In task call_task2 event2 was triggered and task call_task2 is finished at
time %d \n", get_time(LO) );
}
RESULTS
EXAMPLE :HAND_SHAKE
#include "vera_defines.vrh"
program vshell {
event my_event = ON;
fork
sync_event1();
sync_event2();
trigger_event1();
join all
}
task sync_event1() {
printf("before sync_event1 at time %0d \n");
sync(ALL,my_event);
task sync_event2() {
printf("before sync_event2 at time %0d \n");
sync(ALL,my_event);
printf("after sync_event2 at time %0d \n");
printf("before trigger sync_event2 at time %0d \n");
trigger(ONE_BLAST,my_event);
}
task trigger_event1() {
printf("before trigger_event1 at time %0d \n");
trigger(HAND_SHAKE,my_event);
printf("after trigger_event1 at time %0d \n");
sync(ALL,my_event);
printf("after sync trigger_event1 3 at time %0d \n");
}
RESULTS
Event Variables :
These variables serve as the link between triggers and syncs. They are a unique data
type with several important properties.
task T1 (event trigger_a){
printf("\nT1 syncing at cycle=%0d",get_time(LO) );
sync(ALL, trigger_a); // Blocked: proceed after receiving trigger
printf("\nT1 event trigger_a received at cycle=%0d",get_time(LO) );
delay(70);
printf("\nT1 triggering trigger_a at cycle=%0d",get_time(LO) );
trigger (trigger_a);
}
program trigger_play
{
event trigger1;
fork
T1(trigger1);// start T1 and go on
join none
delay(80); // T1 is blocked waiting for
fork
{
printf("\nPROGRAM triggering trigger1 @cycle=%0d",get_time(LO) );
printf("\nPROGRAM This unblocks T1");
trigger(trigger1); // unblock the waiting T1
}
{ delay(50);
printf("\nPROGRAM syncing @cycle=%0d\n\n",get_time(LO) );
sync (ALL, trigger1) ;// wait for T1 to unblock me
}
join
wait_child();
printf("Trigger play done!");
}
RESULTS
T1 syncing at cycle=0
PROGRAM triggering trigger1 @cycle=80
PROGRAM This unblocks T1
T1 event trigger_a received at cycle=80
PROGRAM syncing @cycle=130
Search ✔
semaphore_put(sema,2);
printf(" Putting back key \n");
delay(10);
}
{
printf("Before getting key 2\n");
RESULTS
The number of keys in the bucket can increase if more keys are put into the bucket
than are removed. Therefore, key_count is not necessarily the maximum number of
keys in the bucket.
EXAMPLE:
program vshell {
integer sema,get;
sema = alloc(SEMAPHORE,0,1,1);
if(!sema)
error("Semaphore Allocation failed\n");
if(!get)
error(" No sempahore key for inject2 \n");
else
printf(" Got Key from 1 \n");
semaphore_put(sema,1);
printf(" Putting back key \n");
semaphore_put(sema,1);
printf(" Putting back key \n");
if(!get)
error(" No sempahore key for inject2 \n");
else
printf(" Got Key from 1 \n");
if(!get)
error(" No sempahore key for inject2 \n");
else
printf(" Got Key from 1 \n");
delay(1000);
}
RESULTS:
Search ✔
}
RESULTS
add 56 data 0 id 1
Search ✔
task get_packets()
{
integer ret;
bit [63:0] packet;
while (1)
{
ret = mailbox_get(WAIT, my_mailbox, packet, CHECK);
if (ret > 0)
printf("Got packet %d @time %d\n", packet, get_time(LO) );
}
}
RESULTS
Search ✔
Specman E
Interview Questions
Search ✔
p2 = new p1;
makes a shallow copy of the object referenced by p1, and sets p2 to point to it. A
shallow copy creates a new object and copies the values of all properties from the
source object. It is a shallow copy because it does not make a copy of any nested
objects.
EXAMPLE : copy
class A{
integer j;
task new(){ j=5;}
}
class B{
integer i;
A a;
task new() {i = 1;}
}
task test(){
B b1 = new(); // Create an object of class B
B b2; //Create a null variable of class B
b1.a = new; //Create an object of class A
b2 = new b1; // Create an object that is a copy of b1,
//but only copies the handle a, not the object
//referenced by a.
b2.i = 10; // i is changed in b2, but not b1
printf("i in b2 = %0d\n", b2.i);// i equals 10
printf("i in b1 = %0d\n", b1.i);// i equals 1
//where as:
b2.a.j = 50; // Change j in the object referenced
// by a. j is shared by both b1 and b2
printf("j is %0d in b1 and %d in b2\n", b1.a.j, b2.a.j);
}
program shallow_copy{
test();
}
RESULTS
i in b2 = 10
i in b1 = 1
j is 50 in b1 and 50 in b2
Properties:
This:
EXAMPLE : this
class Demo
{
integer x;
task new (integer x)
{
this.x = x;
}
}
program main {
Demo D;
D = new(10);
printf(" D.x is %d \n",D.x);
}
RESULTS
D.x is 10
The x is now both a property of the class and an argument to the task new(). In the
task new(), an unqualified reference to x will be resolved by looking at the innermost
scope, in this case the subroutine argument declaration. To access the instance
property,we qualify it with this to refer to the current instance.
Class Extensions :
EXAMPLE : Inheritance
class A {
task disp_a (){
printf(" This is class A ");
}
}
class EA extends A {
task disp_ea (){
printf(" This is Extended class A ");
}
}
program main {
EA my_ea;
my_ea = new();
my_ea.disp_a();
my_ea.disp_ea();
}
RESULTS
Polymorphism :
Polymorphism allows the redefining of methods for derived classes while enforcing a
common interface.To achieve polymorphism the 'virtual' identifier must be used when
defining the base class and method(s) within that class. A virtual class is a class which
serves as a template for the construction of derived classes. One cannot create an
instance of a virtual class.
EXAMPLE : Polymorphism
class A {
virtual task disp (){
printf(" This is class A ");
}
}
class EA extends A {
task disp (){
printf(" This is Extended class A ");
}
}
program main {
EA my_ea;
A my_a;
my_ea = new();
my_a = my_ea;
my_ea.disp();
my_a.disp();
}
RESULTS
Super:
The super keyword is used from within a derived class to refer to properties of the
parent class. It is necessary to use super when the property of the derived class has
been overridden, and cannot be accessed directly.
EXAMPLE :
class A {
virtual task disp (){
printf(" This is class A \n");
}
}
class EA extends A {
task disp (){
super.disp();
printf(" This is Extended class A \n");
}
}
program main {
EA my_ea;
my_ea = new();
my_ea.disp();
}
RESULTS
This is class A
This is Extended class A
Abstract Class:
A set of classes can be created that can be viewed as all being derived from a
common base class.If base class is not supposed to be used to creat an object,then it
has to be declared as abstract class using keyword virtual.
EXAMPLE:
virtual class BasePacket{
function integer send(bit[31:0] data){
}
}
class EtherPacket extends BasePacket{
function integer send(bit[31:0] data){
// body of the function
...
}
}
Search ✔
Search ✔
Rand Modifier :
Variables declared with the rand keyword are standard random variables.
When ther are no other control on distrubution,these variables are uniformly
distributed.
Uniformly distribution is only on the valid values.
EXAMPLE
class rand_cl{
rand bit [0:2] Var;
constraint limit_c { Var < 4;}
}
program rand_p{
rand_cl obj;
integer count_0, count_1, count_2, count_3;
count_0 = 0;count_1 = 0;count_2 = 0;count_3 = 0;
obj = new();
repeat(10000)
{
void = obj.randomize();
if( obj.Var == 0) count_0 ++;
else if( obj.Var == 1) count_1 ++;
else if( obj.Var == 2) count_2 ++;
else if( obj.Var == 3) count_3 ++;
}
printf(" count_0 = %0d , count_1 = %0d, count_2 = %0d, count_3 = %0d
",count_0, count_1, count_2, count_3);
}
RESULTS:
Randc Modifier :
Varibles declared as randc, randomly iterates over all the values in the range and no
value is repeated with in an iteration.
Iteration sequences are not same.Bit and enumarated types can be randc variables.To
reduce memory requirements, implementations can impose a limit on the maximum
size of a randc variable,but it should be no less than 8 bits.
EXAMPLE
class rand_c{
randc bit [1:0]Vari;
}
program rand_cp{
rand_c obj;
integer i;
obj = new();
for(i=0;i<20;i++)
{
void = obj.randomize();
printf("%0d_",obj.Vari);
if(i%4==3)
printf("\n");
}
RESULTS
1_2_0_3_
3_2_0_1_
3_1_2_0_
2_0_3_1_
1_3_2_0_
Search ✔
EXAMPLE:
class simple{
task pre_randomize{
printf(" PRE_RANDOMIZATION ");
}
task post_randomize{
PRE_RANDOMIZATION PRE_RANDOMIZATION
Search ✔
Inline constraints allows to add extra constraints to allready existing conrtints which
are declared inside class.If you have constraints already defined for variavle var,
Specman E solver solves those constraints wlong with the inline constraints.
Interview Questions
EXAMPLE
class inline{
rand integer Var;
constraint default_c { Var > 0 ; Var < 100;}
}
program inline_p{
inline obj;
obj = new();
void = obj.randomize() with { Var == 50;} ;
printf(" Randodmize sucessful Var %d ",obj.Var);
}
RESULTS:
openvera supports to change the status of constraint block dynamically.To change the
staus of a Constraint block,built in constraint_mode() method is used.By default all
the constraint blocks are active.
When it is called as task,the arguments to the task determines the operation to be
performed.
When it is called as function,it returns the active status of the specified constrant
block.
EXAMPLE:
class rand_mo{
rand integer Var1;
rand integer Var2;
constraint Var_1 { Var1 == 20;}
constraint Var_2 { Var2 == 10;}
}
program rand_mo_p{
rand_mo obj = new();
void = obj.randomize();
printf(" Var1 : %d Var2 : %d \n",obj.Var1,obj.Var2);
void = obj.constraint_mode(0,"Var_1");
void = obj.randomize();
printf(" Var1 : %d Var2 : %d \n",obj.Var1,obj.Var2);
void = obj.constraint_mode(0,"Var_2");
void = obj.randomize();
printf(" Var1 : %d Var2 : %d \n",obj.Var1,obj.Var2);
}
RESULTS:
Search ✔
2__7__2__4__7__3__3__4__2__7__
Weighted Distribution
Var dist { 10 := 1; 20 := 2 ; 30 := 2 }
Var dist { 10 := 1; 20 := 2 ; [30:32] := 2 }
Var dist { 10 := 1; 20 := 2 ; [30:32] :/ 2 }
EXAMPLE:
class Dist{
rand integer Var;
constraint range { Var dist { {0,1} := 50 , {2,7} := 50 }; }
}
program Dist_p{
Dist obj;
integer count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7;
integer count_0_1 ,count_2_7 ;
obj=new();
count_0 = 0;count_1 = 0;count_2 = 0;count_3 = 0;
count_4 = 0;count_5 = 0;count_6 = 0;count_7 = 0;
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
if( obj.randomize())
{
if( obj.Var == 0) count_0 ++;
else if( obj.Var == 1) count_1 ++;
else if( obj.Var == 2) count_2 ++;
else if( obj.Var == 3) count_3 ++;
else if( obj.Var == 4) count_4 ++;
else if( obj.Var == 5) count_5 ++;
else if( obj.Var == 6) count_6 ++;
else if( obj.Var == 7) count_7 ++;
RESULTS:
count_0 = 2450 , count_1 = 2420, count_2 = 1114, count_3 = 1071, count_4 = 871,
count_5 = 812, count_6 = 621, count_7= 641
count_0_1 = 4870 ;count_2_7 = 5130
EXAMPLE:
class Dist{
rand integer Var;
constraint range { Var dist { {0,1} :/ 50 , {2,7} :/ 50 }; }
}
program Dist_p{
Dist obj;
integer count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7;
integer count_0_1 ,count_2_7 ;
obj=new();
count_0 = 0;count_1 = 0;count_2 = 0;count_3 = 0;
count_4 = 0;count_5 = 0;count_6 = 0;count_7 = 0;
count_0_1 = 0;count_2_7 = 0;
for(int i=0; i< 10000; i++)
if( obj.randomize())
{
if( obj.Var == 0) count_0 ++;
else if( obj.Var == 1) count_1 ++;
else if( obj.Var == 2) count_2 ++;
else if( obj.Var == 3) count_3 ++;
else if( obj.Var == 4) count_4 ++;
else if( obj.Var == 5) count_5 ++;
else if( obj.Var == 6) count_6 ++;
else if( obj.Var == 7) count_7 ++;
printf(" count_0 = %0d , count_1 = %0d, count_2 = %0d, count_3 = %0d, count_4 =
%0d, count_5 = %0d, count_6 = %0d, count_7= %0d
",count_0, count_1, count_2, count_3, count_4, count_5, count_6, count_7);
printf(" count_0_1 = %0d ;count_2_7 = %0d ",count_0_1,count_2_7);
}
RESULTS:
count_0 = 1245 , count_1 = 1242, count_2 = 1211, count_3 = 1271, count_4 = 1287,
count_5 = 1212, count_6 = 1221, count_7= 1241
count_0_1 = 2487 ;count_2_7 = 7513
Implication
rand bit a;
rand bit [3:0] b;
constraint c { (a == 0) -> (b == 1); }
EXAMPLE:
class impli{
rand bit Var;
rand bit [3:0] b;
constraint c { (Var == 0) => (b == 1); }
}
program impli_p{
impli obj;
integer count_0 ,count_1,i ;
obj=new();
count_0 = 0;count_1 = 0;
for(i=0; i< 10000; i++)
{
obj = new();
if( obj.randomize())
{
if( obj.Var == 0 ) count_0 ++;
else if( obj.Var == 1 ) count_1 ++;
}}
printf(" count_0 = %0d;count_1 = %0d;",count_0 ,count_1);
}
RESULTS:
If..Else
EXAMPLE:
class if_else{
rand bit a;
rand bit [3:0] b;
constraint c { if(a == 0) (b == 1); }
}
program if_else_p{
if_else obj;
integer count_0 ,count_1 ;
obj=new();
count_0 = 0;count_1 = 0;
for(int i=0; i< 10000; i++)
{
obj = new();
if( obj.randomize())
{
if( obj.Var == 0 ) count_0 ++;
else if( obj.Var == 1 ) count_1 ++;
}}
printf(" count_0 = %0d;count_1 = %0d;",count_0 ,count_1);
}
RESULTS
Iterative
EXAMPLE:
class Eth_pkt{
rand byte Payload[*] ;
constraint size_c { Payload.size() inside {[46:1500]}; }
constraint element_c { foreach ( Payload[ i ] ) Payload[ i ] inside {[50:100]}; }
}
program iterative{
Eth_pkt obj;
obj = new();
for(int i=0;i< 10000;i++)
{
if(obj.randomize())
printf(" RANDOMIZATION DONE ");
}}
Search ✔
Too many explicit variable ordering may lead to circular dependency.The LRM says
that "Circular dependencies created by the implicit variable ordering shall result in an
error." and "circular dependency is not allowed".
But it does not put restriction on what to do if a explicit circular dependency
exists.Check with your tool,if explicit Circular dependency is existing,it may report
warning,it may fail solver or proceed by just ignoring the order.
EXAMPLE:
program Cir_Dip_p{
class Cir_Dep;
rand integer a,b,c;
Cir_Dip obj=new();
void = obj.randomize();
}
Search ✔
program main{
aop obj;
obj = new();
obj.disp();
}
RESULTS
eaop class
aop class
extends eaop (aop){
after task disp(){
printf("eaop class ");
}
program main{
aop obj;
obj = new();
obj.disp();
}
RESULTS
aop class
eaop class
Search ✔
Specman E
Interview Questions Object_print
The entire object instance hierarchy can be sent to stdout or to a specified file using
the object_print() method. As the deep print routine recurses down the object
instance hierarchy, object members and array elements are indented as they are
printed. All the super object members are displayed with the same indentation.
EXAMPLE :object_print
#include <vera_defines.vrh>
enum colors {red, green, black, white};
class embed{
integer i;
colors col;
reg[3:0] bits_mem;
string str_mem;
}
class simple{
integer a,b,c,d; // integers
colors col; // enum
reg[3:0] abc; // bit vector
embed e;
string str; // string_var
}
program main{
simple abc = new;
abc.e = new;
abc.a = 123;
abc.b = 111111111;
abc.d = 12345;
abc.col = red;
abc.abc[3:0] = 4´b1100;
abc.object_print();
}
RESULTS
a : dec: 123
b : dec: 111111111
c:X
d : dec: 12345
col : ENUM:red
abc : hex: c
e : OBJECT of CLASS embed
i:X
col : ENUM:X
bits_mem : bin: xxxx
str_mem : NULL
str : NULL
EXAMPLE : object_compare()
class MyClass
{integer A;
}
program object_compare_ex
{
MyClass object1, object2;
object1 = new();
object2 = object1.object_copy();
if(!object1.object_compare(object2) )
error("Object compare failed\n");
else
printf("Objects are the same\n");
}
RESULTS
EXAMPLE : object_copy()
MyClass src_obj, dest_obj;
src_obj = new();
dest_obj = src_obj.object_copy();// dest_obj and
// src_object are now duplicates
if (dest_obj == null) error("Copy failed\n");
else printf(" Copy done ");
RESULTS
Copy done
EXAMPLE :
class Serial_Data_Type {
static integer total_inst_count = 0;
packed {
rand reg [19:0] bit_data;
string comment;
}
task new() {
integer status;
status = this.randomize();
if ( !status )
error ("Randomize failed!\n");
comment = psprintf("comment_%0d", total_inst_count) ;
printf("inst = %-9d , data = %-25b comment =
%0s\n",total_inst_count, bit_data, comment );
total_inst_count++ ;
} // new
}
program packed_test {
Serial_Data_Type sdata_arr[5];
reg data_stream[]; // does not have to be byte stream
integer i, offset, left, right;
printf ("\n\nPacking data ...........\n");
offset = 0; left = 0; right = 0;
for ( i = 0; i < 5; i++ ) {
sdata_arr[i] = new();
void = sdata_arr[i].pack (data_stream, offset, left,right );
} // for
printf ("\n\nUnpacking data in order .....\n");
offset = 0; left = 0; right = 0;
for ( i = 0; i < 5; i++ ) {
void = sdata_arr[i].unpack ( data_stream, offset,left, right );
printf("inst = %-9d , data = %-25b comment =
%0s\n", i, sdata_arr[i].bit_data, sdata_arr[i].comment );
} // for
} // packed_test
RESULTS
Search ✔
RESULTS
String length = 16
The fourth character is the letter s.
Lower case string is this is a string
Upper case string is THIS IS A STRING
Str after put 1 at 0 loc is 1his is a string
Comparing str and str_1 resulted 0
Substring from 2 to 4 of str is is
searching for 'is a' in str resulted in 5
matching for 'is' in str resulted in 1
After execute string.atoi method = 123
Search ✔
RESULTS
size of queue 0
pop_back is 10
pop_front is 2
size of queue 3
pop_back is 3
pop_back is 6
Search ✔
Blocking drives suspend Vera execution until the statement completes. Note that the
clock edge (NHOLD or PHOLD) that the drive signal is associated with is used for
Specman E counting synchronized edges during suspension. Once the statement completes, Vera
Interview Questions execution resumes.Non-blocking drives schedule the drive at a future synchronized
edge and Vera execution continues. When the specified synchronized edge occurs, the
drive is executed.
Search ✔
Cross Coverage :
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
Packet format:
OpenVera
Constructs Packet contains Header, data and frame check sequence. Packet width is 8 bits and
Switch TB the length of the packet can be between 4 bytes to 259 bytes.
FCS: This field contains the security check of the packet. It is calculated over the
header and data.
Configuration:
Dut has four output ports. These output ports have to be configure to a address. Dut
matches the DA field of the packet with this configured port address and sends the
packet on to that port. To configure the dut, a memory interface is provided. The
address of the ports should be unique. It is 8 bits wide. Memory address (0,1,2,3)
contains the address of port(0,1,2,4) respectively.
Interface Specification:
The dut has one input Interface, from where the packet enters the dut and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured.
Memory Interface:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively. If the DA feild in the packet matches with
the confugured address of any port ,then the packet comes out of that port.
Input Interface:
The status signal has to be high when data is when packet is sent on to the dut it has
to become low after sending last byte of the packet.
When the dut is busy, and if it is not in a position to accept any more data, it will
assert busy signal. Data which is sent during this busy signal is lost if input is driving
when busy is high
Output Interface:
There are 4 ports, each having data, ready and read signals.
When the data is ready to be sent out from the port, dut makes the ready signal high
indicating that data is ready to be sent.
If the read signal is made high when ready is high, then the data comes out of the
data signal.
Search ✔
end
endmodule //fifo
always@(negedge reset)
begin
error = 1'b0;
data_out = 8'b0000_0000;
addr = 8'b00000000;
write_enb_r = 3'b000;
fsm_write_enb = 1'b0;
state_r = 4'b0000;
state = 4'b0000;
parity = 8'b0000_0000;
parity_delayed = 8'b0000_0000;
sus_data_in = 1'b0;
end
assign busy = sus_data_in;
always @(data_status) begin : addr_mux
if (data_status == 1'b1) begin
case (data_in)
mem0 : begin
write_enb_r[0] = 1'b1;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem1 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b1;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem2 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b1;
write_enb_r[3] = 1'b0;
end
mem3 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b1;
end
default :write_enb_r = 3'b000;
endcase
// $display(" data_inii %d ,mem0 %d ,mem1 %d ,mem2 %d
mem3",data_in,mem0,mem1,mem2,mem3);
end //if
end //addr_mux;
always @(posedge clk) begin : fsm_state
state_r <= state;
end //fsm_state;
assign write_enb[0] = write_enb_r[0] & fsm_write_enb;
assign write_enb[1] = write_enb_r[1] & fsm_write_enb;
assign write_enb[2] = write_enb_r[2] & fsm_write_enb;
assign write_enb[3] = write_enb_r[3] & fsm_write_enb;
endmodule //port_fsm
module switch (clk,
reset,
data_status,
data,
port0,
port1,
port2,
port3,
ready_0,
ready_1,
ready_2,
ready_3,
read_0,
read_1,
read_2,
read_3,
mem_en,
mem_rd_wr,
mem_add,
mem_data);
input clk;
input reset;
input data_status;
input [7:0] data;
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
wire [7:0] data_out_0;
wire [7:0] data_out_1;
wire [7:0] data_out_2;
wire [7:0] data_out_3;
wire ll0;
wire ll1;
wire ll2;
wire ll3;
wire empty_0;
wire empty_1;
wire empty_2;
wire empty_3;
wire ffee;
wire ffee0;
wire ffee1;
wire ffee2;
wire ffee3;
wire ld0;
wire ld1;
wire ld2;
wire ld3;
wire hold;
wire [3:0] write_enb;
wire [7:0] data_out_fsm;
wire [7:0] addr;
reg [7:0]mem[3:0];
wire reset;
fifo queue_0 (.clk (clk),
.reset (reset),
.write_enb (write_enb[0]),
.read (read_0),
.data_in (data_out_fsm),
.data_out (data_out_0),
.empty (empty_0),
.full (ll0));
.read (read_2),
.data_in (data_out_fsm),
.data_out (data_out_2),
.empty (empty_2),
.full (ll2));
always@(posedge clk)
begin
if(mem_en)
if(mem_rd_wr)
begin
mem[mem_add]=mem_data;
///$display("%d %d %d %d %d",mem_add,mem[0],mem[1],mem[2],mem[3]);
end
end
endmodule //router
Search ✔
Verilog
Top Module:
Verification
Verilog Switch TB Top module contains the instance of the Dut and verification environment.
It also has the clock generator. For more information about clock generation, go
Basic Constructs through TB_CONCEPTS in this website.
Creat an Interface and make an instance of the interface file.
Connect the interface instance to dut.
OpenVera Creat an instance of the program block. Program block containg all the verification
Constructs component.
Switch TB CODE: top
RVM Switch TB module top();
//Declare clock signal
RVM Ethernet sample reg clock;
//Signals for Assertion and to view the class proprties in Waveform viewer
reg pkt_status;
Specman E wire data_status;
wire [7:0] data_in;
Interview Questions wire [3:0][7:0] data_out;
wire [3:0] ready;
wire [3:0] read;
wire [7:0] mem_data;
wire [1:0] mem_add;
wire reset;
wire mem_en;
wire mem_rd_wr;
reg SystemClock ;
assign SystemClock = clock;
tb vshell ( .SystemClock (SystemClock),
.\intf.clk (clock),
.\intf.data_status (data_status),
.\intf.data_in (data_in),
.\intf.data_out_0 (data_out[0]),
.\intf.data_out_1 (data_out[1]),
.\intf.data_out_2 (data_out[2]),
.\intf.data_out_3 (data_out[3]),
.\intf.ready_0 (ready[0]),
.\intf.ready_1 (ready[1]),
.\intf.ready_2 (ready[2]),
.\intf.ready_3 (ready[3]),
.\intf.read_0 (read[0]),
.\intf.read_1 (read[1]),
.\intf.read_2 (read[2]),
.\intf.read_3 (read[3]),
.\intf.mem_data (mem_data),
.\intf.mem_add (mem_add),
.\intf.reset (reset),
.\intf.mem_en (mem_en),
.\intf.mem_rd_wr (mem_rd_wr)
);
switch switch1 (.clk (clock),
.reset (reset),
.data_status (data_status),
.data (data_in),
.port0 (data_out[0]),
.port1 (data_out[1]),
.port2 (data_out[2]),
.port3 (data_out[3]),
.ready_0 (ready[0]),
.ready_1 (ready[1]),
.ready_2 (ready[2]),
.ready_3 (ready[3]),
.read_0 (read[0]),
.read_1 (read[1]),
.read_2 (read[2]),
.read_3 (read[3]),
.mem_en (mem_en),
.mem_rd_wr (mem_rd_wr),
.mem_add (mem_add),
.mem_data (mem_data));
initial begin
//If you are using always for clock generation, take care not have edge on time 0
clock = 0;
forever begin
#5 clock = !clock;
end
end
endmodule //top
Search ✔
bind rec_ports rec_0 {
OpenVera data_out intf.data_out_0;
Constructs ready intf.ready_0;
Switch TB read intf.read_0;
}
RVM Switch TB
RVM Ethernet sample bind rec_ports rec_1 {
data_out intf.data_out_1;
ready intf.ready_1;
read intf.read_1;
Specman E }
Interview Questions
bind rec_ports rec_2 {
data_out intf.data_out_2;
ready intf.ready_2;
read intf.read_2;
}
bind rec_ports rec_3 {
data_out intf.data_out_3;
ready intf.ready_3;
read intf.read_3;
Search ✔
task pre_randomize(){
this.mem[0]=cfg.mem[0];
this.mem[1]=cfg.mem[1];
this.mem[2]=cfg.mem[2];
this.mem[3]=cfg.mem[3];
//////////////////////////////////////////////////////////////
// parity_calc()
//
// Return the byte resulting from xor-ing among all data bytes
// and the byte resulting from concatenating addr and len
//////////////////////////////////////////////////////////////
function bit [7:0] parity_cal(){
integer i;
bit [7:0] result ;
result = 8'hff;
result = result ^ da;
result = result ^ sa;
result = result ^ len;
data = new [len];
data[0] = uid ;
result = result ^ data[0];
for (i = 1;i<len;i++)
{
data[i] = random();
result = result ^ data[i];
}
parity_cal = result;
}
Search ✔
Specman E
Interview Questions
Search ✔
Search ✔
//Define task to generate the packet and call the drive task
Verilog task gen_and_drive(){
Verification integer l;
l = 0;
Verilog Switch TB printf("[DRIVER] NUMBER PACKETS %d\n ",gen_rator.no_of_pkts);
Basic Constructs repeat (gen_rator.no_of_pkts)
{
void = mailbox_get(WAIT, gen,cur_packet,CHECK);
@(posedge intf.clk);
OpenVera drive_packet(cur_packet);
Constructs }
Switch TB }
RVM Switch TB
RVM Ethernet sample
task drive_packet(packet pkt) {
bit [7:0] pkt_packed[*];
integer i;
Specman E printf("[DRIVER] Starting to drive packet to intf %0d len %0d \n",pkt.da,pkt.len);
Interview Questions
//Do packing of generated packet
pkt_packed = new[pkt.len + 4];
pkt_packed[0] = pkt.da;
pkt_packed[1] = pkt.sa;
pkt_packed[2] = pkt.len;
foreach(pkt.data,i)
pkt_packed[i+3]=pkt.data[i];
pkt_packed[pkt.len+3]=pkt.parity;
@(posedge intf.clk);
foreach(pkt_packed,i)
printf("[PKT drvr] pkt %h at %d\n",pkt_packed[i],i);
// Byte by byte packed data on to DUV
for (i=0;i<pkt.len+3;i++)
{
@ (posedge intf.clk);
intf.data_status = 1 ;
intf.data_in[7:0] = pkt_packed[i];
printf("[PKT drved] pkt %h at %d\n",pkt_packed[i],i);
}
@ (posedge intf.clk);
intf.data_status = 0 ;
intf.data_in[7:0] = pkt.parity ;
//Add the sent packet to scoreboard expected packet queue
score_board.add_exp_packet(pkt);
@(posedge intf.clk);
}
Search ✔
@(posedge intf.clk);
Specman E received_bytes.push_back(ports.$data_out);
Interview Questions printf("[RECIVER] chanel valid 0 data %x num %d\n
",ports.$data_out,received_bytes.size());
}
ports.$read = 0;
repeat (1)@(posedge intf.clk);
rcv_packet=new(id,cfg);
id++;
printf("[RECIVER]pkt id is %d size is %d\n",id,received_bytes.size());
//void = received_bytes.pop_front();
//unpack the recived data
rcv_packet.byte_unpack(received_bytes);
//as queues are used,delete it
received_bytes.delete();
Search ✔
trigger(err);
}
Search ✔
cfg = new();
Verilog gen_rator= new(cfg);
Verification driver_obj = new();
score_board = new();
Verilog Switch TB
Basic Constructs receiver_obj_0 = new(cfg,rec_0);
receiver_obj_1 = new(cfg,rec_1);
receiver_obj_2 = new(cfg,rec_2);
receiver_obj_3 = new(cfg,rec_3);
OpenVera
Constructs no_of_errors = 0;
Switch TB // Reset the dut
@(posedge intf.clk);
RVM Switch TB intf.reset = 1;
RVM Ethernet sample @(posedge intf.clk);
intf.reset =0;
delay(100);
Specman E //// Configure the dut.
Interview Questions cfg.drive_add();
delay(100);
//// Generate the packets
gen_rator.gen_pkts();
fork
// Forking error counter task
error_counter();
// Fork task to Drive the packets
driver_obj.gen_and_drive();
//// Fork task to collect packets
receiver_obj_0.collect_packets();
receiver_obj_1.collect_packets();
receiver_obj_2.collect_packets();
receiver_obj_3.collect_packets();
join none
delay(10000);
printf("\n ***** END OF SIMULATION **** \n");
}
if(no_of_errors > 0)
printf("\n************TEST FAILED with %d ERRORS************\n",no_of_errors);
else
printf("\n************TEST PASSED************\n");
}
task error_counter(){
while(1){
sync(ALL,err);
@(posedge intf.clk);
no_of_errors++;
}
}
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Packet format:
Packet contains Header, data and frame check sequence. Packet width is 8 bits and
the length of the packet can be between 4 bytes to 259 bytes.
Packet header:
Packet header contains three fields DA, SA and length.
DA: Destination address of the packet. It is 8 bits. The switch drives the packet to
respective ports based on this destination address of the packets.
SA: Source address of the packet from where it originate.
Length: This is the length of the data. It can be from 0 to 255.
FCS: This field contains the security check of the packet. It is calculated over the
header and data.
Configuration:
Dut has four output ports. These output ports have to be configure to a address. Dut
matches the DA field of the packet with this configured port address and sends the
packet on to that port. To configure the dut, a memory interface is provided. The
address of the ports should be unique. It is 8 bits wide. Memory address (0,1,2,3)
contains the address of port(0,1,2,4) respectively.
Interface Specification:
The dut has one input Interface, from where the packet enters the dut and 4 output
interfaces from where the packet comes out and one memory interface, through the
port address can be configured.
Memory Interface:
Through memory interfaced output port address are configured. It accepts 8 bit data
to be written to memory. It has 8 bit address inputs. Address 0,1,2,3 contains the
address of the port 0,1,2,3 respectively. If the DA feild in the packet matches with
the confugured address of any port ,then the packet comes out of that port.
Input Interface:
The status signal has to be high when data is when packet is sent on to the dut it has
to become low after sending last byte of the packet. 2 clocks gap should be
maintained between packets.
Output Interface:
There are 4 ports, each having data, ready and read signals.
When the data is ready to be sent out from the port, dut makes the ready signal high
indicating that data is ready to be sent.
If the read signal is made high when ready is high, then the data comes out of the
data signal.
Search ✔
end
end
endmodule //fifo
always@(negedge reset)
begin
error = 1'b0;
data_out = 8'b0000_0000;
addr = 8'b00000000;
write_enb_r = 3'b000;
fsm_write_enb = 1'b0;
state_r = 4'b0000;
state = 4'b0000;
parity = 8'b0000_0000;
parity_delayed = 8'b0000_0000;
sus_data_in = 1'b0;
end
assign busy = sus_data_in;
always @(data_status) begin : addr_mux
if (data_status == 1'b1) begin
case (data_in)
mem0 : begin
write_enb_r[0] = 1'b1;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem1 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b1;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b0;
end
mem2 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b1;
write_enb_r[3] = 1'b0;
end
mem3 : begin
write_enb_r[0] = 1'b0;
write_enb_r[1] = 1'b0;
write_enb_r[2] = 1'b0;
write_enb_r[3] = 1'b1;
end
default :write_enb_r = 3'b000;
endcase
// $display(" data_inii %d ,mem0 %d ,mem1 %d ,mem2 %d
mem3",data_in,mem0,mem1,mem2,mem3);
end //if
end //addr_mux;
always @(posedge clk) begin : fsm_state
state_r <= state;
end //fsm_state;
end //if
sus_data_in = 1'b0;
if ((data_status == 1'b1) &&
(hold == 1'b0)) begin
data_out = data_in;
fsm_write_enb = 1'b1;
end
else if ((data_status == 1'b0) &&
(hold == 1'b0)) begin
data_out = data_in;
fsm_write_enb = 1'b1;
end
else begin
fsm_write_enb = 1'b0;
end //if
end //end of case DATA_LOAD
HOLD_STATE : begin
if (hold == 1'b1) begin
state = HOLD_STATE;
end
else if ((hold == 1'b0) && (data_status == 1'b0)) begin
state = PARITY_LOAD;
end
else begin
state = DATA_LOAD;
end //if
if (hold == 1'b1) begin
sus_data_in = 1'b1;
fsm_write_enb = 1'b0;
end
else begin
fsm_write_enb = 1'b1;
data_out = data_in;
end //if
end //end of case HOLD_STATE
BUSY_STATE : begin
if (ffee == 1'b0) begin
state = BUSY_STATE;
end
else begin
state = DATA_LOAD;
end //if
if (ffee == 1'b0) begin
sus_data_in = 1'b1;
end
else begin
addr = data_in; // hans
data_out = data_in;
fsm_write_enb = 1'b1;
end //if
end //end of case BUSY_STATE
endcase
end //fsm_core
assign write_enb[0] = write_enb_r[0] & fsm_write_enb;
assign write_enb[1] = write_enb_r[1] & fsm_write_enb;
assign write_enb[2] = write_enb_r[2] & fsm_write_enb;
assign write_enb[3] = write_enb_r[3] & fsm_write_enb;
endmodule //port_fsm
module switch (clk,
reset,
data_status,
data,
port0,
port1,
port2,
port3,
ready_0,
ready_1,
ready_2,
ready_3,
read_0,
read_1,
read_2,
read_3,
mem_en,
mem_rd_wr,
mem_add,
mem_data);
input clk;
input reset;
input data_status;
input [7:0] data;
input mem_en;
input mem_rd_wr;
input [1:0] mem_add;
input [7:0] mem_data;
output [7:0] port0;
output [7:0] port1;
output [7:0] port2;
output [7:0] port3;
output ready_0;
output ready_1;
output ready_2;
output ready_3;
input read_0;
input read_1;
input read_2;
input read_3;
wire [7:0] data_out_0;
wire [7:0] data_out_1;
wire [7:0] data_out_2;
wire [7:0] data_out_3;
wire ll0;
wire ll1;
wire ll2;
wire ll3;
wire empty_0;
wire empty_1;
wire empty_2;
wire empty_3;
wire ffee;
wire ffee0;
wire ffee1;
wire ffee2;
wire ffee3;
wire ld0;
wire ld1;
wire ld2;
wire ld3;
wire hold;
wire [3:0] write_enb;
wire [7:0] data_out_fsm;
wire [7:0] addr;
reg [7:0]mem[3:0];
wire reset;
fifo queue_0 (.clk (clk),
.reset (reset),
.write_enb (write_enb[0]),
.read (read_0),
.data_in (data_out_fsm),
.data_out (data_out_0),
.empty (empty_0),
.full (ll0));
.write_enb (write_enb[2]),
.read (read_2),
.data_in (data_out_fsm),
.data_out (data_out_2),
.empty (empty_2),
.full (ll2));
always@(posedge clk)
begin
if(mem_en)
if(mem_rd_wr)
begin
mem[mem_add]=mem_data;
///$display("%d %d %d %d %d",mem_add,mem[0],mem[1],mem[2],mem[3]);
end
end
endmodule //router
Search ✔
CODE: top.v
module top();
Verilog
//Declare clock signal
Verification reg clock;
Verilog Switch TB //Signals for Assertion and to view the class proprties in Waveform viewer
wire data_status;
Basic Constructs wire [7:0] data_in;
wire [7:0] data_out[0:3];
wire [3:0] ready;
OpenVera wire [3:0] read;
Constructs wire [7:0] mem_data;
wire [1:0] mem_add;
Switch TB wire reset;
RVM Switch TB wire mem_en;
wire mem_rd_wr;
RVM Ethernet sample
wire SystemClock ;
assign SystemClock = clock;
Specman E main tb ( .SystemClock (SystemClock),
.\intf.clk (clock),
Interview Questions .\intf.data_status (data_status),
.\intf.data_in (data_in),
.\intf.data_out_0 (data_out[0]),
.\intf.data_out_1 (data_out[1]),
.\intf.data_out_2 (data_out[2]),
.\intf.data_out_3 (data_out[3]),
.\intf.ready_0 (ready[0]),
.\intf.ready_1 (ready[1]),
.\intf.ready_2 (ready[2]),
.\intf.ready_3 (ready[3]),
.\intf.read_0 (read[0]),
.\intf.read_1 (read[1]),
.\intf.read_2 (read[2]),
.\intf.read_3 (read[3]),
.\intf.mem_data (mem_data),
.\intf.mem_add (mem_add),
.\intf.reset (reset),
.\intf.mem_en (mem_en),
.\intf.mem_rd_wr (mem_rd_wr)
);
switch switch1 (.clk (clock),
.reset (reset),
.data_status (data_status),
.data (data_in),
.port0 (data_out[0]),
.port1 (data_out[1]),
.port2 (data_out[2]),
.port3 (data_out[3]),
.ready_0 (ready[0]),
.ready_1 (ready[1]),
.ready_2 (ready[2]),
.ready_3 (ready[3]),
.read_0 (read[0]),
.read_1 (read[1]),
.read_2 (read[2]),
.read_3 (read[3]),
.mem_en (mem_en),
.mem_rd_wr (mem_rd_wr),
.mem_add (mem_add),
.mem_data (mem_data));
initial begin
clock = 0;
forever begin
#5 clock = !clock;
end
end
endmodule //top
Search ✔
bind rec_ports rec_0 {
OpenVera data_out intf.data_out_0;
Constructs ready intf.ready_0;
Switch TB read intf.read_0;
}
RVM Switch TB
RVM Ethernet sample bind rec_ports rec_1 {
data_out intf.data_out_1;
ready intf.ready_1;
read intf.read_1;
Specman E }
Interview Questions
bind rec_ports rec_2 {
data_out intf.data_out_2;
ready intf.ready_2;
read intf.read_2;
}
bind rec_ports rec_3 {
data_out intf.data_out_3;
ready intf.ready_3;
read intf.read_3;
Search ✔
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
//All simulation log output shall be done through the message service.
Specman E
Interview Questions rvm_log log;
Configuration cfg;
packet pkt;
packet_atomic_gen gen;
packet_channel gen2drv_chan;
packet_channel rcv2sb_chan;
packet_channel drv2sb_chan;
drvr_xtor drvr;
rcvr_xtor rcvr_0;
rcvr_xtor rcvr_1;
rcvr_xtor rcvr_2;
rcvr_xtor rcvr_3;
scoreboard sb;
task new();
virtual task gen_cfg();
virtual task build();
virtual task reset_dut_t();
virtual task cfg_dut_t();
virtual task start_t();
virtual task wait_for_end_t();
virtual task stop_t();
virtual task cleanup_t();
virtual task report();
}
task Environment::new(){
super.new("Environment");
this.log = new("ENV_LOG","0");
this.cfg = new();
rvm_note(this.log," ENV CREATED \n");
}
task Environment::gen_cfg(){
super.gen_cfg();
rvm_note(this.log," Starting... Gen_cfg \n");
if (!cfg.randomize())
rvm_fatal(this.log, "Configuration Randomization Failed!\n");
cfg.display();
}
task Environment::build() {
super.build();
rvm_note(this.log," Starting... build \n");
pkt = new();
pkt.do_cfg(cfg);
gen = new("Generator","0");
gen.stop_after_n_insts = 20;
gen2drv_chan = new("gen2drv","0");
rcv2sb_chan = new("rcv2sb","chan",10);
drv2sb_chan = new("drv2sb","chan",10);
gen.out_chan = this.gen2drv_chan;
drvr = new("driver",0,gen2drv_chan,drv2sb_chan);
rcvr_0 = new("reciver_0",0,rec_0,rcv2sb_chan);
rcvr_1 = new("reciver_1",1,rec_1,rcv2sb_chan);
rcvr_2 = new("reciver_2",2,rec_2,rcv2sb_chan);
rcvr_3 = new("reciver_3",3,rec_3,rcv2sb_chan);
sb = new(rcv2sb_chan,drv2sb_chan);
}
//Blocking methods shall have a name that ends with the "_t" suffix.
task Environment::reset_dut_t(){
super.reset_dut_t();
rvm_note(this.log," Starting... reset_dut \n");
@(posedge intf.clk);
intf.data_status <= 0;
intf.data_in <= 0;
intf.read_0 <= 0;
intf.read_1 <= 0;
intf.read_2 <= 0;
intf.read_3 <= 0;
intf.mem_data <= 0;
intf.mem_add <= 0;
intf.reset <= 0;
intf.mem_en <= 0;
intf.mem_rd_wr <= 0;
@(posedge intf.clk);
intf.reset <= 1;
@(posedge intf.clk);
intf.reset <= 0;
@(posedge intf.clk);
@(posedge intf.clk);
rvm_note(this.log," Ending... reset_dut \n");
}
task Environment::cfg_dut_t(){
integer i;
super.cfg_dut_t();
rvm_note(this.log," Starting... cfg_dut \n");
for(i = 0;i<4 ;i++)
{
intf.mem_en <= 1;
@(posedge intf.clk);
intf.mem_rd_wr <= 1;
@(posedge intf.clk);
intf.mem_add <= i;
intf.mem_data <= cfg.da_port[i];
}
@(posedge intf.clk);
intf.mem_en <= 0;
intf.mem_rd_wr <= 0;
intf.mem_add <= 0;
intf.mem_data <= 0;
task Environment::start_t() {
super.start_t();
rvm_note(this.log," Starting... start \n");
gen.start_xactor();
drvr.start_xactor();
rcvr_0.start_xactor();
rcvr_1.start_xactor();
rcvr_2.start_xactor();
rcvr_3.start_xactor();
sb.start_xactor();
}
task Environment::wait_for_end_t() {
super.wait_for_end_t();
rvm_note(this.log," Starting... wait_for_end \n");
fork//watchdog
{
void = gen.notify.wait_for_t(gen.DONE);
rvm_note(this.log," DONE:: packet_atomic_gen \n");
repeat(100) @(posedge intf.clk);
rvm_error(this.log," Watchdog timeout occured \n");
}
{
while(sb.no_rcv_pkt != 20) @(posedge intf.clk);
rvm_note(this.log," DONE:: total number of sent pkts are receved \n");
}
join any
rvm_note(this.log," Ending ... wait_for_end \n");
task Environment::stop_t() {
super.stop_t();
rvm_note(this.log," Starting... stop \n");
this.drvr.stop_xactor();
this.rcvr_0.stop_xactor();
this.rcvr_1.stop_xactor();
this.rcvr_2.stop_xactor();
this.rcvr_3.stop_xactor();
this.sb.stop_xactor();
rvm_note(this.log," Ending ... stop \n");
task Environment::cleanup_t() {
super.cleanup_t();
rvm_note(this.log," Starting... cleanup \n");
}
task Environment::report() {
rvm_note(this.log," Starting... report \n");
super.report();
rvm_note(this.log," Ending... report \n");
}
`endif
Search ✔
task packet::new(){
super.new(this.log);
}
task packet::do_cfg(Configuration cfg){
this.mem[0]= cfg.da_port[0];
this.mem[1]= cfg.da_port[1];
this.mem[2]= cfg.da_port[2];
this.mem[3]= cfg.da_port[3];
msg = psprintf(" packet new %x %x %x %x",mem[0],mem[1],mem[2],mem[3]);
rvm_note(this.log,msg);
}
function string packet::psdisplay(string prefix = ""){
integer i;
sprintf(psdisplay,"%s packet
#%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.object_id);
sprintf(psdisplay,"%s%s da:0x%h sa:0x%h len:0x%h
\n", psdisplay, prefix,this.da,this.sa,this.len);
sprintf(psdisplay, "%s%s data:", psdisplay, prefix);
for (i = 0; i < this.len - 1; i++) sprintf(psdisplay,"%s data[%0d]
0x%h", psdisplay,i, data[i]);
}
function rvm_data packet::copy(rvm_data to = null){
packet cpy;
// Copying to a new instance?
if (to == null)
cpy = new;
else
// Copying to an existing instance. Correct type?
if (!cast_assign(cpy, to,CHECK))
{
rvm_fatal(this.log, "Attempting to copy to a non packet instance");
copy = null;
return;
}
super.copy_data(cpy);
cpy.da = this.da;
cpy.sa = this.sa;
cpy.len = this.len;
cpy.data = new[this.len];
foreach(cpy.data,i)
cpy.data[i] = this.data[i];
copy = cpy;
}
//unpacking function for converting recived data to class properties
function integer packet::byte_unpack(bit [7:0] bytes[*],integer offset
,integer kind){
sprintf(msg," bytes size %d",bytes.size());
da = bytes[1];
sa = bytes[2];
len = bytes[3];
sprintf(msg,"packet
#%0d.%0d.%0d\n", this.stream_id, this.scenario_id, this.object_id);
sprintf(msg,"da:0x%h sa:0x%h len:0x%h \n", this.da,this.sa,this.len);
rvm_note(this.log,msg);
data = new [len - 4];
parity = bytes[bytes.size()-1];
foreach (data,i) data[i] = bytes[i+4];
}
function bit[7:0] packet::parity_cal(){
integer i;
bit[7:0] result ;
result = result ^ this.da;
result = result ^ this.sa;
result = result ^ this.len;
for (i = 0;i<this.len;i++)
{
result = result ^ this.data[i];
}
parity_cal = result;
}
//post randomize fun to cal parity
task packet::post_randomize(){
parity = parity ^ parity_cal();
sprintf(msg," %x %x %x %x",mem[0],mem[1],mem[2],mem[3]);
rvm_note(this.log,msg);
}
{
diff = psprintf("Different LEN values: %b != %b", this.len, cmp.len);
compare = 0;
return;
}
foreach(data,i)
if (this.data[i] != cmp.data[i])
{
diff = psprintf("Different data[%0d] values: 0x%h !=
0x%h",i, this.data[i], cmp.data[i]);
compare = 0;
return;
}
if (this.parity != cmp.parity)
{
diff = psprintf("Different PARITY values: %b != %b", this.parity, cmp.parity);
compare = 0;
return;
}
}
function integer packet::byte_pack(var bit [7:0] bytes[*],integer offset ,integer
kind){
byte_pack = 0;
bytes = new[this.len + 4];
bytes[0] = this.da;
bytes[1] = this.sa;
bytes[2] = this.len;
foreach(data,i)
bytes[3+i] = data[i];
bytes[this.len + 3 ] = parity;
byte_pack = this.len + 4;
}
#endif
Search ✔
task new();
task do_cfg(Configuration cfg);
virtual function string psdisplay(string prefix );
virtual function rvm_data copy(rvm_data to);
virtual function integer byte_unpack(bit [7:0] bytes[*],integer offset
= 0,integer kind = -1);
virtual function bit[7:0] parity_cal();
task packet::new(){
super.new(this.log);
}
task packet::do_cfg(Configuration cfg){
this.mem[0]= cfg.da_port[0];
this.mem[1]= cfg.da_port[1];
this.mem[2]= cfg.da_port[2];
this.mem[3]= cfg.da_port[3];
msg = psprintf(" packet new %x %x %x %x",mem[0],mem[1],mem[2],mem[3]);
rvm_note(this.log,msg);
}
function string packet::psdisplay(string prefix = ""){
integer i;
sprintf(psdisplay,"%s packet
#%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.object_id);
sprintf(psdisplay,"%s%s da:0x%h sa:0x%h len:0x%h
\n", psdisplay, prefix,this.da,this.sa,this.len);
sprintf(psdisplay, "%s%s data:", psdisplay, prefix);
for (i = 0; i < this.len - 1; i++) sprintf(psdisplay,"%s data[%0d]
0x%h", psdisplay,i, data[i]);
}
function rvm_data packet::copy(rvm_data to = null){
packet cpy;
// Copying to a new instance?
if (to == null)
cpy = new;
else
// Copying to an existing instance. Correct type?
if (!cast_assign(cpy, to,CHECK))
{
rvm_fatal(this.log, "Attempting to copy to a non packet instance");
copy = null;
return;
}
super.copy_data(cpy);
cpy.da = this.da;
cpy.sa = this.sa;
cpy.len = this.len;
cpy.data = new[this.len];
foreach(cpy.data,i)
cpy.data[i] = this.data[i];
copy = cpy;
}
//unpacking function for converting recived data to class properties
function integer packet::byte_unpack(bit [7:0] bytes[*],integer offset
,integer kind){
sprintf(msg," bytes size %d",bytes.size());
da = bytes[1];
sa = bytes[2];
len = bytes[3];
sprintf(msg,"packet
#%0d.%0d.%0d\n", this.stream_id, this.scenario_id, this.object_id);
sprintf(msg,"da:0x%h sa:0x%h len:0x%h \n", this.da,this.sa,this.len);
rvm_note(this.log,msg);
data = new [len - 4];
parity = bytes[bytes.size()-1];
foreach (data,i) data[i] = bytes[i+4];
}
function bit[7:0] packet::parity_cal(){
integer i;
bit[7:0] result ;
result = result ^ this.da;
result = result ^ this.sa;
result = result ^ this.len;
for (i = 0;i<this.len;i++)
{
result = result ^ this.data[i];
}
parity_cal = result;
}
//post randomize fun to cal parity
task packet::post_randomize(){
parity = parity ^ parity_cal();
sprintf(msg," %x %x %x %x",mem[0],mem[1],mem[2],mem[3]);
rvm_note(this.log,msg);
}
return;
}
foreach(data,i)
if (this.data[i] != cmp.data[i])
{
diff = psprintf("Different data[%0d] values: 0x%h !=
0x%h",i, this.data[i], cmp.data[i]);
compare = 0;
return;
}
if (this.parity != cmp.parity)
{
diff = psprintf("Different PARITY values: %b != %b", this.parity, cmp.parity);
compare = 0;
return;
}
}
function integer packet::byte_pack(var bit [7:0] bytes[*],integer offset ,integer
kind){
byte_pack = 0;
bytes = new[this.len + 4];
bytes[0] = this.da;
bytes[1] = this.sa;
bytes[2] = this.len;
foreach(data,i)
bytes[3+i] = data[i];
bytes[this.len + 3 ] = parity;
byte_pack = this.len + 4;
}
#endif
Search ✔
task drvr_xtor::new(string inst,integer stream_id ,
Verilog packet_channel gen2drv_chan ,
Verification packet_channel drv2sb_chan ){
super.new("driver",inst,stream_id);
Verilog Switch TB
Basic Constructs if(gen2drv_chan == null)
this.gen2drv_chan = new("gen2drv_channel","chan",10);
else
this.gen2drv_chan = gen2drv_chan;
OpenVera
Constructs if(drv2sb_chan == null)
Switch TB this.drv2sb_chan = new("drv2sb_channel","chan",10);
else
RVM Switch TB this.drv2sb_chan = drv2sb_chan;
RVM Ethernet sample
rvm_note(log,"Driver created \n");
}
Specman E //All threads shall be started in the extension of the rvm_xactor::main_t() method
Interview Questions //Extensions of the rvm_xactor::main_t() method shall fork a call to super.main_t()
task drvr_xtor::main_t(){
super.main_t();
rvm_note(this.log," STARTED main task ");
while(1){
//wait_if_stopped_or_empty(this.gen2drv_chan);
pkt = this.gen2drv_chan.get_t();
sprintf(this.msg,"pkt da %x pkt sa %x pkt len %d \n",pkt.da,pkt.sa,pkt.len);
rvm_note(this.log,msg);
if (!cast_assign(drv_pkt, pkt.copy()))
rvm_fatal(this.log, "Attempting to copy to a non Packet instance");
drive(drv_pkt);
@(posedge intf.clk);
this.drv2sb_chan.sneak(drv_pkt);
}
}
task drvr_xtor::drive(packet pkt){
bit [7:0] pack_pkt[*];
integer pkt_len,i;
pkt_len = pkt.byte_pack(pack_pkt,0,0);
sprintf(this.msg,"Packed packet length %d \n",pkt_len);
rvm_note(this.log,this.msg);
@(posedge intf.clk);
for (i=0;i< pkt_len - 1;i++)
{
@(posedge intf.clk);
intf.data_status <= 1 ;
intf.data_in <= pack_pkt[i];
}
@(posedge intf.clk);
intf.data_status <= 0 ;
intf.data_in <= 0;
@(posedge intf.clk);
}
#endif
Search ✔
task rcvr_xtor::main_t(){
OpenVera bit [7:0] received_bytes[*] ;
Constructs super.main_t();
Switch TB rvm_note(this.log," STARTED main task ");
while(1){
RVM Switch TB @(posedge port_.$ready);
RVM Ethernet sample while (port_.$ready) {
port_.$read <= 1;
@(posedge intf.clk);
received_bytes = new[received_bytes.size() + 1] (received_bytes);
Specman E received_bytes[received_bytes.size()-1] = port_.$data_out;
Interview Questions }
port_.$read <= 0;
void = pkt.byte_unpack(received_bytes);
received_bytes.delete();
rcv_pkt = new pkt;
rcv2sb_chan.put_t(rcv_pkt);
}
}
#endif
Search ✔
`endif
Search ✔
TUTORIALS
About the author:
SystemVerilog UVM/OVM Killing Sequences on Sequencer Abruptly
Verification Vishnu Prasanth
is ovm/uvm expert. He is
Constructs Sometimes you may need to drive input until you see come condition or some timer currently working with
Interface expires. Once you meet that condition, you need to stop generating stimulus. The Vitesse, Hyderabad,
code for this scenario look like below India.
OOPS
Randomization //Test Connect to Vishnu @
Functional Coverage
begin
fork
Assertion begin
DPI wait(rtl_linkup == 1); Report a Bug or Comment
end on This section - Your
UVM Tutorial begin input is what keeps
VMM Tutorial forever Testbench.in improving
idles_transmit.start(Sequencer); with time!
OVM Tutorial end
Easy Labs : SV join_any
disable fork;
Easy Labs : UVM end
Easy Labs : OVM
Easy Labs : VMM In the above code we are driving idles until rtl_linkup condition is observed. But here
AVM Switch TB there is a problem, As we are trying kill idles_transmit sequence abruptly when
condition is met, this may cause the sequencer to be in intermittent state. This will
VMM Ethernet sample cause the problem on the next sequences which trigger on the same sequencer. As
sequencer is in intermittent state it may not get grant and will wait for for grant
forever. To avoid this problem we need to reset the sequencer after killing threads.
Verilog The code look like below.
Verification
Verilog Switch TB //Test
Basic Constructs begin
fork
begin
wait(rtl_linkup == 1);
OpenVera end
Constructs begin
Switch TB forever
idles_transmit.start(Sequencer);
RVM Switch TB end
RVM Ethernet sample join_any
disable fork;
Sequencer.stop_sequence();
end
Specman E
Interview Questions
In the above code the stop_sequences call will reset the sequencer variables and
won't cause any problem for the next sequences which are triggered on same
sequencer. Here also we have another problem with the sequence thread which is
killed with disable fork. Sometimes by the time thread is killed request might have
been sent to driver. if thread is killed and stop_sequence is called before receiving
the item_done, item_done will cause fatal error as request fifo is empty. So we need
to kill thread and call of stop_sequence only after receiving item_done from driver.
The code will look like below.
//Sequence .
class idles_transmit extends ovm_sequence #(REQ= packet);
bit received_item_done;
task body();
wait_for_grant();
assert(req.randomize());
send_req(req);
received_item_done = 0;
wait_for_item_done();
received_item_done = 1;
endtask
endclass
//Test
begin
fork
begin
wait(rtl_linkup == 1);
end
begin
forever
idles_transmit.start(Sequencer);
end
join_any
@(posedge idles_transmit.received_item_done);
disable fork;
Sequencer.stop_sequence();
end
In the above code we are trying to kill the thread and reseting sequencer state only
after receiving the ite_done for the request sent, which is the idle way to stop
thread.
| HOME | ABOUT | ARTICLES | ACK | FEEDBACK | SITEMAP | LINKS | BLOG | JOBS Search ✔
TUTORIALS
About the author:
SystemVerilog Do not rely on illegal_bins
Verification Ankit Gopani
is ASIC Engineer at
Constructs eInfochips,
Interface Do not rely on illegal_bins for checking purpose. If you rely on cover group where you Ahmedabad,India.
have written illegal_bins, what happens when you turn off the coverage??
OOPS He is a specialties in SoC
Randomization That is where Assertions coming in picture...! If you really want to ignore values then Verification and VIP
use ignore_bins. If you really want to throw errors then use an assertions checkers. development in System
Functional Coverage Verilog VMM.
Assertion While illegal_bins removes values from coverage calculations, it also throws errors.
Philosophically, you need to ask yourself the questions, Visit Ankit's Blog for
DPI more SV stuff
UVM Tutorial (1) "Should a passive component like a cover group be actively throwing errors?" and AsicWithAnkit.BlogSpot.com
VMM Tutorial (2) "If you rely on the cover group for checking, then what happens when you turn
coverage off?"
OVM Tutorial
Easy Labs : SV
covergroup cg @ (posedge clk iff decode); Report a Bug or Comment
Easy Labs : UVM on This section - Your
Easy Labs : OVM coverpoint opcode { input is what keeps
bins move_op[] = {3'b000, 3'b001}; Testbench.in improving
Easy Labs : VMM bins alu_op = {[3'b010:3'b011], [3'b101:3'b110]}; with time!
AVM Switch TB bins jump_op = {3'b111};
illegal_bins unused_op = {3'b100};
VMM Ethernet sample }
Verilog From the example given above, you can see 3'b100 is an illegal op code and as per
Verification protocol if that value occurs then its an error. So here instead of writing and
illegal_bins you can have a assert property with coverage to check specifically this
Verilog Switch TB scenario.
Basic Constructs
It is actually a debatable point because illegal bins will stops simulation if it hits, and
from the last message or from debugging engineer can debug the reason for failure.
The mail point is as it is not allowing the simulation forward, you can not check the
OpenVera functionality in error case. So to avoid this constraint we have assertions with cover
Constructs property which allows us to go ahead with simulation with error indication.
Switch TB
So usually I would prefer to have an assertions (with cover property) where strong
RVM Switch TB protocol check requires instead of writing illegal_bins.
RVM Ethernet sample
Enjoy...!
-ASIC with Ankit
Specman E
Interview Questions
| HOME | ABOUT | ARTICLES | ACK | FEEDBACK | SITEMAP | LINKS | BLOG | JOBS Search ✔
TUTORIALS
About the author:
SystemVerilog PASS and FAIL Messages with Colors...!
Verification Ankit Gopani
is ASIC Engineer at
Constructs eInfochips,
Interface How many among you know that you can actually display color messages using Verilog Ahmedabad,India.
and SystemVerilog?
OOPS He is a specialties in SoC
Randomization You can implement a logic in your testbench to have nicely colored display messages Verification and VIP
Functional Coverage
at the end of your simulation which will give you a PASS/FAIL messages. I have development in System
written a piece of code given below and you can refer the same. I have captured a Verilog VMM.
Assertion snapshot of output which you can see below.
Visit Ankit's Blog for
DPI more SV stuff
UVM Tutorial AsicWithAnkit.BlogSpot.com
VMM Tutorial program clr_display();
class color ;
OVM Tutorial task display ();
Easy Labs : SV $display("%c[1;34m",27);
$display("***************************************"); Report a Bug or Comment
Easy Labs : UVM $display("*********** TEST CASE PASS ************"); on This section - Your
Easy Labs : OVM $display("***************************************"); input is what keeps
$write("%c[0m",27); Testbench.in improving
Easy Labs : VMM with time!
AVM Switch TB $display("%c[1;31m",27);
$display("***************************************");
VMM Ethernet sample $display("*********** TEST CASE FAIL ************");
$display("***************************************");
$display("%c[0m",27);
Verilog endtask
Verification endclass
Verilog Switch TB initial
Basic Constructs begin
color clr;
clr = new ();
clr.display ();
OpenVera end
Constructs endprogram
Switch TB
RVM Switch TB OUTPUT:
RVM Ethernet sample
Specman E
Interview Questions
1 set bold
With an above example you can have a display messages with colors. So this way you
can have nicely and colored messages on your terminal.
Enjoy...!
-ASIC with Ankit
| HOME | ABOUT | ARTICLES | ACK | FEEDBACK | SITEMAP | LINKS | BLOG | JOBS Search ✔
TUTORIALS
About the author:
SystemVerilog Whats new in Systemverilog 2009 ?
Verification Ankit Shah
is working at Sibridge
Constructs In 2005 there were separate standards for Verilog and SystemVerilog which are Technologies Pvt. Ltd,
Interface merged here with SystemVerilog 2009. There are 30+ noticeable new constructs and Ahmedabad,India.
25+ system task are introduced in SystemVerilog 2009.
OOPS Your feedback / input /
Randomization I listed out following new constructs which are added in SV-2009. thought on this article,
send to Ankit @
Functional Coverage mail2ajshah@gmail.com
Assertion
DPI timeunit and timeprecision
UVM Tutorial You can specify timeunit and timeprecision inside the module with single keyword. Report a Bug or Comment
on This section - Your
VMM Tutorial
input is what keeps
OVM Tutorial module E (...); Testbench.in improving
timeunit 100ps / 10fs; // timeunit with optional second argument with time!
Easy Labs : SV
...
Easy Labs : UVM endmodule
Easy Labs : OVM
(Ch. 3.14.2.2 of LRM)
Easy Labs : VMM
AVM Switch TB
checker - endchecker
VMM Ethernet sample
The checker is specifically created to encapsulate assertions. It can be added with the
modeling code and can be instantiationed. Formal arguments of checker are inputs.
Verilog
Verification (Ch. 17)
Verilog Switch TB checker my_check1 (logic test_sig);
Basic Constructs a1: assert property (p (test_sig));
c1: cover property (!test_sig ##1 test_sig);
endchecker : my_check1
OpenVera global clocking
Constructs
Switch TB Global clocking block is declared as the global clocking block for an entire elaborated
SystemVerilog model.
RVM Switch TB
RVM Ethernet sample global clocking @(clk1 or clk2);
endclocking
(Ch. 14.14)
Specman E
Interview Questions Printing format
(Ch 21.2.1.2)
(Ch 21.2.1.2)
edge
It is equivalent to posedge+negedge
(Ch. 31.5)
let
This local score compiler directive replaces the other test macro like `define. A let
construct may be instantiated in other expressions.
let declarations can be used for customization and can replace the text macros in
many cases.
unique0
Keyword unique will issue a violation report if no condition matches. while keyword
unique0 will not issue a violation report if no condition matches.
(Ch. 12.4.2)
size() method is introduced to return number of entries in associative array like num()
method.
(Ch. 7.9.1)
Queue delete()
Now you can pass specific index number inside the delete function to delete that
particular index. If index is not specified then it will delete entire Q.
(Ch. 7.10.2)
module dut(
input bit_pkg::reset rst;
input bit_pkg::clk clock;
...
endmodule
Packet chaining, automatic package and multiple package export is also introduced in
SV-2009.
(Ch. 23)
SV-2009 allows to declare pure virtual methods as well as class. It must be written in
abstract class & it must be only a prototype, It must not contain any statement and
must with without endtask/endfunction.
virtual class BasePacket;
pure virtual function integer send(bit[31:0] data); // No implementation
endclass
(Ch. 8.20)
pure constraint
virtual class C;
pure constraint test;
endclass
(Ch. 18.5.2)
Using fork/join_none, now time consuming constructs can be used inside function.
function void disp;
fork
#0 $display("%t: This is #0", $time);
#1 $display("%t: This is #1", $time);
#3 $display("%t: This is #3 and A = %x", $time, a);
a <= 8'hbb; // It allows non-blocking assignment
#2 $display("%t: This is #2", $time);
join_none
endfunction
(Ch. 9.3.2)
cg cg1 = new;
function void F(int j);
bit d;
...
cg1.sample( d, j );
endfunction
(Ch. 19.8.1)
weak - strong
These sequence operators are introduced to simulate assertion efficiently. Assert may
produce wrong message if there is a glitch in the signal. strong require that some
terminating condition happen in the future, and this includes the requirement that
the property clock ticks enough time to enable the condition to happen. weak do not
impose any requirement on the terminating condition, and do not require the clock to
tick. If the strong or weak operator is omitted, then the evaluation of the
sequence_expr depends on the assertion statement in which it is used. If the assertion
statement is assert property or assume property, then the sequence_expr is evaluated
as weak(sequence_expr). Otherwise, the sequence_expr is evaluated as
strong(sequence_expr).
The default in SV-2005 was strong while in SV-2009 is weak unless you. specified
strong.
(Ch. 16.13)
A property of this form evaluates to true if, and only if, either both
(Ch. 16.13)
Property s1 says that done shall be asserted at some clock tick during the first 6 clock
ticks, and starting from one of the clock ticks when done is asserted, rst shall always
be low. Property s2 says that done shall be asserted at some clock tick during the first
6 clock ticks, and starting the clock tick after one of the clock ticks when done is
asserted, rst shall always be low.
(Ch. 16.13)
always - s_always
property s1;
a ##1 b |=> always c;
endproperty
property s1 evaluates to true provided that if a is true at the first clock tick and b is
true at the second clock tick, then c shall be true at every clock tick that follows the
second.
(Ch. 16.13)
property s1;
a until b;
endproperty
property p3;
a until_with b;
endproperty
Property s1 evaluates to true if, and only if, a is true at every clock tick beginning
with the starting clock tick of the evaluation attempt and continuing
until, but not necessarily including, a clock tick at which b is true.
(Ch. 16.13)
The property p3 evaluates to true provided that a is true at every clock tick beginning
with the starting clock tick of the evaluation attempt and continuing
until and including a clock tick at which b is true.
(Ch. 16.13)
eventually - s_eventually
property s1;
s_eventually a;
endproperty
The property s1 evaluates to true if, and only if, there exists a current or future clock
tick at which a is true.
(Ch. 16.13.13)
property p; (reject_on(b) s2); endproperty
property p; not (reject_on(b) s2); endproperty
not inverts the effect of operator, so if b becomes true during the evaluation of s2
then p evaluates to true.
(Ch. 16.13.14)
case
(Ch. 16.13.16)
restrict
untyped
(Deferred assertion) assert #0 - assume #0 - cover #0
Deferred immediate assertion evaluates after signal have stabilized in a time step.
Shortcut operators
##[+] is equivalent to ##[1:$]
##[*] is equivalent to ##[0:$]
<signal>[+] is equivalent to <signal>[*1:$]
<signal>[*] is equivalent to <signal>[*0:$]
(Ch. 16.7)
`define
`define MACRO1(a=5) $display(a);
(Ch. 22.5)
`undefineall
`define FPGASIM
`define GATESIM
module...
....
....
endmodule
`undefineall
(Ch. 22.5)
It is used to specify reserved keywords, it will give an error if implementain does not
matched with version_specifier. e.g if you have specified "1800-2009" then all the
previous versions of Verilog/SystemVerilog keywords can be used but if you have
specified "1800-2005" then those keywords which are introduced specifically in SV-
2009 those can not be used.
(Ch. 22.14)
It keeps track of the filenames of SystemVerilog source files and line nunbers in the
files. which can be helpfull to source error messages and the file name. `__FILE__
expands to the name of the current input file, in the form of a string literal constant.
This is the path by which the compiler opened the file, not the short name specified
in `include or as the command line argument. `__LINE__ expands to the current input
line number, in the form of a decimal
integer constant.
file path and line number will be return which contain above message.
SYSTEM TASK
(Ch 20.18.1)
$global_clock returns the event statement which is written global clocking block
declaration. Here it will return "clk1 or clk2".
(Ch. 14.14)
$sformatf - this system function returns the message into string. Thus string can be
passed into valid function.
$fatel - $error - $warning - $info can be used outside assertion.
$assertpasson - enable execution of pass statement.
$assertpassoff - stop execution of pass statement.
$assertfailon - enable execution of pass statement.
$assertfailoff - stop execution of fail statement.
$assertnonvacuouson - enable execution of pass statement when assertion is vacuous.
$assertvacuousoff - stop execution of pass statement when assertion is non vacuous.
$changed
(Ch 20.13)
$past_gclk - $rose_gclk - $fell_gclk - $stable_gclk - $changed_gclk
It will give past sampled value of the signal with respect to global clock.
(Ch 20.13)
$future_gclk - $rosing_gclk - $falling_gclk - $steady_gclk - $changing_gclk
It will give future sampled value of the signal with respect to global clock.
$inferred_clock - $inferred_disable - $inferred_enable
(Ch. 16.15.7)
Protected envelopes
It specify a region of text that shall be transformed prior to analysis by the source
language processor.
(Ch. 34)
Still there could be many enhancement behind the curtain. It always GOOD to KNOW
more. Your feedback/input/thought are welcomed which can help me to update
contain. Reach me at mail2ajshah@gmail.com
Search ✔
TUTORIALS
About the authors:
SystemVerilog Introduction to Ethernet Frames : Part - 1
Verification Bhavani shankar is VLSI
engineer at Kacper
Constructs This tutorial is divided into two parts. Part-1 will be on Ethernet Frames and Part-2 Technologies Pvt. Ltd.
Interface will be on Simple Ethernet Testplan. Bhavani shankar is an
For Part-2 , Click master in VLSI-CAD from
OOPS Manipal Centre for
Randomization Information Science,
1.Ethernet Protocol Layer Manipal.
Functional Coverage
Assertion The Ethernet protocol basically implements the bottom two layers of the Open Gopi Krishna He is the
DPI Systems Interconnection (OSI) 7-layer model, i.e., the data link and physical sub Author of testbench.in.
layers. Following Figure depicts the typical Ethernet protocol stack and the
UVM Tutorial relationship to the OSI model.
VMM Tutorial
Report a Bug or Comment
OVM Tutorial on This section - Your
input is what keeps
Easy Labs : SV
Testbench.in improving
Easy Labs : UVM with time!
Easy Labs : OVM
Easy Labs : VMM
AVM Switch TB
VMM Ethernet sample
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB 2.Ethernet Frame Structure
RVM Switch TB The following illustrates the format of an Ethernet frame as defined in the original
RVM Ethernet sample IEEE 802.3 standard
Specman E
Interview Questions
Preamble
A sequence of 56 bits having alternating 1 and 0 values that are used for
synchronization. They serve to give components in the network time to detect the
presence of a signal, and read it before the frame data arrives.
The Destination MAC Address field addresses destination stations. This may addresses
single or multiple stations.
Destination Address (6bytes) of all 1 bits refers to all stations on the LAN and is called
a "Broadcast address".
Sequence of 8 bits having the bit configuration 10101011 indicates the start of the
frame.
The Source MAC Address addresses the station at which it originated. The 802.3
standard permits these address fields to be either 2-bytes or 6-bytes in length.
Length/Type (2bytes)
If the value of this field is less than or equal to 1500, then the Length/Type field
indicates the number of bytes in the subsequent MAC Client Data field. If the value of
this field is greater than or equal to 1536, then the Length/Type field indicates the
nature of the MAC client protocol (protocol type)
This field contains the actual data transferred from the source station to the
destination station or stations. The maximum size of this field is 1500 bytes. If the
size of this field is less than 46 bytes, then use of the subsequent "Pad" field is
necessary to bring the frame size up to the minimum length.
Pad
If necessary, extra data bytes are appended in this field to bring the frame length up
to its minimum size. A minimum Ethernet frame size is 64 bytes from Destination MAC
Address(DA) field through the Frame Check Sequence(FCS).
This field contains a 4-byte Cyclic Redundancy Check (CRC) value used for error
checking.
When a source station assembles a MAC frame, it calculates a CRC checksum on all
the bits in the frame from Destination MAC Address (DA) to the Pad fields (that is, all
fields except the preamble, start frame delimiter, and frame check sequence).
The source station stores this CRC value in this field and transmits it as part of the
frame. When the frame is received at destination station, it calculates CRC of
received data and compares it with FCS. If it does not match then destination station
assumes an error occurred during transmission and discards the frame.
The original Ethernet standards defined the minimum frame size as 64-bytes and the
maximum as 1518-bytes. These numbers include all bytes from the Destination MAC
Address field through the Frame Check Sequence field. The Preamble and Start Frame
Delimiter fields are not included when quoting the size of a frame. The IEEE 802.3ac
standard released in 1998 extended the maximum allowable frame size to 1522-bytes
to allow a "VLAN tag" to be inserted into the Ethernet frame format.
Interframe Gap
Ethernet devices must allow a minimum idle period between transmission of frames
known as the interframe gap (IFG) or interpacket gap (IPG). It provides the time for
devices to recover and prepare to receive next frame. The minimum interframe gap is
96 bit times.
The last 2-bytes of the VLAN tag contain the following information
The first 3-bits are a User Priority Field that may be used to
Assign a priority level to the Ethernet frame.
The next 1-bit is a Canonical Format Indicator (CFI) used in Ethernet frames to
indicate the presence of a Routing Information Field (RIF).
The last 12-bits are the VLAN Identifier (VID) which uniquely identifies the VLAN to
which the Ethernet frame belongs.
JUMBO Frames
JUMBO frames are introduced in order to Increase the maximum size of the MAC Client
Data field, larger frames would provide more efficient use of the network Bandwidth
while reducing the number of frames that have to be processed.
JUMBO frames has the capacity to carry bytes from 64bytes (min size) to 9000bytes
(max size)
The 8870 value is actually a reserved Length/Type field assignment that indicates
frame as JUMBO.
PAUSE Frames
Flow control operation known as "PAUSE" frames are included in 10GBE as it supports
the full duplex mode.
The 8808 value is actually a reserved Length/Type field assignment that indicates
frame as PAUSE. Length/Type field is followed by 2 bytes of MAC control Opcode (00-
01) and 2bytes of MAC control Parameter (timer=00-00toFF-FF) with a unique DA (01-
80-c2-00-00-01) in MAC DA field
PAUSE frame considers 64bytes as Minimum size and 1518bytes as Maximum size for
Normal frame and 1522bytes when tagged.
Transmitter Mac should not transmit the frames once it receives Pause frames from
receiver until the time duration specified in the Pause timer
Transmitter Mac should reset/replace the current pause timer with newly arrived
pause time when a Pause frame arrives from receiver before the current Pause time
expires.
Search ✔
TUTORIALS
About the authors:
SystemVerilog Introduction to Ethernet Frames : Part - 2
Verification Bhavani shankar is VLSI
engineer at Kacper
Constructs In part-2 , we will see a simple testplan for 10G Ethernet Frames. Technologies Pvt. Ltd.
Interface For Part-1 , Click Bhavani shankar is an
master in VLSI-CAD from
OOPS Manipal Centre for
TEST PLAN FOR MAC FRAME
Randomization Information Science,
Manipal.
Functional Coverage
MAC FRAME FORMAT
Assertion Gopi Krishna He is the
Author of testbench.in.
DPI
UVM Tutorial
VMM Tutorial
Report a Bug or Comment
OVM Tutorial on This section - Your
input is what keeps
Easy Labs : SV PREAMBLE Testbench.in improving
Easy Labs : UVM with time!
Discussion:
Easy Labs : OVM
Easy Labs : VMM The frame begins with the 64-bit preamble field which allows 10G Ethernet
interfaces on the network to synchronize themselves with the incoming data stream
AVM Switch TB before the arrival of important data fields.
VMM Ethernet sample
[Need for Synchronization: In LAN implementation, most of the physical layer
components are allowed to provide valid output only after some number of bit times
Verilog prior to the valid input signals. So this condition necessities a Preamble which is to be
sent before the start of the data .This allows the PLS circuitry to reach its steady
Verification state with the received frame’s timing. So Preamble is used for physical medium
Verilog Switch TB stabilization and synchronization followed by SFD.]
Basic Constructs
Preamble is not used by the MAC layer, so the minimum amount of preamble
required for a device to function properly depends up on which physical layer is
implemented and not up on the MAC layer.
OpenVera
Constructs The preamble bits are transmitted in order from left to right and it should be noted
Switch TB that PRE ends with a ‘0’.
RVM Switch TB Up on the reception of a Frame Physical signal Decapsulation procedure discards
RVM Ethernet sample every bit of preamble until a valid SFD.
IEEE Standard does not define the minimum PRE size, PRE size is handled depending
up on the PHY as it is the function of physical medium. So min PRE size is considered
Specman E as 1byte .Even though Standard defines as PRE as 7bytes,Mac should tolerate large
Interview Questions amounts of Preamble
[The PRE is maintained in the fast Ethernet and gigabit systems to provide
compatibility with the original Ethernet frame. However, both systems use more
complex mechanisms for encoding the signals that avoid any signal startup losses, so
they don’t need preamble to protect the frame signals]
Valid PRE
1) A frame with PRE of 7octets in PRE field with the bit pattern shown below and
should always end with a ‘0’.
2) A frame with variable PRE octets like 1, 2, 3,4,5,6 by using pattern shown in 1st
case
Invalid PRE
3) Generate a frame with varying bit pattern’s using following cases and observe the
results.
5) Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
References:
Discussion:
SFD field is the sequence 10101011 which immediately follows the PRE pattern and
indicates the start of the frame.
The last two bits indicates the receiving interface that the end of the preamble
and SFD has been reached and that the bits that follow are actual fields of the frame
Any successive bits following the transmission of SFD are recognized as data bits
and are passed on to the LLC sub layer
Valid SFD
1) A frame of one octet size SFD with bit pattern 10101011 and placed after PRE.
2) Any frame with invalid SFD pattern is considered as Bad frame and discarded
Invalid SFD
2) A Frame consisting only PRE and Good SFD [i.e. Sop PRE SFD Eop]
3) Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
References:
FCS field contains a 4-byte cyclical redundancy check (CRC) value used for error
checking. CRC is a polynomial that is calculated using the contents of the destination,
source, type (or length), and data fields except PRE, SFD and FCS. As the frame is
generated by the transmitting station, the CRC value is simultaneously being
calculated.
The source station stores 32 bits of the CRC value (x31 term is the most bit of the
first octet and the x0term is the right most of the last octet) that are the result of
this calculation in the FCS field and transmits it as a part of the frame. The x31
coefficient of the CRC polynomial is sent as the first bit of the field and the x0
coefficient as the last bit.
Valid CRC
1) The 32bit CRC value in FCS field of received frame should match the 32bit CRC
value computed on received frame.
Invalid CRC
2) Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
References:
IEEE STD 802.3,2005 Edition, subclasses 3.2.8, 4.2.4.1.2.
O’REILY-Ethernet Definitive Guide. PDF
LENGTH/TYPE FIELD
Discussion:
a) In case of untagged
Maximum untagged frame size is 1518 bytes(from DA to FCS)
b) In case of tag
Maximum tagged frame size is 1522bytes (Untagged size + tag prefix size)
If the value in the Length/type field is less than or equal to 1500 then the Value
indicates the number of bytes in the subsequent MAC Client Data field. (Length
Interpretation)
If the value in the length/type field is greater than or equal to 1536 then the value
Indicates the nature of the MAC client protocol (protocol type like jumbo, pause etc)
All other values are undefined. (Type Interpretation)
The minimum length of the Data/Pad field is 46 bytes, if the length of the frame in
the length/type field is less than 46 then all extra bytes are considered as
padded/appended in this field to bring the frame length up to its minimum size
The maximum length of the Data/pad field is 1500bytes, if the length of the frame
in the length /type field is greater than 1500 and less than 1536, frame is discarded.
10GE supports the VLAN Tagging which is inserted in to the Ethernet frame
between the source MAC address and Length/Type field. The first 2-bytes of the VLAN
tag consist of the "802.1Q Tag Type" and are always set to the value of 0x8100.
a) VLAN tagged frames takes 64bytes as minimum size and 1522 bytes as maximum
size (max size may vary depending up on VLAN count).
b) The 0x8100 value is actually a reserved Length/Type field assignment that
indicates the presence of the VLAN tag.
Note: As the Standard does not define the min tagged frame size, it is considered as
64bytes which is common to all types of frames. This min size constraint may vary
depending up on the Company, (CISCO defined the minimum size of the Ethernet
frame with 802.1Q tagging is 68 bytes)
JUMBO frames are introduced in order to Increase the maximum size of the MAC
Client Data field, larger frames would provide more efficient use of the network
Bandwidth while reducing the number of frames that have to be processed.
a) JUMBO frames has the capacity to carry bytes from 64bytes (min size) to
9000bytes (max size)
b) The 8870 value is actually a reserved Length/Type field assignment that
indicates frame as JUMBO.
Valid Frames
1) A frame(untagged) size between 64 and 1518 bytes [Valid size Normal untagged
frame]
Generate a frame with the following acceptable sizes and observe the results. Mac
should accept these frames
64,65,67,100,512,1500,1516,1517,1518
2) A tagged frame size between 64 and 1522 bytes [Valid size Normal tagged frame]
Generate a frame with the following acceptable sizes and observe the results, Mac
should accept these frames
64,65,67,100,512,1500,1516,1517,1518, 1520,1522
3) A frame less than min length (<46) with padded values [Length (<46) untagged
padded Normal frame]
Generate a frame with the following lengths in length field along with proper
Padding and observe the results, Mac should accept the frames
1,2,3,4,5,6,7,40,42,44,45
4) A frame greater than min length (with out padding) but less than max
length(1500bytes) [Length (>46) untagged Normal frame]
Generate a frame with the following lengths in length field and observe the
results, Mac should accept the frames
47,50,100,512,1497,1498,1499,1500
5) A frame greater than or equal to1536 bytes i.e. Type interpretation Generate a
frame with the following values in length/Type field and observe the results, Mac
should interpret the frame as one of the following types
Generate a Jumbo frame of size (< =9k+22); Mac should accept the frame as JUMBO
frame with VLAN tag. [JUMBO (size<=9k+22) tagged frame]
a) Generate a frame of size (>64) by placing 8870 in the regular Length/type field
and repeat with 1st valid frame case including 1519, 1520, 1522. Mac should accept
the frame as JUMBO untagged frame. [JUMBO (size>64) untagged frame]
5.3.1) PAUSE frame of size (>64) and (<1522) with VLAN tag
Generate a Tagged Pause frame by placing 8808 in the regular Length/type field
and next 2bytes of opcode field with (00-01) and repeat with 2nd valid frame cases
(64,65,67,100,512,1500,1516,1517,1518, 1520,1522) ; Mac should accept the frame as
Pause frame with VLAN tag. [PAUSE (size>64) and (<1522) Tagged Frame]
Generate a untagged pause frame and repeat with 1st valid frame cases
(64,65,67,100,512,1500,1516,1517,1518); Mac should accept the frame as Pause
frame with out VLAN tag. [PAUSE (size>64) and (<1518) untagged Frame]
5.3.3) PAUSE frame with MAC control Parameters (zero & Non-zero Timer)
a) Generate a untagged Pause frame by placing (00-01) in opcode field and vary
timer values from 00-00 to FF-FF(hex) [Untagged PAUSE with Zero & non-zero Timer]
b) Repeat (a) for tagged Pause frame [Tagged PAUSE with Zero & non-zero Timer]
c) Repeat (a),(b) with different pause times before the completion of current
pause_timer [Multiple Pause frames with different timers]
Invalid Frames
1) A Frame which is less than min frame size (<64) with bad CRC(Runt frames) [Runt
size (<64) common to Normal, JUMBO&VLAN tagged/untagged Runt frames]
a) Generate a frame (both tagged and untagged) with the following sizes which are
less than min frame size (<64) and observe the results, MAC should discard these
frames
(1) 1, 2,3,4,5,6,7,8,45,46,47
(2) 50, 61, 62, 63
b) Repeat (a) for PAUSE frame and observe the results, Mac should not accept the
frame as VALID [PAUSE Runt frame]
3) A untagged Frame greater than max frame size (>1518) [Over size (>1518) untagged
Normal frame]
3.1) Generate a frame with the following sizes which are greater than Max frame
size
a) 1519, 1520, 1521, 1522
b) 1526, 1530, 1534,1535,1536,1537
3.2) Repeat (a) for untagged PAUSE frame [Over size (>1518) untagged PAUSE
frame]
(a) Generate a frame using 3.A (b) Invalid frame cases [Over size (>1522) tagged
Normal frame]
(b) Repeat (a) for tagged PAUSE frame [Over size (>1522) tagged PAUSE frame]
a) Generate a frame with the following lengths in length field without padding and
observe the results, Mac should discard the frames as
1,2,3,4,5,6,7,40,42,44,45 [Runt Length (<46) not padded Normal frame]
b) Repeat (a) with tagged frame [Runt Length (<46) not padded tagged Normal
frame]
[Example: suppose current pause timer is set to 8sec and if other frame arrives with
pause time 0sec, then Mac should transmit the frames with out violating the min IFG]
Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
References:
IEEE Std 802.3, 2002 Edition - subclasses 3.1.1, Figure 3-1 - MAC frame format,3.2.6,
3.5, Figure 3-3 Tagged MAC frame format, 4.4.2-allowable Implementations
IEEE STD 802.3-2005 - Subclasses 31.3 and 31B.3.3, 31B.3.7
IEEE STD 802.3-2005 - Subclasses 3.5, 31.4, 31.5.1, and 31.5.2
IEEE STD 802.3-2005 - Subclasses 4.2.9, and 4.2.4.2.2
O’REILY-Ethernet Definitive Guide. PDF
The Destination MAC Address field identifies the station or stations that are to
receive the frame. DA field follows the preamble and Each Ethernet interface is
assigned a unique 48-bit address, called the interface's physical or hardware address.
The DA field contains the 48-bit Ethernet address that corresponds to the address
of the interface in the station that is the destination of the frame.
The DA field may specify either an "Individual address" destined for a single station
or "Multicast address" destined for a group of stations or the standard broadcast
address
The IEEE 802.3 version of the frame adds significance to the second bit of the
destination address, which is used to distinguish between locally and globally
administered addresses.
2) If the address of the Ethernet interface is administered locally for some reason,
then the second bit is supposed to be set to a value of one. In the case of a broadcast
address, the second bit is also a one.
Remaining 46bits are a uniquely assigned value that identifies a single station or
group of stations or all stations on the network
[Locally administered addresses are very rarely used on Ethernet systems, since the
vast majority of Ethernet interfaces are assigned their own unique 48-bit address.
Locally administered addresses, However, have been commonly used on some Token
Ring systems.]
Valid Frame
a) Repeat 5.3.C (a), (b),(c) Valid paused Type frame cases by placing unique
multicast address reserved for PAUSE transactions (01-80-C2-00-00-01) [Un tagged
Pause with Unique (DA) reserved Multicast Address]
b) Repeat (a) for tagged PAUSE frame [Tagged Pause with Unique (DA) reserved
Multicast Address]
Invalid Frame
2) PAUSE frame with invalid DA (only when addresses are not valid )
a) Generate a Pause frame with DA other than pause unique Multicast address (01-
80-C2-00-00-01) by placing following address values in DA field
[Invalid DA PAUSE tagged frame] All zeros(0000000000000)
All ones(11111111111111)
SFD or PRE pattern(10101011)
Random values
b) Repeat (a) for untagged PAUSE frame [Invalid DA PAUSE untagged frame]
Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
References:
The Source MAC Address (6 bytes) identifies the station that originated the frame
and it is always an individual address. The 1st bit (LSB) is reserved and always set
to"0".
This is the physical address of the interface that sends the frame. The source
address is not interpreted in any way by the Ethernet MAC protocol. Instead, it is
provided for the use of high-level protocols. An Ethernet station uses its physical
address as the source address in any frame it transmits.
[IEEE standard does not specifically state that an interface may have the ability to
override the 48-bit physical address assigned by the manufacturer. However, all
Ethernet interfaces in use these days appear to allow the physical address to be
changed, which makes it possible for the network administrator or the high level
network software to modify the Ethernet interface address]
Valid Frame
Generate a frame by placing valid 6bytes of source address ensuring first bit with "0"
Invalid Frame
1) A Frame with 6bytes of invalid SA(only when following are invalid addresses)
[Invalid SA field Normal frame]
a) Generate a frame by placing following invalid address values
All zeros (000000...)
All ones (1111111...)
SFD or PRE pattern(10101011)
Random value
2) Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
3) A frame with invalid SA by making 0th bit as 1 ,Receiving MAC should discard
packet
References:
Data Field contains the data transferred from the source station to the destination
station or stations
The maximum size of this field is 1500 bytes
The minimum size of this field is 46bytes
The maximum size of the data field is determined by the maximum frame size and
address size parameters of the particular implementation
PAD
If the size < 46 bytes, then use of the subsequent "Pad" field is necessary to bring
the frame size up to the minimum length.
If necessary, extra data bytes are appended in this field to bring the frame length up
to its minimum size.
The size of the pad, if any is determined by the size of the data field supplied by the
MAC client and the minimum frame size and address size parameters.
Full data transparency is provided in the sense that any arbitrary sequence of octet
values may appear in the data field up to a maximum number specified by the
implementation of the standard that is used.
Length value indicated in Length/Type field is compared with the Data length in
Data field
Length>Data length - Length error (loss of Data bits)
Length
Length=Data length - no padding required
For a padded Frame of Length (<46) in Length/Type field then data length should
be always greater than the value in length field.
Valid Frame
Invalid Frame
1) Generate a Tagged frame of length (<46) in Length/Type field but data field length
shows value (<46) even after padding is performed by transmitter Mac. [Padded
Tagged frame < min size]
3) A Frame of length (>46) in Length/Type field but data field shows the length less
than the length shown in Length field. [Frame with Length error(loss of Data bits)]
{Suppose length field has 70 but data length is 60bytes then what about remaining
10bytes?}
5) Repeat bad frames mentioned above with each frame followed and preceded by a
Good Frame separated by required minimum Inter Frame Gap (96 bits).
References:
Search ✔
TUTORIALS
About the author:
SystemVerilog Introduction to PCI Express
Verification Arjun Shetty
is perusing Master of
Constructs We will start with a conceptual understanding of PCI Express. This will let us Technology in VLSI &
Interface appreciate the importance of PCI Express. This will be followed by a brief study of the Embedded Systems in
PCI Express protocol. Then we will look at the enhancements and improvements of the International Institute
OOPS Of Information
protocol in the newer 3.0 specs.
Randomization Technology, Hyderabad
Functional Coverage 1 Basic PC system architecture
Arjuns Blog
Assertion We will start by looking at the basic layout of a PC system. Logically, an average PC
DPI system is laid out in something like shown in the figure.
UVM Tutorial The core logic chipset acts as a switch or router, and routes I/O traffic among the Report a Bug or Comment
different devices that make up the system. on This section - Your
VMM Tutorial
input is what keeps
OVM Tutorial In reality, the core logic chipset is split into two parts: the northbridge and the Testbench.in improving
Easy Labs : SV southbridge (or I/O bridge). This split is there for a couple of reasons, the most with time!
important of which is the fact that there are three types of devices that naturally
Easy Labs : UVM work very closely together, and so they need to have faster access to each other: the
Easy Labs : OVM CPU, the main memory, and the video card. In a modern system, the video card's GPU
is functionally a second (or third) CPU, so it needs to share privileged access to main
Easy Labs : VMM
memory with the CPU(s). As a result, these three devices are all clustered together
AVM Switch TB off of the northbridge.
VMM Ethernet sample
Verilog
Verification
Verilog Switch TB
Basic Constructs
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
The northbridge is tied to a secondary bridge, the southbridge, which routes traffic
from the different I/O devices on the system: the hard drives, USB ports, Ethernet
ports, etc. The traffic from these devices is routed through the southbridge to the
northbridge and then on to the CPU and/or memory.
As is evident from the diagram above, the PCI bus is attached to the southbridge. This
bus is usually the oldest, slowest bus in a modern system, and is the one most in need
of an upgrade.
The main thing that we should take away from the previous diagram is that the
modern PC is a motley collection of specialized buses of different protocols and
bandwidth capabilities. This mix of specialized buses designed to attach different
types of hardware directly to the southbridge is something of a continuously evolving
hack that has been gradually and collectively engineered by the PC industry as it tries
to get around the limitations of the aging PCI bus. Because the PCI bus can't really cut
it for things like Serial ATA, Firewire, etc., the trend has been to attach interfaces
for both internal and external I/O directly to the southbridge. So today's southbridge
is sort of the Swiss Army Knife of I/O switches, and thanks to Moore's Curves it has
been able to keep adding functionality in the form of new interfaces that keep
bandwidth-hungry devices from starving on the PCI bus.
In an ideal world, there would be one primary type of bus and one bus protocol that
connects all of these different I/O devices ? including the video card/GPU ? to the
CPU and main memory. Of course, this "one bus to rule them all" ideal is never, ever
going to happen in the real world. It won't happen with PCI Express, and it won't
happen with Infiniband (although it technically could happen with Infiniband if we
threw away all of today's PC hardware and started over from scratch with a round of
natively Infiniband-compliant devices).
Still, even though the utopian ideal of one bus and one bus protocol for every device
will never be achieved, there has to be way bring some order to the chaos. Luckily for
us, that way has finally arrived in the form of PCI Express (a.k.a. PCIe).
2 A primer on PCI
Before we go into detail on PCIe, it helps to understand how PCI works and what its
limitations are.
The PCI bus debuted over a decade ago at 33MHz, with a 32-bit bus and a peak
theoretical bandwidth of 132MB/s. This was pretty good for the time, but as the rest
of the system got more bandwidth hungry both the bus speed and bus width were
cranked up in a effort keep pace. Later flavors of PCI included a 64-bit, 33MHz bus
combination with a peak bandwidth of 264MB/s; a more recent 64-bit, 66MHz
combination with a bandwidth of 512MB/s.
PCI uses a shared bus topology to allow for communication among the different
devices on the bus; the different PCI devices (i.e., a network card, a sound card, a
RAID card, etc.) are all attached to the same bus, which they use to communicate
with the CPU. Take a look at the following diagram to get a feel for what a shared
bus looks like.
Because all of the devices attached to the bus must share it among themselves, there
has to be some kind of bus arbitration scheme in place for deciding who gets access
to the bus and when, especially in situations where multiple devices need to use the
bus at the same time. Once a device has control of the bus, it becomes the bus
master, which means that it can use the PCI bus to talk to the CPU or memory via the
chipset's southbridge.
The shared bus topology's main advantages are that it's simple, cheap, and easy to
implement ? or at least, that's the case as long as you're not trying to do anything too
fancy with it. Once you start demanding more performance and functionality from a
shared bus, then you run into its limitations. Let's take a look at some of those
limitations, in order to motivate our discussion of PCI Express's improvements.
This scheme works fine when there are only a few devices attached to the bus,
listening to it for addresses and data. But the nature of a bus is that any device that's
attached to it and is "listening" to it injects a certain amount of noise onto the bus.
Thus the more devices that listen to the bus ? and thereby place an electrical load on
the bus ? the more noise there is on the bus and the harder it becomes to get a clean
signal through.
To summarize, PCI as it exists today has some serious shortcomings that prevent it
from providing the bandwidth and features needed by current and future generations
of I/O and storage devices. Specifically, its highly parallel shared-bus architecture
holds it back by limiting its bus speed and scalability, and its simple, load-store, flat
memory-based communications model is less robust and extensible than a routed,
packet-based model.
The PCI-X spec essentially doubled the bus width from 32 bits to 64 bits, thereby
increasing PCI's parallel data transmission abilities and enlarging its address space.
The spec also ups PCI's basic clock rate to 66MHz with a 133MHz variety on the high
end, providing yet another boost to PCI's bandwidth and bringing it up to 1GB/s (at
133MHz).
The latest version of the PCI-X spec (PCI-X 266) also double-pumps the bus, so that
data is transmitted on the rising and falling edges of the clock. While this improves
PCI-X's peak theoretical bandwidth, its real-world sustained bandwidth gains are more
modest.
While both of these moves significantly increased PCI's bandwidth and its usefulness,
they also made it more expensive to implement. The faster a bus runs, the sensitive it
becomes to noise; manufacturing standards for high-speed buses are exceptionally
strict for this very reason; shoddy materials and/or wide margins of error translate
directly into noise at higher clock speeds. This means that the higher-speed PCI-X bus
is more expensive to make.
The higher clock speed isn't the only thing that increases PCI-X's noise problems and
manufacturing costs. The other factor is the increased bus width. Because the bus is
wider and consists of more wires, there's more noise in the form of crosstalk.
Furthermore, all of those new wires are connected at their endpoints to multiple PCI
devices, which means an even larger load on the bus and thus more noise injected
into the bus by attached devices. And then there's the fact that the PCI devices
themselves need 32 extra pins, which increases the manufacturing cost of each
individual device and of the connectors on the motherboard.
All of these factors, when taken together with the increased clock rate, combine to
make the PCI-X a more expensive proposition than PCI, which keeps it out of
mainstream PCs. And it should also be noted that most of the problems with
increasing bus parallelism and double-pumping the bus also plague recent forms of
DDR, and especially the DDR-II spec.
And after all of that pain, you still have to deal with PCI's shared-bus topology and all
of its attendant ills. Fortunately, there's a better way.
PCIe's most drastic and obvious improvement over PCI is its point-to-point bus
topology. Take a look at the following diagram, and compare it to the layout of the
PCI bus.
In a point-to-point bus topology, a shared switch replaces the shared bus as the
single shared resource by means of which all of the devices communicate. Unlike in a
shared bus topology, where the devices must collectively arbitrate among themselves
for use of the bus, each device in the system has direct and exclusive access to the
switch. In other words, each device sits on its own dedicated bus, which in PCIe lingo
is called a link.
Like a router in a network or a telephone switchbox, the switch routes bus traffic and
establishes point-to-point connections between any two communicating devices on a
system.
The overall effect of the switched fabric topology is that it allows the "smarts" needed
to manage and route traffic to be centralized in one single chip ? the switch. With a
shared bus, the devices on the bus must use an arbitration scheme to decide among
themselves how to distribute a shared resource (i.e., the bus). With a switched
fabric, the switch makes all the resource-sharing decisions.
When PCIe's designers started thinking about a true next-generation upgrade for PCI,
one of the issues that they needed to tackle was pin count. In the section on PCI
above, I covered some of the problems with the kind of large-scale data parallelism
that PCI exhibits (i.e. noise, cost, poor frequency scaling, etc.). PCIe solves this
problem by taking a serial approach.
As I noted previously, a connection between two a PCIe device and a PCIe switch is
called a link. Each link is composed of one or more lanes, and each lane is capable of
transmitting one byte at a time in both directions at once. This full-duplex
communication is possible because each lane is itself composed of one pair of signals:
send and receive.
In order to transmit PCIe packets, which are composed of multiple bytes, a one-lane
link must break down each packet into a series of bytes, and then transmit the bytes
in rapid succession. The device on the receiving end must collect all of the bytes and
then reassemble them into a complete packet. This disassembly and reassembly
happens must happen rapidly enough to where it's transparent to the next layer up in
the stack. This means that it requires some processing power on each end of the link.
The upside, though, is that because each lane is only one byte wide, very few pins are
needed to transmit the data. You might say that this serial transmission scheme is a
way of turning processing power into bandwidth; this is in contrast to the old PCI
parallel approach, which turns bus width (and hence pin counts) into bandwidth. It so
happens that thanks to Moore's Curves, processing power is cheaper than bus width,
hence PCIe's tradeoff makes a lot of sense.
We saw earlier that a link can be composed of "one or more lanes", so us clarify that
now. One of PCIe's nicest features is the ability to aggregate multiple individual lanes
together to form a single link. In other words, two lanes could be coupled together to
form a single link capable of transmitting two bytes at a time, thus doubling the link
bandwidth. Likewise, you could combine four lanes, or eight lanes, and so on.
A link that's composed of a single lane is called an x1 link; a link composed of two
lanes is called an x2 link; a link composed of four lanes is called an x4 link, etc. PCIe
supports x1, x2, x4, x8, x12, x16, and x32 link widths.
PCIe's bandwidth gains over PCI are considerable. A single lane is capable of
transmitting 2.5Gbps in each direction, simultaneously. Add two lanes together to
form an x2 link and you've got 5 Gbps, and so on with each link width. These high
transfer speeds are good, good news, and will enable a new class of applications, like
SLI video card rendering.
the protocol itself. The following material will make an attempt to explain the details
of PCIe protocol, its layers and the functions of each of the layers in a brief way.
PCI Express is a high performance, general purpose I/O interconnect defined for a
wide variety of future computing and communication platforms.
A Root Complex (RC) denotes the root of an I/O hierarchy that connects the
5.2.2 Endpoints
Endpoint refers to a type of Function that can be the Requester or Completer of a PCI
Express transaction either on its own behalf or on behalf of a distinct non-PCI Express
device (other than a PCI device or Host CPU), e.g., a PCI Express attached graphics
controller or a PCI Express-USB host controller. Endpoints are classified as either
legacy, PCI Express, or Root Complex Integrated Endpoints.
A PCI Express to PCI/PCI-X Bridge provides a connection between a PCI Express fabric
and a PCI/PCI-X hierarchy.
PCI Express can be divided into three discrete logical layers: the Transaction Layer,
the Data Link Layer, and the Physical Layer. Each of these layers is divided into two
sections: one that processes outbound (to be transmitted) information and one that
processes inbound (received) information.
Note that a simpler form of packet communication is supported between two Data
Link Layers (connected to the same Link) for the purpose of Link management.
This is the top layer that interacts with the software above.
The Data Link Layer acts as an intermediate stage between the Transaction Layer and
the Physical Layer. Its primary responsibility is to provide a reliable mechanism for
exchanging Transaction Layer Packets (TLPs) between the two components on a Link.
Logical Sub-block
Takes care of Symbol Encoding, framing, data scrambling, Link initialization and
training, Lane to lane de-skew
Electrical Sub-block
The electrical sub-block section defines the physical layer of PCI Express 5.0 GT/s
that consists of a reference clock source, Transmitter, channel, and Receiver. This
section defines the electrical-layer parameters required to guarantee interoperability
among the above-listed PCI Express components. This section comprehends both 2.5
GT/s and 5.0 GT/s electricals. In many cases the parameter definitions between 2.5
and 5.0 GT/s are identical, even though their respective values may differ. However,
the need at 5.0 GT/s to minimize guardbanding, while simultaneously comprehending
all phenomena affecting signal integrity, requires that all the PCI Express system
components - Transmitter, Receiver, channel, and Refclk, be explicitly defined in the
specification. For this reason, each of these four components has a separate
specification section for 5.0 GT/s.
The goal of the PCI-SIG work group defining this next-generation interface was to
double the bandwidth of PCIe Gen 2, which is 5 gigatransfers per second (GT/s)
signaling but 4GT/s effective bandwidth after 8b/10b encoding overhead. The group
had two choices: either to increase the signaling rate to 10GT/s with 20 percent
encoding overhead or select a lower signaling rate (8GT/s) for better signal integrity
and reduced encoding overhead with a different set of challenges. The PCI-SIG
decided to go with 8GT/s and reduce the encoding overhead to offer approximately
7.99GT/s of effective bandwidth, approximately double that of PCIe Gen 2. The
increase in signaling rate from PCIe Gen 2's 5GT/s to PCIe Gen 3's 8GT/s provides a
sixty percent increase in data rate and the remainder of the effective bandwidth
increase comes from replacing the 8b/10b encoding (20 percent inefficiency) with
128b/130b coding (1-2 percent inefficiency). The challenge of moving from PCIe Gen 2
to Gen 3 is to accommodate the signaling rate where clock timing goes from 200ps to
125ps, jitter tolerance goes from 44ps to 14ps and the total sharable band (for SSC)
goes down from 80ps to 35ps. These are enormous challenges to overcome but the
PCI-SIG has already completed board, package, and system modeling to make sure
designers are able to develop systems that support these rates. The table below
highlights some key aspects of PCIe Gen 2 and Gen 3. The beauty of the Gen 3 solution
is that it will support twice the data rate with equal or lower power consumption than
PCIe Gen 2. Additionally, applications using PCIe Gen 2 would be able to migrate
seamlessly as the reference clock remains at 100MHz and the channel reach for
mobiles (8 inches), clients (14 inches), and volume servers (20 inches) stay the same.
More complex equalizers, such as decision feedback equalization, may be
implemented optionally for extended reach needed in a backplane environment. The
Gen 3 specification will enhance signaling by adding transmitter de-emphasis,
receiver equalization, and optimization of Tx/Rx Phase Lock Loops and Clock Data
Recovery. The Gen 3 specification also requires devices that support Gen 3 rate to
dynamically negotiate up or down to/from Gen 1 and Gen 2 data rates based on
signal/line conditions.
Goal: improve performance. Each successive generation doubles the bit rate of the
previous generation, and that holds true for Gen3, too, but there’s a significant
difference this time. Since the previous speed was 5.0 GT/s, the new speed would
normally have been 10.0 GT/s, but the spec writers considered a signal that used a
10GHz clock problematic because of the board design and signal integrity issues that
many vendors would face. Constrained to stay under that frequency, they were forced
to consider other options. The solution they chose was to move away from the 8b/10b
encoding scheme that PCIe and most other serial transports have used because it adds
a 20% overhead from the receiver’s perspective. Instead, they chose a modified
scrambling method that effectively creates a 128/130 encoding method. This gain in
efficiency meant that an increase in frequency to only 8.0GHz would be enough to
achieve a doubling of the bandwidth and meet this goal
Goal: allow the system to select how much system resource is allocated to a device.
This new optional set of registers allows functions to communicate their resources
size options to system software, which can then select the optimal size and
communicate that back to the function. Ideally, the software would use the largest
setting reported, since that would give the best performance, but it might choose a
smaller size to accommodate constrained resources. Currently, sizes from 1MB to
512GB are possible. If these registers are implemented, there is one capability
register to report the possible sizes, and one control register to select the desired size
for each BAR. Note that devices might report a smaller size by default to help them
be compatible in many systems, but using the smaller size would also reduce its
performance.
To allow software to set up PM policies, functions define two transition latency values
and every substate associates its max transition time (longest time it takes to enter
that substate from any other substate) with one of those.
Goal: support a much larger number of functions inside devices. For requesters and
completers, this means treating the device number value as though it was really just
an extension of the function field to give an 8-bit value for the function number.
Since the device number is no longer included, it’s always assumed to be 0. The spec
also defines a new set of optional registers that can be used to assign a function
group number to each function. Within an ARI device, several functions can be
associated with a single group number, and that can serve as the basis for arbitration
or access control.
References:
www.arstechnica.com
www.pcisig.com
www.pcstats.com
www.digitalhomedesignline.com
Search ✔
TUTORIALS
About the author:
SystemVerilog VCSMX Separate compilation example
Verification Emmanuelle Chu
is EDA support engineer
Constructs When I started to use VCSMX along with system Verilog, one main problem came up: I at Texas Instruments
Interface had to generate one executable for each program. (Nice Area, France). She
Coming up with VCSMX version 2008.12, the separate compile feature was introduced is with TI from 2004.
OOPS Emmanuelle Chu is an
to solve the problem; anyway the working model is quite strict. I used as a starting
Randomization point "switch" example from www.testbench.in to illustrate the separate compile master in Electronics
flow. The idea is to generate a partition of your program file that would be loaded and computers from
Functional Coverage ENSSAT.
when you launch your executable. A single image of your design is needed; if you
Assertion change your program file, you would only need to analyze it and generate a new
DPI partition. Please have a look to the Makefile provided along with the testcase. The
version 2008.12-2 of VCSMX was used to set up the testcase.
UVM Tutorial Report a Bug or Comment
1. Compile your DUT on This section - Your
VMM Tutorial
comp_dut input is what keeps
OVM Tutorial Testbench.in improving
2. Compile the testbench components for a given package. with time!
Easy Labs : SV
comp_pack
Easy Labs : UVM
Easy Labs : OVM - Analyze the code with vlogan..
- Generate shared object libraries for each package with VCS.
Easy Labs : VMM - Repeat these steps for each package.
AVM Switch TB
In VMM methodology, a class should be defined within a package, Driver.sv, packet.sv
VMM Ethernet sample and environment.sv are now system verilog packages.
Partition should also be generated for packages [separate compile feature steps]
6. Generate simv, which includes the DUT, program shell file, and top module to link
the DUT with the program shell file.
elab
7. Run simulations using the generated simv, specifying the partitions that need to be
loaded
run
Search ✔
TUTORIALS
Human beings reaction in this complex world of happenings varies widely with respect
Verilog to situations, surroundings, emotions, need, requirements, time frame, money,
Verification visualization, belief, education, knowledge, expertise, intuition and so on. Such
complex is the nature of human being and certainly there's no exception at work place
Verilog Switch TB too. Therefore it's cynical to say that the job being done by a Verification Engineer is
Basic Constructs simple & complete.
The quality of the job done by the verification engineer is directly proportional to his
or her psychological maturity and profoundness acquired, adopted and developed with
OpenVera age and experience.
Constructs
Switch TB Let's examine the psychology of the verification engineer by describing the definition
of Verification under three circumstances.
RVM Switch TB
RVM Ethernet sample
"Functional Verification is the process to prove that the RTL works as per the
specification"
Specman E "Functional verification is the process to find all the bugs present in the RTL design"
Interview Questions
"Functional Verification is the process to detect the defects and minimize the risks
associated with the residual defects"
1)
"Functional Verification is the process to prove that the RTL works as per the
specification"
Generally this definition is given by the RTL designers or the new verification
engineers with prior RTL design experience. The above definition sounds good if the
RTL designer itself is trying to verify his implementation . RTL designer intentions
would mostly revolve around the point to prove that the RTL meets the specification.
RTL designer will exercise only those inputs for which the correct results are obtained
and are specified in the specification and the DUT can still contain bugs which will not
be visible.
2)
"Functional verification is the process to find all the bugs present in the RTL design"
This definition sounds good epically if the main aim of the verification engineer is to
prove that the RTL work for what it's supposed to do and not what is not supposed to
do. This type of psychology would bring out the most of the bugs in the RTL. This goal
is impossible to achieve.
3)
"Functional Verification is the process to detect the defects and minimize the risks
associated with the residual defects"
This definition appears to sound realistic. Practically, if at any point, the RTL
development starts, the verification should start and keep in track the number of bugs
being detected while correcting.
At some stage of a planned verification, there would be a stage where no bugs are
identified after many days or weeks or sometimes months of verification which
statistically allows you to conclude that the RTL is "good enough" to be released to
next step. i.e. there may still exist some bugs undetected, but the risk associated with
the residual defects is not very high or are tolerable.
From the above three definitions, we can understand that the psychology of a
verification engineer plays a vital role throughout the ASIC development cycle.
Verification Engineer requires technical skills similar to RTL designers, but Verification
engineers need to acquire other skills, as well.
Most engineers that I've talked to over the years believe that the mind-set and
personality of a good Verification engineer are different from those of a good RTL
designers. For example Verification engineer are more experimental then RTL
designers.
Keen Observation
Detective Skills
Deduction skills
Destructive Creativity and Negative Thinking
Understanding the DUT as an integration of its parts
Cynical but Affable Attitude
Organized, Flexible and Patience at Job
Objective and Neutral Attitude
Discipline and Perseverance
Communication Skills
Learning from Past
Keen Observation
The Verification engineer must possess the qualities of an 'eye for detail'. A keen
observation is the prime quality any Verification engineer must possess. Not all bugs
are visible clearly to the naked eye. With keen observation, the Verification engineer
can easily identify or detect many critical bugs. Verification engineer should learn
how to look for details, how to analyze the things from different possible dimensions.
The more observant a verification engineer is, the more likely he is detecting more
bugs.
Detective Skills
Ideally the Design under development would be documented before, after and
throughout the development process. Unfortunately, there is every chance of not
updating the documentation (specification, defect reports etc) due to time and
resource constraints.
Deduction Skills
A Verification engineer with deduction skills is also likely to be good at issue solving.
Deduction skill is an ability to analyze the meanings of the signs and deriving of a
conclusion by reasoning. It's a logical thinking, which helps a Verification engineer to
differentiate a bug from a false one. Deduction skills may come from practice of
cognitive information processing, power of interpretation and can help a Verification
engineer in differencing and decision making.
Deduction skills play major role while debugging. Not all the verification engineers
can debug an issue at same speed. Looking at some waveform signals, log messages,
he has to isolate or locate it. In Verification life cycle, everything can be planned and
can meet the schedule in time except debugging. Time spent in debugging is
unpredictable and cannot be planned ahead.
A creative oriented but destructive approach is necessary while verifying a RTL by the
Verification engineer to make the RTL Design evolve more robustly and reliably.
Negative Thinking is a art. While mentioning the risks involved in the project, a
Verification engineer has to consider all the things that can go wrong. Training the
mind to think negatively in required situations helps Verification engineer develop an
efficient contingency plan.
A word of caution here; distractive skills are useful only for specific situations. A
Verification engineer has to be smart enough to identify such situations and wear an
appropriate thinking hat to deal with the situation.
The RTL design is a culmination of lines of code interacting with data through user
interfaces. It is an integration of separate group of code interacting with other groups
assembled together to function as a whole chip. The developers might be working on
a respective piece of code module focusing more on those modules under work, at a
time.
It is no wonder if the developer sometimes may not even know the complete workflow
of the RTL and not necessary too. Whereas, in the case of a Verification engineer,
being the rider of the DUT, should understand and know about the complete
specifications of the DUT.
The Verification engineer may not be the best expert on any one module of the RTL
but definitely he/she should gain expertise on the overall operation of the RTL
Design. In fact, the Verification engineer should possess a 'Systems' view of the RTL
design because they are the only people to see and verify the complete functionality
of interdependent modules and compatibility.
Irrespective of the nature of the RTL design, the Verification engineer need to be
tenacious in questioning even the smallest ambiguity until it is proved.
There may arise some situations during the course of verification , a large number of
bugs might be encountered unusually which might compel to further delay in RTL
freezing. This may lead to heat up the relation between the Verification engineer and
RTL design teams. The Verification engineer should balance this relationship not at
the cost of the bugs but by convincing and upholding their intentions to "assault the
RTL design but not the RTL developers".
Verification engineer must remember the fact that not all the tests planned are
performed completely and some tests dependent on other tests has to be blocked for
later testing. We manage ourselves, our tasks, so that we make the most of our time.
Verification engineer have to juggle a lot of tasks.
Nobody would like to hear and believe bad news, right? Well, Verification engineer
are sometimes viewed as messengers of bad news in a team. No wonder, how good
the Verification engineer is (meaning very negative) and brilliant in doing his job
(identifying bugs-no one likes to do it but most human beings are taken for granted to
be naturally very good at it, at least from childhood), he/she might always be a
messenger of communicating the bad part, which, the creators (developers) doesn't
like it.
The Verification engineer must be able to deal with the situation where he/she is
blamed for doing his/her job (detecting bugs) too good. The Verification engineer's
jobs must be appreciated and the bugs should be welcomed by the RTL design team
because every potential bug found by the Verification engineer would mean a
reduction of one bug that would potentially might have been encountered in later
stage.
Irrespective of the negative aspects of doing such a highly skillful job, the role of a
Verification engineer is to report honestly every known bug encountered in the
product with always an objective and a neutral attitude.
One obvious aspect of verification is that it can be extremely repetitive and may
require a lot of manual effort. Consider the following situations:
A Verification engineer is struck with a bug that is not reproducible at all the
instances. In order to reproduce the bug he goes through the whole series of steps
again and again.
As part of a daily routine, a Verification engineer has been asked to collect data
about test cases executed, bugs reported, etc.
There can be numerous examples that prove the reiterative nature of the job.
A very predictable reaction to this repetition is to simply get tired of the job. But soft
skills include the psychological tools to persevere, and to find ways to make effort
more productive and interesting. This attitude difference helps a Verification
engineer maintain focus and higher levels of quality work. It brings the ability to carry
out task at hand in spite of difficulty.
Communication Skills
Communication skills form the necessary ingredients for success in any profession.
Communication is something that we always do in our personal lives as well as
professional life. Communication is a very basic human skill and one cannot go very far
without it. Communication in this context does not involve any body language; so it's
the pure word power, which rules the situation. Though most of us agree that these
skills are important, very few of us give these skills a high enough priority. For a VE,
both verbal and written communication is crucial.
If your written communication is bad, you'll miss the salient points - the audience
won't know the important stuff - or you'll put the audience to sleep. This means your
bug reports will bounce back as "invalid" / "unable to reproduce" / "won't fix."
Keep learning from past experience and try not getting caught in any mistakes that
have been made earlier. A common saying is "Never repeat the same mistake again". A
verification engineer should know not only his mistakes, but also the RTL Designers
mistakes. If RTL designers does the same mistake, Verification engineer past
experience on catching the same mistake increases the possibility of the finding the
mistake easily.
Stupid:
Absurdly dumb things that just happen.
Simple:
Mistakes that are avoidable but your sequence of decisions made inevitable.
Involved:
Mistakes that are understood but require effort to prevent.
Complex:
Mistakes that have complicated causes and no obvious way to avoid next time.
Search ✔
TUTORIALS
About the author:
SystemVerilog Graphical Test Bench Generation
Verification Donna Mitchell
is Vice President of
Constructs Test bench code is often difficult to understand, even when written using modular Marketing and Co-
Interface programming techniques, because of the large amount of parallel activity occurring in Founder of SynaptiCAD
the test bench that is not apparent when just reading through the code. However, Sales Inc. Mitchell's
OOPS industry experience
when that same parallel activity is displayed as waveforms in a timing diagram the
Randomization interaction between the signals is obvious from just glancing at the timing diagram. includes 20 years of
Timing diagrams allow a much clearer and concise description of the interaction of hardware and software
Functional Coverage development.
parallel processes and signal activity than can be achieved by writing code. A
Assertion graphical representation also facilitates the collaboration of many engineers on a
DPI single test bench by removing the need to interpret source code. Any engineer
familiar with the design specifications is able to look at a given timing diagram and
UVM Tutorial have an immediate understanding of what the transactor does, dramatically Report a Bug or Comment
simplifying test bench maintenance. on This section - Your
VMM Tutorial
input is what keeps
OVM Tutorial There are several tools on the market that can take basic waveforms and generate Testbench.in improving
Easy Labs : SV simple VHDL and Verilog models. This article will discuss the tools offered by with time!
SynaptiCAD, because they offer three different levels of test bench generation ranging
Easy Labs : UVM from simple stimulus test benches, test benches that monitor system reaction during
Easy Labs : OVM simulation, to full bus-functional models that behaviorally model the outside system.
We will show examples of timing diagrams and some of the code that they can
Easy Labs : VMM generate.
AVM Switch TB
VMM Ethernet sample Level 1: Basic Stimulus Generation
The most basic of the graphical testbench generation tools can take drawn waveforms
Verilog and generate VHDL or Verilog stimulus. This level of test bench generation is great for
Verification generating quick small test benches, because the temporal relationships between
edges are easier to see in a graphical timing diagram then in raw VHDL or Verilog
Verilog Switch TB code. This simple graphical test bench generation can be found in many timing
Basic Constructs diagram editors and several graphical simulator-debugging environments. SynaptiCAD
offers it in their WaveFormer Pro timing diagram editor and in their BugHunter Pro
simulation debugging environment.
OpenVera Below is an image of a simple timing diagram that was drawn in WaveFormer Pro. This
Constructs shows how different types of signals, buses, and clocks will generate stimulus code.
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Once a timing diagram is finished, the test bench code can be generated via a simple
In the generated code, notice that the clock is a parameterized process. Not all tools
generate clock signals this way, but it makes it easy for the user to modify the
operation of the test bench by changing the values of the clock variables.
WaveFormer also supports complex data types and user-defined types. Notice that
SIG1 has a VHDL type of integer. In WaveFormer, the VHDL and Verilog types of signals
can be changed using the Signals Properties dialog. VHDL user-defined types can also
be entered through the same interface as demonstrated by the SIG3 signal.
For larger test benches, the waveform data can be imported from an outside source
like a logic analyzer, simulator, or spreadsheet. For example, if you are designing a
new ASIC to upgrade an existing communications system, then you can use a logic
analyzer to capture stimulus vectors from the communications system and use
WaveFormer to translate the data into a VHDL test bench to test the new ASIC design.
It is important to investigate whether the test bench tool you are using can read the
type of files that your waveform data is in.
The next level up in graphical test bench generation is to add elements to the timing
diagram that will generate code to check the behavior of the model under test (MUT)
during simulation. In the SynaptiCAD tool line, you can add the Reactive Test Bench
Option to any of the tools that support basic stimulus generation.
In the timing diagram, the user draws both the stimulus waveforms (black) and the
expected output of the model under test (blue waveforms). Samples are added to the
blue expected waveforms to generate specific tests at those points in the diagram.
During simulation if the actual value is different from the expected value at the
sample point, then a report will be generated that describes the discrepancy between
the expected and actual value from the model under test.
Below is a picture of the generated code for the sample that is used to check the
output of the read cycle.
Often reactive test bench tools include a method for repeating sections of the
waveforms. With SynaptiCAD’s tools the user places marker lines on the diagram to
define the beginning and ending of loops. Loops can also depend on the sampled
values of expected output from the model under test. This way the test bench can be
made to "react" to the behavior of the model under test during simulation.
Reactive test bench generation often allows the option of creating "clock-based" test
benches as well as the "time-based" test benches currently supported by the stimulus
based generation models. Clock-based test benches delay in clock cycles instead of
times, allowing the user to change his clock frequency without needing to change his
timing diagram. Clock-based test benches are also required when testing using high-
speed "cycle-based" simulators.
As your test benches become more and more complicated, it will become more
difficult to model them using a single timing diagram as described in the previous two
levels. SynaptiCAD offers TestBencher Pro to overcome this problem. At the time of
this writing TestBencher is the only graphical test bench generator that can take
multiple timing diagrams and generate a complete bus functional model from them.
Once the transactions are defined, the user writes a sequencer process to apply the
timing diagrams to the model under test. Inside the sequencer process the user can
write behavioral VHDL or Verilog code to pass in variables and process information to
the transactions. TestBencher also has a graphical interface for assisting the user in
writing the apply calls. Below is an example of a sequencer process that repetitively
applies a write transaction followed by a read transaction. Each time the loop is
performed the delay value is changed so that model is tested over different delay
times.
// Sequencer Process
real delay0; // delay0 will serve as the index and the delay value
initial
begin
for (delay0 = 32.0; delay0 > 5.0; delay0 = delay0 - 5.0)
begin
// Apply_Tbwrite( addr , data , $realtobits(delay0_min) );
Apply_Tbwrite( 'hF0 , 'hAE , $realtobits(delay0) );
// Apply_tbread( addr , data , $realtobits(delay0_min) );
Apply_tbread( 'hF0 , 'hAE , $realtobits(delay0));
end
Abort_tbglobal_clock;
$fclose(logfile);
end
You can free yourself from the time-consuming process of writing Verilog and VHDL
test benches by hand and instead generate them graphically from timing diagrams
using a timing diagram editor. By using timing diagrams, the engineer can work at a
higher level abstraction, free from the tedious details of the underlying code. This
graphical representation facilitates the collaboration of many engineers on a single
test bench by removing the need to interpret HDL source code. Any engineer familiar
with the design specifications is able to look at a given timing diagram and have an
immediate understanding of what the transaction is doing. This level of abstraction
also provides a great aid in terms of maintainability. The first step in choosing a test
bench generator is to determine the complexity of your expected test bench and then
to pick a tool that can generate that code. This article described the functionality of
test bench tools offered by SynaptiCAD. If you would like to experiment with these
tools you can find more information on the http://www.syncad.com/syn_tb_diff.htm
page of the SynaptiCAD web site.
Search ✔
TUTORIALS
About the author:
SystemVerilog Verilog Basic Examples
Verification Nithin Singani
is perusing Master of
Constructs AND GATE Technology in VLSI &
Interface Embedded Systems in
Truth Table Manipal University,
OOPS India.
Randomization
Functional Coverage
Assertion Report a Bug or Comment
on This section - Your
DPI input is what keeps
UVM Tutorial Testbench.in improving
with time!
VMM Tutorial
OVM Tutorial Verilog design
Easy Labs : SV
//in data flow model
Easy Labs : UVM module and_gate(
Easy Labs : OVM input a,b,
output y);
Easy Labs : VMM
AVM Switch TB //Above style of declaring ports is ANSI style.Verilog2001 Feature
VMM Ethernet sample
assign y = a & b;
endmodule
Verilog
Verification TestBench
Verilog Switch TB module tb_and_gate;
Basic Constructs
reg A,B;
wire Y;
OpenVera
and_gate a1 (.a(A) ,.b(B),.y(Y));
Constructs
Switch TB //Above style is connecting by names
RVM Switch TB initial begin
RVM Ethernet sample A =1'b0;
B= 1'b0;
#45 $finish;
end
Specman E
Interview Questions always #6 A =~A;
always #3 B =~B;
always @(Y)
$display( "time =%0t \tINPUT VALUES: \t A=%b B =%b \t output value
Y =%b",$time,A,B,Y);
endmodule
output
XOR GATE
Truth Table
Verilog design
module xor_gate (
input a,b,
output y);
endmodule
TestBench
module tb_and_gate;
reg A,B;
wire Y;
xor_gate a1 (.a(A) ,.b(B),.y(Y));
initial begin
A =1'b0;
B= 1'b0;
#45 $finish;
end
always #6 A =~A;
always #3 B =~B;
always @(Y)
$display( "time =%0t \tINPUT VALUES: \t A=%b B =%b \t output value Y
=%b",$time,A,B,Y);
endmodule
output
OR GATE
Truth Table
Verilog design
always @(a,b)
y = a |b;
endmodule
TestBench
module tb_and_gate;
reg A,B;
wire Y;
or_gate a1 (.a(A) ,.b(B),.y(Y));
initial begin
A =1'b0;
B= 1'b0;
#45 $finish;
end
always #6 A =~A;
always #3 B =~B;
always @(Y)
$display( "time =%0t \tINPUT VALUES: \t A=%b B =%b \t output value Y
=%b",$time,A,B,Y);
endmodule
output
Half Adder
Truth Table
Verilog design
module half_adder(
input a,b,
output sum,carry);
assign sum = a^b;
assign carry = a & b;
endmodule
TestBench
module tb_half_adder;
reg A,B;
wire SUM,CARRY;
half_adder HA (.a(A) ,.b(B),.sum(SUM),.carry(CARRY))
initial begin
A =1'b0;
B= 1'b0;
#45 $finish;
end
always #6 A =~A;
always #3 B =~B;
always @(SUM,CARRY)
$display( "time =%0t \tINPUT VALUES: \t A=%b B =%b \t output value SUM =%b CARRY
=%b ",$time,A,B,SUM,CARRY);
endmodule
output
Full Adder
Verilog design
module full_adder(
input a,b,cin,
output reg sum,cout);
always @(*) begin
sum = a^b^cin;
cout = (a&b)+(b&cin)+(cin&a);
end
endmodule
TestBench
module tb_full_adder;
reg A,B,CIN;
wire SUM,COUT;
full_adder FA (.a(A) ,.b(B),.sum(SUM),.cin(CIN),.cout(COUT));
initial begin
A =1'b0;
B= 1'b0;
CIN = 1'b0;
#45 $finish;
end
always #6 A =~A;
always #3 B =~B;
always #12 CIN = ~CIN;
always @(SUM,COUT)
$display( "time =%0t \tINPUT VALUES: \t A =%b B =%b CIN =%b \t output value
SUM
=%b COUT =%b ",$time,A,B,CIN,SUM,COUT);
endmodule
output
module ripple_carry(a,b,cin,cout,sum);
parameter N=4;
input [N-1 :0] a,b;
input cin;
output [N-1:0]sum;
output cout;
wire [N:0]carry;
assign carry[0]=cin;
//generate statement without using label is verilog-2005 feature. Generate
statement is verilog-2001 feature.
genvar i;
generate for(i=0;i<N;i=i+1) begin
full_adder FA (.a(a[i]),.b(b[i]),.cin(carry[i]),.sum(sum[i]),.cout(carry[i+1]));
end
endgenerate
assign cout = carry[N];
endmodule
TestBench Using $random
module tb_ripple_carry;
parameter N=4;
reg [N-1:0]A,B;
reg CIN;
wire [N-1:0]SUM;
wire COUT;
ripple_carry RCA(.a(A),.b(B),.cin(CIN),.sum(SUM),.cout(COUT));
initial begin
A= 4'b0000;
B= 4'b0000;
CIN =1'b0;
repeat(10)
input_generate(A,B,CIN);
#45 $finish;
end
task input_generate;
output [N-1:0]A_t,B_t;
output CIN_t;
begin
#4;
A_t = $random % 4;
//Above statement will generate Random values from -3 to +3.
B_t = $random % 4;
CIN_t =$random;
end
endtask
task display;
input [N-1:0] A_td,B_td,SUM_td;
input CIN_td,COUT_td;
$strobe("Time =%0t \t INPUT VALUES A=%b B=%b CIN =%b \t OUTPUT VALUES SUM
=%b COUT =%b",$time,A_td,B_td,CIN_td,SUM_td,COUT_td);
endtask
always@(SUM,A,COUT)
$display(A,B,SUM,CIN,COUT);
endmodule
output
Time =0 INPUT VALUES A=0000 B=0000 CIN =0 OUTPUT VALUES SUM =0000 COUT =0
Time =4 INPUT VALUES A=0000 B=1101 CIN =1 OUTPUT VALUES SUM =1110 COUT =0
Time =8 INPUT VALUES A=1111 B=0001 CIN =1 OUTPUT VALUES SUM =0001 COUT =1
Time =12 INPUT VALUES A=1101 B=1110 CIN =1 OUTPUT VALUES SUM =1100 COUT =1
Time =16 INPUT VALUES A=0001 B=0010 CIN =1 OUTPUT VALUES SUM =0100 COUT =0
Time =20 INPUT VALUES A=0001 B=0000 CIN =1 OUTPUT VALUES SUM =0010 COUT =0
Time =24 INPUT VALUES A=1110 B=1101 CIN =0 OUTPUT VALUES SUM =1011 COUT =1
Time =28 INPUT VALUES A=0001 B=1111 CIN =0 OUTPUT VALUES SUM =0000 COUT =1
Time =32 INPUT VALUES A=0011 B=0010 CIN =0 OUTPUT VALUES SUM =0101 COUT =0
Time =36 INPUT VALUES A=0000 B=1101 CIN =0 OUTPUT VALUES SUM =1101 COUT =0
Multiplexer(2:1)
Truth Table
Verilog design
module mux21(
input a,b,sel,
output y);
endmodule
TestBench
module tb_mux21;
reg A,B,SEL;
wire Y;
mux21 MUX (.a(A) ,.b(B),.sel(SEL),.y(Y));
initial begin
A =1'b0;
B= 1'b0;
SEL =1'b0;
#45 $finish;
end
always #6 A =~A;
always #3 B =~B;
always #5 SEL = ~SEL;
always @(Y)
$display( "time =%0t \tINPUT VALUES: \t A=%b B =%b SEL =%b \t output value Y =%b
",$time,A,B,SEL,Y);
endmodule
output
Multiplexer(4:1)
Verilog design
module mux41(
input i0,i1,i2,i3,sel0,sel1,
output reg y);
always @(*) //It includes all Inputs. You can use this instead of specifying all
inputs in //sensivity list.Verilog-2001 Feature
begin
case ({sel0,sel1})
2'b00 : y = i0;
2'b01 : y = i1;
2'b10 : y = i2;
2'b11 : y = i3;
endcase
end
endmodule
TestBench
module tb_mux41;
reg I0,I1,I2,I3,SEL0,SEL1;
wire Y;
mux41 MUX (.i0(I0),.i1(I1),.i2(I2),.i3(I3),.sel0(SEL0),.sel1(SEL1),.y(Y));
initial begin
I0 =1'b0;
I1= 1'b0;
I2 =1'b0;
I3 =1'b0;
SEL0 =1'b0;
SEL1 =1'b0;
#45 $finish;
end
always #2 I0 = ~I0;
always #4 I1 =~I1;
always #6 I2 =~I1;
always #8 I3 =~I1;
always #3 SEL0 = ~SEL0;
always #3 SEL1 = ~SEL1;
always @(Y)
$display( "time =%0t INPUT VALUES: \t I0=%b I1 =%b I2 =%b I3 =%b SEL0 =%b SEL1 =%b
\t output value Y =%b ",$time,I0,I1,I2,I3,SEL0,SEL1,Y);
endmodule
output
Encoder(8:3)
Verilog design
module encoder83(
input en,
input [7:0]in,
output reg [2:0]out);
always@(*)
begin
if(!en) //Active low enable
out = 0;
else begin
case ({in})
8'b0000_0001 : out =3'b000;
8'b0000_0010 : out =3'b001;
8'b0000_0100 : out =3'b010;
8'b0000_1000 : out =3'b011;
8'b0001_0000 : out =3'b100;
8'b0010_0000 : out =3'b101;
8'b0100_0000 : out =3'b110;
8'b1000_0000 : out =3'b110;
default : out =3'bxxx;
endcase
end
end
endmodule
module tb_encoder83;
reg en;
reg [7:0]in;
wire [2:0] out;
encoder83 ENC (.en(en),.in(in),.out(out));
initial begin
en =0;
in =0;
repeat(10)
random_generation(in,en);
#45 $finish;
end
task random_generation;
output [7:0]in_t;
output en_t;
begin
#4;
in_t = $random % 8;
en_t =$random;
end
endtask
task display;
input en_t;
input [7:0]in_t;
input [2:0]out_t;
$display("time =%0t \t INPUT VALUES \t en =%b in =%b \t OUTPUT VALUES out
=%b",$time,en_t,in_t,out_t);
endtask
always@(out)
display(en,in,out);
endmodule
output
Priority Encoder(8:3)
Verilog design
module priority_enco(
input en,
input [3:0]in,
output reg v,
output reg [1:0]out );
integer i;
always@(*) begin
if(!en) begin
out = 2'b00;
v =1'b0;
end
else
begin :block1
for (i=3; i>=0; i= i-1) begin
//Priority Logic. each Time It will check Whether the MSB bit is active, If so
it will break //the loop. Otherwise It will decrement and continue the same
if (in[i]==1'b1) begin
case (i)
3: begin out = 2'b11; v= 1'b1; end
2: begin out = 2'b10; v= 1'b1; end
1: begin out = 2'b01; v= 1'b1; end
0: begin out = 2'b00; v= 1'b1; end
default :begin out = 2'bxx; v= 1'bx; end
endcase
disable block1;
//Disable statement is synthesizible
end
end
end
end
endmodule
module tb_prior_enco ;
reg en;
reg [2:0]in;
wire [1:0] out;
wire v;
priority_enco PRIOR_ENC (.en(en),.in(in),.out(out),.v(v));
initial begin
en =0;
in =0;
repeat(19)
random_generation(in,en);
#65 $finish;
end
task random_generation;
output [3:0]in_t;
output en_t;
begin
#4;
in_t = $random % 4;
en_t =$random;
end
endtask
task display;
input en_t;
input [3:0]in_t;
input [1:0]out_t;
input v_t;
$display("time =%0t \t INPUT VALUES \t en =%b in =%b \t OUTPUT VALUES out =%b
v =%b",$time,en_t,in_t,out_t,v_t);
endtask
always@(out)
display(en,in,out,v);
endmodule
output
Decoder(8:3)
Verilog design
module decoder38(
input en,
input [2:0]in,
output reg [7:0]out);
always@(*)
begin
if(!en)
out = 0;
else 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'bxxxx_xxxx;
endcase
end
end
endmodule
module tb_decoder38;
reg en_tb;
reg [2:0]in_tb;
wire [7:0] out_d;
reg [7:0] out_tb;
decoder38 DEC (.en(en_tb),.in(in_tb),.out(out_d));
initial begin
en_tb =0;
in_tb =0;
repeat(10)
random_generation(in_tb,en_tb) ;
#45 $finish;
end
//Below Block is used to generate expected outputs in Test bench only. These
outputs //are used to compare with DUT output. You have Checker task (ScoreBoard
in SV), for //that you need Reference output
always@(in_tb,en_tb)
begin
if(!en_tb)
out_tb = 0;
else begin
case ({in_tb})
3'b000 : out_tb = 8'b0000_0001;
3'b001 : out_tb = 8'b0000_0010;
3'b010 : out_tb = 8'b0000_0100;
3'b011 : out_tb = 8'b0000_1000;
3'b100 : out_tb = 8'b0001_0000;
3'b101 : out_tb = 8'b0010_0000;
3'b110 : out_tb = 8'b0100_0000;
3'b111 : out_tb = 8'b1000_0000;
default : out_tb = 8'bxxxx_xxxx;
endcase
end
end
task random_generation;
output [2:0]in_t;
output en_t;
begin
#4;
in_t = $random % 3;
en_t =$random;
end
endtask
task checker;
//In this block reference value and generated output are compared
input [7:0]outd_t;
input [7:0]outtb_t;
begin
if(outd_t === outtb_t)
$display("time =%0t \t DUT VALUE =%b TB VALUE =%b \tDUT and TB VALUES
ARE MATCHED ",$time,outd_t,outtb_t);
else
$display("time =%0t \tDUT and TB VALUES ARE NOT MATCHED ",$time);
end
endtask
always@(out_d,out_tb)
checker(out_d,out_tb);
endmodule
time =0 DUT VALUE =00000000 TB VALUE =00000000 DUT and TB VALUES ARE
MATCHED
time =4 DUT VALUE =00000100 TB VALUE =00000100 DUT and TB VALUES ARE
MATCHED
time =8 DUT VALUE =00000001 TB VALUE =00000001 DUT and TB VALUES ARE
MATCHED
time =16 DUT VALUE =00000000 TB VALUE =00000000 DUT and TB VALUES ARE
MATCHED
time =20 DUT VALUE =00000001 TB VALUE =00000001 DUT and TB VALUES ARE
MATCHED
time =28 DUT VALUE =00000000 TB VALUE =00000000 DUT and TB VALUES ARE
MATCHED
time =40 DUT VALUE =00000001 TB VALUE =00000001 DUT and TB VALUES ARE
MATCHED
D-Latch
Verilog design
module d_latch(
input en,d,
output reg q);
always@(en,d)
begin
if(en)
q <= d;
end
endmodule
TestBench
module tb_latch;
reg en,d;
wire q;
d_latch DLATCH (.en(en) ,.d(d) ,.q(q));
initial begin
en =1'b0;
d =1'b1;
#45 $finish;
end
always #6 en =~ en;
always #3 d =~d;
always@( q , en )
$display("time =%0t \t INPUT VALUES \t en =%b d =%b \t OUTPUT VALUES
q=%b",$time,en,d,q);
endmodule
output
D-FlipFlop(Asynchronous Reset)
Verilog design
module d_ff (
input clk,d,rst_n,
output reg q);
endmodule
TestBench
module tb_dff;
reg RST_n, CLK,D;
wire Q;
d_ff DFF (.clk(CLK) ,.rst_n(RST_n) ,.q(Q),.d(D));
initial begin
RST_n = 1'b0;
CLK =1'b0;
D =1'b0;
#5 RST_n = 1'b1;
#13 RST_n = 1'b0;
#7 RST_n = 1'b1;
#45 $finish;
end
always #3 CLK = ~CLK;
always #6 D = ~D;
always @(posedge CLK ,negedge RST_n)
$strobe("time =%0t \t INPUD VALUES \t D =%b RST_n =%b \t OUDPUD VALUES Q
=%d",$time,D,RST_n,Q);
//$strobe will execute as a last statement in current simulation.
endmodule
output
D-FlipFlop(Synchronous Reset)
Verilog design
module d_ff (
input clk,d,rst_n,
output reg q);
//In Synchronous Reset, Reset condition is verified wrt to clk.Here It is verified at
every //posedge of clk.
always@(posedge clk )
begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end
endmodule
TestBench
module tb_dff;
reg RST_n, CLK,D;
wire Q;
d_ff DFF (.clk(CLK) ,.rst_n(RST_n) ,.q(Q),.d(D));
initial begin
RST_n = 1'b0;
CLK =1'b0;
D =1'b1;
#5 RST_n = 1'b1;
#7 RST_n = 1'b0;
#7 RST_n = 1'b1;
#45 $finish;
end
always #4 CLK = ~CLK;
always #6 D = ~D;
always @(posedge CLK )
$strobe("time =%0t \t INPUT VALUES \t D =%b RST_n =%b \t OUDPUT VALUES Q
=%d",$time,D,RST_n,Q);
endmodule
output
T-FlipFlop
Verilog design
module t_ff (
input clk,t,rst_n,
output reg q);
always@(posedge clk ,negedge rst_n)
begin
if (!rst_n)
q <= 1'b0;
else if(t)
q <= ~q;
else
q <= q;
end
endmodule
TestBench
module tb_tff;
reg RST_n, CLK,T;
wire Q;
t_ff TFF (.clk(CLK) ,.rst_n(RST_n) ,.q( Q ),.t(T));
initial begin
RST_n = 1'b0;
CLK =1'b0;
T =1'b0;
#5 RST_n = 1'b1;
#13 RST_n = 1'b0;
#7 RST_n = 1'b1;
#45 $finish;
end
always #3 CLK = ~CLK;
always #6 T = ~T;
always @(posedge CLK ,negedge RST_n)
$strobe("time =%0t \t INPUT VALUES \t T =%b RST_n =%b \t OUTPUT VALUES Q
=%d",$time,T,RST_n,Q);
endmodule
output
3-Bit Counter
//Used Structural Model in RTL and Behavior Model in Test bench
Verilog design
module t_ff(
output reg q,
input t, rst_n, clk);
always @ (posedge clk or negedge rst_n)
if (!rst_n) q <= 1'b0;
else if (t) q <= ~q;
endmodule
module counter (
output [2:0] q,
input rst_n, clk);
wire t2;
t_ff ff0 ( q[0], 1'b1, rst_n, clk);
t_ff ff1 ( q[1], q[0], rst_n, clk);
t_ff ff2 ( q[2], t2, rst_n, clk);
and a1 (t2, q[0], q[1]);
endmodule
TestBench
module tb_counter_3bit;
reg clk,rst_n;
wire [2:0] q;
reg [2:0] count;
counter CNTR (.clk(clk),.rst_n(rst_n),.q(q));
initial begin
clk <= 1'b0;
forever #5 clk <= ~ clk;
end
initial
begin
rst_n <= 0;
@(posedge clk);
@(negedge clk);
rst_n <= 1;
repeat (10) @(posedge clk);
$finish;
end
//Below always block represents the 3-bit counter in behavior style.
//Here it is used to generate reference output
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 0;
else
count <= (count + 1);
end
always @( q ) scoreboard(count);
//Below task is used to compare reference and generated output. Similar to score
board //in SV Test bench
task scoreboard;
input [2:0]count;
input [2:0] q;
begin
if (count == q)
$display ("time =%4t q = %3b count = %b match!-:)",
$time, q, count);
else
$display ("time =%4t q = %3b count = %b <-- no match",
$time, q, count);
end
endtask
endmodule
output
It will have following sequence of states. It can be implemented without FSM also.
000
001
011
010
110
111
101
100
Verilog Code
module greycode_counter_3bit(
input clk,rst_n,
output reg [2:0]count);
reg [2:0] pr_state,nx_state;
parameter cnt0 =3'b000,
cnt1 =3'b001,
cnt2 =3'b011,
cnt3 =3'b010,
cnt4 =3'b110,
cnt5 =3'b111,
cnt6 =3'b101,
cnt7 =3'b100;
always@(posedge clk, negedge rst_n) begin // FIRST ALWAYS BLOCK
//This always block is used for State assignment. Sequential always block.
if(!rst_n)
pr_state <= cnt0;
else
pr_state <=nx_state;
end
always@(pr_state) begin //SECOND ALWAYS BLOCK
//this always block used for next state logic, Combinational
case (pr_state)
cnt0 : nx_state = cnt1;
cnt1 : nx_state = cnt2;
cnt2 : nx_state = cnt3;
cnt3 : nx_state = cnt4;
cnt4 : nx_state = cnt5;
cnt5 : nx_state = cnt6;
cnt6 : nx_state = cnt7;
cnt7 : nx_state = cnt0;
default : nx_state = cnt0;
endcase
end
always@(posedge clk ,negedge rst_n) begin //THIRD ALWAYS BLOCK
//this always block used for output assignment,Sequential
if(!rst_n)
count <= 3'b000;
else begin
case (pr_state)
cnt0 : count <= 3'b000;
cnt1 : count <= 3'b001;
cnt2 : count <= 3'b011;
cnt3 : count <= 3'b010;
cnt4 : count <= 3'b110;
cnt5 : count <= 3'b111;
cnt6 : count <= 3'b101;
cnt7 : count <= 3'b100;
default :count <=3'bxxx;
endcase
end
end
endmodule
TestBench
module tb_greycode_counter;
reg clk,rst_n;
wire [2:0] count;
greycode_counter_3bit COUNTER(.clk(clk),.rst_n(rst_n),.count(count));
initial begin
clk =1'b0;
rst_n = 1'b0;
@(posedge clk);
@(posedge clk);
rst_n = 1'b1;
repeat(9) @(posedge clk);
$finish;
end
always #5 clk = ~clk;
always@(count)
$display("time =%0t \t rst_n =%b count =%b",$time,rst_n,count);
endmodule
output
Divide by 2 clk
module div_2clk(
input clk,rst_n,
output reg clk_out);
always@(posedge clk,negedge rst_n) begin
if(rst_n)
clk_out <= 1'b0;
else
clk_out <= ~clk_out;
end
endmodule
TestBench
module tb_div_2clk;
reg clk,rst_n;
wire clk_out;
div2_clk clkby2 (.clk(clk),.rst_n(rst_n),.clk_out(clk_out));
initial begin
clk =1'b0;
rst_n =1'b0;
@(posedge clk);
@(posedge clk);
rst_n = 1'b1;
repeat(15) @(posedge clk);
//It will run till 15 clock cycles
$finish;
end
always #5 clk = ~clk;
always @(clk_out)
$display("time = %0t \t Input clk =%b \t output clk=%b ",$time,clk,clk_out);
endmodule
output
Divide by 3 clk
Verilog Code
module div_3clk(
input clk,rst_n,
output clk_by_3);
parameter ST10 =2'b00,
ST11 =2'b01,
ST12 = 2'b10;
parameter ST20 =2'b00,
ST21 =2'b01,
ST22 = 2'b10;
reg clk_temp1,clk_temp2;
reg [1:0] pr_state1,nx_state1;
reg [1:0] pr_state2,nx_state2;
always@(posedge clk ,negedge rst_n) begin
if(!rst_n)
pr_state1 <= ST10;
else
pr_state1 <= nx_state1;
end
always @(pr_state1) begin
//In second always block only we have output logic and next state logic
case (pr_state1)
ST10 : begin clk_temp1 = 1'b1; nx_state1 =ST11; end
ST11 : begin clk_temp1 = 1'b0; nx_state1 =ST12; end
ST12 : begin clk_temp1 = 1'b0; nx_state1 =ST10; end
default : begin clk_temp1 = 1'bx; nx_state1 =ST10; end
endcase
end
always@(negedge clk ,posedge rst_n) begin
if(!rst_n)
pr_state2 <= ST20;
else
pr_state2 <= nx_state2;
end
always @(pr_state2) begin
case (pr_state2)
ST20 : begin clk_temp2 = 1'b0; nx_state1 =ST21; end
ST21 : begin clk_temp2 = 1'b0; nx_state1 =ST22; end
ST22 : begin clk_temp2 = 1'b1; nx_state1 =ST20; end
default : begin clk_temp2 = 1'bx; nx_state1 =ST20; end
endcase
end
assign clk_divby3 = clk_temp1|| clk_temp1;
endmodule
TestBench
module tb_div_2clk;
reg clk,rst_n;
wire clk_out;
div_3clk clkby3 (.clk(clk),.rst_n(rst_n),.clk_by_3(clk_out));
initial begin
clk =1'b0;
rst_n =1'b0;
@(posedge clk);
@(posedge clk);
rst_n = 1'b1;
repeat(15) @(posedge clk);
$finish;
end
always #5 clk = ~clk;
always @(clk_out)
$display("time = %0t \t Input clk =%b \t output clk=%b ",$time,clk,clk_out);
endmodule
output
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Literals are numeric, character and string values speciï¬ed literally in e. Operators
can be applied to literals to create compound expressions. The following categories of
literals and constants are supported in e:
------------------------------------------------------------
Sized Numbers
--------------------------------------------------------------
Binary A leading 'b or 'B 8'b11001010
Octal A leading 'o or 'O 6'o45
Decimal A leading 'd or 'D 16'd63453
Hexadecimal A leading 'h or 'H or 'x or 'X 32'h12ffab04
--------------------------------------------------------------
Predeï¬Ned Constants
---------------------------------------------------------
Constant Description
---------------------------------------------------------
TRUE For Boolean variables and expressions.
FALSE For Boolean variables and expressions.
NULL For structs, speciï¬es a NULL pointer. For
character strings, speciï¬es an empty string.
UNDEF UNDEF indicates NONE where an index is expected.
MAX_INT Represents the largest 32-bit int (231 -1)
MIN_INT Represents the smallest 32-bit int (-231).
MAX_UINT Represents the largest 32-bit uint (232-1).
--------------------------------------------------------
Search ✔
EXAMPLE:
OpenVera
type direction_t: [READ, WRITE] (bits: 1);
Constructs
Switch TB Default first enum value is 0. Subsequent enum values are increment by 1. This
internal value is used for comparisons(with strong type matching maintained).
RVM Switch TB Values can be explicitly assigned with the syntax:
RVM Ethernet sample
EXAMPLE:
type opcode_t: [ADD = 4, SUB = 6];
Specman E
Interview Questions
Search ✔
Shift Operators
EXAMPLE
<'
extend sys {
run() is also{
var x: int = 0x123456;
outf("%x\n", x >> 2);
var y: uint = 0x654321;
outf("%x\n", y >> 3);
};
};
'>
RESULT
48d15
ca864
Boolean Operators
EXAMPLE
<'
extend sys {
run() is also{
var x: int = 2;
if(x > 1)
{ out(" (X > 1) ");};
if((x > 1) && (x < 3))
{ out(" (x > 1) && (x < 3) "); };
if((x > 1) || (x < 3))
{ out(" (x > 1) || (x < 3) "); };
if((x > 1) => (x < 3))
{ out(" (x > 1) => (x < 3) "); };
if((x > 1) and (x < 3))
};
};
'>
RESULT
(X > 1)
(x > 1) && (x < 3)
(x > 1) || (x < 3)
(x > 1) => (x < 3)
(x > 1) and (x < 3)
(x > 1) or (x < 3)
Arithmetic Operators
EXAMPLE:
<'
extend sys {
run() is also{
out(1 + 4);
out(3 - 4);
out(41 * 3);
out(27 / 4);
out(53 % 7);
};
};
'>
RESULTS
5
-1
123
6
4
Comparison Operators
EXAMPLE
<'
extend sys {
run() is also{
out( 5 < 6);
out( 5 <= 6);
out( 5 > 6);
out( 5 >= 6);
out( 5 == 6);
out( 5 != 6);
out( 5 == 6);
out( 5 != 6);
out( "gg" ~ "gg" );
out( "gg" !~ "gg");
out( 5 in {4;5;6} );
};
};
'>
RESULT
TRUE
TRUE
FALSE
FALSE
FALSE
TRUE
FALSE
TRUE
TRUE
FALSE
TRUE
Special-Purpose Operators
EXAMPLE:is[not]
<'
type pack_kind :[long, short];
struct packet {
kind: pack_kind;
when long packet {
a: int;
};
check_my_type() is {
if me is a long packet (l) {
print l;
};
if me is not a long packet {
print kind;
};
};
};
extend sys {
p:packet;
run() is also {
p.check_my_type();
}
};
'>
RESULT
Search ✔
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
a_list.push(44);
print a_list;
a_list.push0(55);
print a_list;
a_list.resize(4);
print a_list;
a_list.clear();
print a_list;
}
};
'>
RESULT:
a_list =
0. 1
1. 2
2. 3
3. 4
a_list.pop() = 4
a_list =
0. 1
1. 2
2. 3
3. 9
a_list =
0. 1
1. 2
2. 33
3. 3
4. 9
a_list =
0. 1
1. 2
2. 33
3. 3
4. 9
5. 5
6. 5
a_list =
0. 1
1. 2
2. 33
3. 3
4. 5
5. 5
a_list =
0. 22
1. 1
2. 2
3. 33
4. 3
5. 5
6. 5
a_list.pop0() = 22
a_list =
0. 1
1. 2
2. 33
3. 3
4. 5
5. 5
6. 44
a_list =
0. 55
1. 1
2. 2
3. 33
4. 3
5. 5
6. 5
7. 44
a_list =
0. 0
1. 0
2. 0
3. 0
a_list = (empty)
Keyed List:
A keyed list data type is similar to hash tables or association lists found in other
programming languages. If the element type of the list is a scalar type or a string
type, then the hash key must be the predefined implicit variable it.
A keyed list is a distinct type, different from a regular list. This means that you
cannot assign a keyed list to a regular list, nor assign a regular list to a keyed list: if
list_a is a keyed list and list_b is a regular list, list_a = list_b is a syntax error.
EXAMPLE:
<'
extend sys {
!a: list(key: it) of int(bits: 3);
run() is also {
var b: int(bits: 4);
for i from 0 to 10 {
gen b;
a.add(b);
};
if a.key_exists(2) then {
print a;
print a.key_index(4);
};
};
};
'>
RESULT:
Search ✔
};
'>
Invoking Tcms:
A start action can be used within another method, either a TCM or a regular method.
A started TCM begins execution either when its sampling event occurs or immediately,
if the sampling event has already occurred for the current Specman tick.A started
TCM runs in parallel with the TCM that started it on a separate thread. Notes. A TCM
that has a return value cannot be started with a start action.. You cannot start a TCM
before the run phase begins or after the check phase begins.
EXAMPLE:
<'
struct meth {
event clk is rise('top.clk');
run() is also {
out("Starting main…");
start main();
};
};
'>
Execution Flow
---------------------
Execution Phases
---------------------
--Initialization
--Pre-run generation
--Simulation run
--Post-run check
--Finalization
---------------------
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera RESULT:
Constructs
Switch TB This is BASE
This is BASE
RVM Switch TB This is EXTENDED
RVM Ethernet sample
Is First
Specman E
Interview Questions "is first" is used for extending existing method/TCM. When we use "is first" it adds new
lines of code/functionality before existing code shown in below example.
EXAMPLE:
<'
struct exam {
from_exam() is {
out ( "This is BASE" );
};
};
};
};
extend sys {
exam : exam;
e_exam : e_exam;
run() is also {
exam.from_exam();
e_exam.from_exam();
};
};
'>
RESULT
This is BASE
This is EXTENDED
This is BASE
Is Only
"is only" is used for over riding existing method/TCM. When we use "is only" it over
rides the existing code/functionality before existing code and replaces with new code
as shown in below example.
EXAMPLE:
<'
struct exam {
from_exam() is {
out ( "This is BASE" );
};
};
};
};
extend sys {
exam : exam;
e_exam : e_exam;
run() is also {
exam.from_exam();
e_exam.from_exam();
};
};
'>
RESULT:
This is BASE
This is EXTENDED
Search ✔
When
EXAMPLE:when
<'
type pack_kind :[long, short];
struct packet {
kind: pack_kind;
when long packet {
a: int;
};
check_my_type() is {
if me is a long packet (l) {
print l;
};
if me is not a long packet {
print kind;
};
};
};
extend sys {
p:packet;
run() is also {
p.check_my_type();
}
};
'>
RESULT
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB Temporal Checking
RVM Switch TB
1. The temporal expressions we saw for defining events and using in wait actions in
RVM Ethernet sample
TCMs can also be used for checking behavior through time.
2. The struct member expect spawns a thread that reports an error if a temporal
expression does not succeed.
Specman E
Interview Questions
Search ✔
[ Exp..Exp ]
The first match repeat operator is only valid in a temporal sequence {TE; TE; TE}. The
first match repeat expression succeeds on the first success of the match-expression
between the lower and upper bounds specified for the repeat-expression. First match
repeat also enables specification of behavior over infinite sequences by allowing an
infinite number of repetitions of the repeat-expression to occur before the match-
expression succeeds.
Where @ev_a is an event occurrence, {[..]*TE1;@ev_a} is equivalent to:
{@ev_a} or {[1]*TE1; @ev_a} or {[2]*TE1; @ev_a} or {[3]*TE1; @ev_a}…
~[ Exp..Exp ]
You can use the true match repeat operator to specify a variable number of
consecutive successes of a temporal expression.True match variable repeat succeeds
every time the subexpression succeeds. This expression creates a number of parallel
repeat evaluations within the range. True match repeat also enables specification of
behavior over infinite sequences by repeating an infinite number of occurrences of a
temporal expression. The expression ~[..]*TE is equivalent to:
[0] or [1]*TE or [2]*TE
=>
The yield operator is used to assert that success of one temporal expression depends
on the success of another temporal expression. The yield expression TE1 => TE2 is
equivalent to (fail TE1) or {TE1 ; TE2}.The yield expression succeeds without
evaluating the second expression if the first expression fails. If
the first expression succeeds, then the second expression must succeed in sequence.
Yield is typically used in conjunction with the expect struct member to express
temporal rules. The sampling event from the context applies to both sides of the yield
operator expression. The entire expression is essentially a single temporal expression,
so that (TE1 => TE2)@sampling_event is effectively (TE)@sampling_event where TE is
the temporal expression made up of TE1 => TE2.
Search ✔
Used to specify the sampling event for a temporal expression. The specified sampling Report a Bug or Comment
Verilog event overrides the default sampling event. Every temporal expression has a sampling on This section - Your
event. The sampling event applies to all subexpressions of the temporal expression. It input is what keeps
Verification
can be overridden for a subexpression by attaching a different sampling event to the Testbench.in improving
Verilog Switch TB subexpression. A sampled temporal expression succeeds when its sampling event with time!
Basic Constructs occurs with or after the success of the temporal expression.
Cycle
OpenVera
Constructs Represents one cycle of some sampling event.With no explicit sampling event
Switch TB specified, this represents one cycle of the default sampling event. With a sampling
event specified, cycle is equivalent to @sys.any@sampling-event.
RVM Switch TB
RVM Ethernet sample
True(Exp)
Consume
Removes the occurrence of an event so that it is not available for other temporal
expressions. The consume expression succeeds whenever the event occurs. If the
event occurs more than once during any given cycle, all occurrences are consumed.
After an event occurrence is consumed, that occurrence will not be recognized by any
temporal expression during the current Specman Elite tick, unless the event is
emitted again. An event cannot be consumed by more then one consume expression.
Care should be used to avoid creating race conditions between multiple events that
use an event that is consumed.
Exec
Invokes an action block when a temporal expression succeeds. The actions are
executed immediately upon the success of the expression, but not more than once per
Specman Elite tick.
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Packing.Low
Places the least significant bit of the first physical field declared or lowest list item at
index [0] in the resulting list of bit.
EXAMPLE:
<'
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);
!data_packed_low : list of bit;
keep opcode == 0b100;
keep operand == 0b11001;
keep address == 0b00001111;
do_packs () is {
data_packed_low = pack(packing.low, opcode, operand);
};
};
extend sys {
instruction : instruction;
run() is also {
instruction.do_packs();
print instruction;
print "----------------------------";
out (" %b \n",instruction.data_packed_low );
}
};
'>
RESULT:
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
Syntax cover event-type [using coverage-group-option, ...] is {coverage-item- Report a Bug or Comment
Verilog definition; ...}; on This section - Your
cover event_type is empty; input is what keeps
Verification
Testbench.in improving
Verilog Switch TB with time!
Basic Constructs
Cross-Coverage
ItemA cross coverage item is the cross product(matrix) of two or more previously
declared basuic items. It Can cross any number of items declared in the same
coverage group. This can also be done in e code or interactively, using Coverage
GUI. Options for cross are same as for basic items are available, except using ranges.
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
OpenVera
Constructs
Switch TB
RVM Switch TB
RVM Ethernet sample
Specman E
Interview Questions
Search ✔
CODE : seq_driver.e
<'
extend seq_driver {
event clock is only @agent.clk;
keep bfm_interaction_mode == PULL_MODE;
send_items() @clock is {
var item: vector_s;
while TRUE {
item = get_next_item();
agent.bfm.send_vector(item);
emit item_done;
};
};
run() is also {
start send_items();
};
};
'>
CODE : testcase.e
<'
extend MAIN vector_sequence {
body()@driver.clock is only{
//for i from 0 to 9 {
do vector keeping {
.kind == INPUT;
};
print vector.a;
print vector.b;
do vector keeping {
.kind == OUTPUT;
};
print vector.output;
//};
};
};
'>
CODE : agent_h.e
<'
unit agent_u {
};
'>
CODE : agent.e
<'
extend agent_u {
keep hdl_path() == "~/and_gate_tb";
bfm: bfm_u is instance;
};
'>
CODE : coverage_h.e
<'
unit coverage_u {
agent:agent_u;
event cover_event;
};
'>
~
CODE : coverage.e
<'
extend coverage_u {
'>
CODE : scoreboard_h.e
<'
unit scoreboard_u {
};
'>
CODE : scoreboard.e
'
extend scoreboard_u {
a:bit;
b:bit;
output:bit;
};
'>
CODE : monitor_h.e
<'
unit monitor_u {
agent: agent_u;
};
'>
CODE : monitor.e
<'
extend monitor_u {
checker() is{
if ((agent.sb.a & agent.sb.b) == agent.sb.output) {
}
else {
dut_error("output mismatch");
};
};
};
'>
CODE : bfm_h.e
<'
unit bfm_u {
agent: agent_u;
};
'>
CODE : bfm.e
<'
extend bfm_u {
event clk is @agent.clk;
send_vector(vec:vector_s)@clk is {
if vec.kind == INPUT {
'(agent.sig_a)'= vec.a;
'(agent.sig_b)'= vec.b;
wait[1];
agent.sb.a= vec.a;
agent.sb.b= vec.b;
emit agent.coverage.cover_event;
};
if vec.kind == OUTPUT {
vec.output='(agent.sig_c)';
agent.sb.output=vec.output ;
wait[1];
agent.monitor.checker();
};
};
};
'>
CODE : env.e
<'
unit env_u{
agent: agent_u is instance;
};
'>
CODE : top.e
<'
import import_files.e;
extend sys{
env : env_u is instance;
stop_wave: bool;
keep soft stop_wave == FALSE;
all_objections_dropped(kind: objection_kind) is also {
if kind == TEST_DONE and !stop_wave {
raise_objection(TEST_DONE);
start env.agent.close_waveform();
message(LOW,"close_waveform()");
stop_wave = TRUE;
};
};
};
'>
Search ✔
In iSV,o etoi createoa qMUTEX,re construct iaoq jsemaphorere with ione okey.
A ikeyo eisi given tooeither qmonitorre or itestcaseoq jtore read ioperation
obasedqon whoz comesu yfirst.e oOncezx the key is returned, other waiting
component can take the key and start its operation.
www.testbench.in
It iiso enoti possibleoto qlistre out ieveryoq jpossiblere real itime oscenarioqwhile
verifyingz DUT.
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
If iweo etryi toolist qoutre the iscenarios,oq jthenre we imay omissqsome ofz them.u
ySo,e ousingzx randomization, based on the specification, scenarios are generated in
a randomfashion.
For iexample,o etoi generateoa qpacketre of ilengthoq jwhichre ranges ifrom 0
otoq9, inz verilogu y{$random()}e o%zx 10 should be used.
With ithis,o epacketsi ofolength qarere generated irandomly.oq j
www.testbench.in
Seed iiso eusedi toochange qthere sequence iofoq jrandomre numbers igenerated.
The iseedo einitializes thei randomonumber qgenerator.re
All itheo erandomi numbersowhich qarere generated ifrom aoq jparticularre seed
ivalue ocanqbe recreated byz givingu ythee osamezx seed.
Functional icoverageo e,i byothe qnamere itself i,oq jisre related ito
otheqfunctionality ofz theu ydesigne oandzx it is defined by the user. User will define
the coverage points for the functions to be covered in DUT. This is completely under
user control.
(Q i11)o eIfi CodeoCoverage qisre 100% iandoq jfunctionalre coverage iis onot,qwhat
doesz itu ymeane o?
Ans:
(Q i12)o eIfi Functionalocoverage qisre 100% iandoq jcodere coverage iis onot,qthen
whatz doesu yite omean?
Ans:
1) iIfo etherei isoa qbugre in itestoq jenvironment,re due ito othisqtest mayz falseu
yPass.e oThezx functional coverage will hit due to this false pass but some of the dut
code may not get exercised.
2) iIfo ethei dutois qare legacy icode oroq jIP,re it imay ohaveqsome usez lessu
yblockse otozx support extra functionality. Due to this code coverage will not be 100%
achieved.
3) iIno emyi firstocompany, there qwasre some iuseoq jlessre logic iwhich odidqnot
getz exercised.u yWhene oIzx approached the RTL designer, he said that fixing this
use less code will break the whole design. So he did not fix it. In this situation ,
functional coverage is 100%, but not the code coverage.
4)My ifriendso eexperience,i onceoRTL qdesignerre added iaoq jcodere for ia
onewqfeature. Because ofz missu ycommunication,e omyzx friend didnt know that
RTL designer added this new functionality.
When imyo efriendi didothe qcodere coverage, iheoq jfoundre some iunexercised
ologicqwhich hez didntu yunderstoode oandzx approached RTL designer. Then they
figured out that because of miscommunication, they found a feature in the spec
which was implemented, but not verified.
www.testbench.in
I idonto ethinki ,opoint q2)re can ibeoq javoided.re Point i1), o3)qand 4)z canu ybee
osolved.zx
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
2)Separate icompilation:
www.testbench.in
Compile itheo etestbenchi once. Toorun qare testcase, icompileoq jthere testcase i,
olinkqthe testcasez tou ytestbenche ocompiledzx code and simulate.
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i18)o eExplaini howomessages qarere implemented iinoq jyourre testbench?
Ans:
In iVMM/RVM/AVM/OVM/UVM/ERM/Truss&Tealo emethodologies, messagei
handlingologic qisre predefined. iUseoq jcanre use ithese opredefinedqmessage
servicesz andu yprinte omessageszx as required by testbench. If above methodology
base classes are not used, then user can define his own message handling logic.
www.testbench.in
reg iclk;
initial iclko e=i 0;o
always i#10o eclki =o~clk; q
(Q i20)o eHowi toopass qare value itooq jtestbenchre from icommand oline?
Ans:
Click on the below link
http://www.testbench.in/TB_22_COMPILATION_N_SIMULATION_SWITCHS.html
Search ✔
www.testbench.in
I ilikeo epointi 3.oThe qexternalre file iwilloq jbere availabe iafter osimulation.qSo
,z thisu yfilee ocouldzx be used for debugging.
www.testbench.in
To iovero ethei aboveomentioned qdisadvantage, hierarchalre path icanoq jbere
used. iThis oisqcalled backdoorz access.
Linting itoolso earei theotools qthatre flag isuspiciousoq jlanguagere usage iand
oerror-proneqsyntactical constructs.z Lintingu ytoolse ogenerallyzx perform static
analysis of source code. Linting tools can help programmer find dangerous code before
a compiler turns them into run-time bugs.
(Q i39)o eWhoi shouldodo qthere rtl idebugoq j?re The idesigner o?qThe VEz ?
Ans:
www.testbench.in
Search ✔
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
module ques();
string strin[7] ;
www.testbench.in
int i,j,k,file;
initial begin
string s;
file i=$fopen("file.txt","r");
while (!$feof(file))begin
k= $fscanf(file,"",s);
strin[i] =s;
i++;
end
www.testbench.in
$fclose(file);
foreach(strin[j])
$display("index ij=o e0 stringi =",j,strin[j]);
$finish;
end
endmodule
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
Ans:
If iusero ewanti toodeallocate, qhere can ijustoq jassignre null ito otheqobject.
www.testbench.in
EXAMPLE:
testclass ib; // Declareo eai handleob qforre testclass
b i= new; //o eConstruct ai testclassoobject qandre stores itheoq jaddressre in ib
o."new"qallocate spacez foru ytestclass
b=null; i//Deallocateo ethei object.MeansoDeallocate qthere memory ispaceoq
jforre object.
task Driver::run;
www.testbench.in
forever begin
...
<pre_callback> //It icallso ethei functionopre_callback.
i
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
transmit(tr);
end
endtask
task pre_callback;
www.testbench.in
endtask
Bug::Here iObjecto e"tr"i isoconstructed qoncere outside itheoq jloop.re Then i"tr"
oisqrandomized andz putu ytheme ointozx mailbox "mbx".But mailbox "mbx" holds
only handles,not objects.Therefore Mailbox contains multiple handles pointing to
single object.Here code gets the last set of random values.
www.testbench.in
task run;
repeat (10)
begin
tr i=new(); o e//1.Constructing
assert(tr.randomize);//2.Randomize
www.testbench.in
Factory iPattern:
1)construct iao eblueprinti objecto
2)Randomize ithiso eblueprint(i Itohas qcorrectre random ivaluesoq j)
3)Make iao ecopyi ofothis qobjectre
www.testbench.in
4)Put iintoo emailbox
class Generator;
mailbox mbx;
Transaction iblueprint;
blueprint i= new;//1.Constructingo eBluei print
task run;
Transaction itr;
Repeat(10}
begin
www.testbench.in
assert(blueprint.randomize); //2.Randomizing iBlueo eprint
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
tr i= blueprint.copy; // 3.Copyo ethei blueprint
mbx.put(tr); // i4.Puto eintoi mailbox
end
endtask
endclass
WIRE:
1. iWireo eisi justoan qinterconnectionre between itwooq jelementsre which idoes
onotqhave anyz drivingu ystrength
2. iIto eisi usedofor qmodelingre combinational icircuitoq jasre it icannot ostoreqa
value.
3. iWireo ehasi aodefault qvaluere of i"z""oq jandre get ivalues ocontinuouslyqfrom
thez outputsu yofe odeviceszx to which they are connected to.
4.Example:
wire A;
assign A i= b&c;
REG
www.testbench.in
1. iRego eisi ao4 qstatere unsigned ivariableoq jthatre can ihold oaqvalue andz
retainsu yuntile oazx new value is assigned to it.
2. iRegistero edatai typeocan qbere used iforoq jmodelingre both icombinational
oandqsequential logic
3. iDefaulto evaluei fororegister qisre "x" iandoq jitre doesn't irequire oanyqdriver
toz assignu yvaluee olikezx wire. It can be driven from initial and always block.
Values of the register can be changed anytime in the simulation by assigning a new
value to register.
4.Example: i
reg A;
always @ (b ior c)
begin
A=b&c;
end
Note:A iiso edeclaredi asoreg qwhichre can ibeoq jevaluatedre only iwhen othereqis
az changeu yine oanyzx of the signal in the sensitivity list. So reg needs to store the
value until there is a change in sensitivity list.
www.testbench.in
LOGIC: i
1. i4o estatei unsignedodata qtypere introduced iinoq jSystemre verilog.
2.System iVerilogo eimprovesi theoclassic qregre data itypeoq jsore that iit ocanqbe
drivenz by
a. iContinuouso eassignments, (ex:assigni crc=~crc; )
b. iGates,o e(ex:i andog1(q_out, qd);re )
c. iModules,o e(ex:i Flp_fopsof1 q(q,re q_out, iclk,rst);oq j)
3.In iadditiono etoi beingoa qvariable.re It iisoq jgivenre the isynonym ologicqso
thatz itu ydoese onotzx look
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
ilikeo eai registerodeclaration. q
www.testbench.in
4.If iyouo eonlyi madeoprocedural qassignmentsre to i'logic'oq jthenre it iwas
osemanticallyqequivalent toz 'reg'.u y
5.A ilogic signalo ecani beoused qanywherere a inetoq jisre used, iexcept othatqa
logicz variableu ycannote obezx driven by
imultipleo estructurali drivers,osuch qasre when iyouoq jarere modeling ia
obidirectionalqbus.
6.Example: i
module sample1;
logic crc, sa i,d, q_out;
logic clk,rst;
initial
begin
clk=1'b0; //procedural iassignment
www.testbench.in
i#10 clko e=1'b1;
end
assign crc=~crc; //continuous iassignment
and g1(q_out, id);o e//q_outi isodriven qbyre gate
Flp_fops if1o e(q,i q_out,oclk,rst); q//qre is idrivenoq jbyre module
endmodule
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
EXAMPLE:
clocking cb i@(posedge clk);// clockingo eblocki cbodeclares, qsignalsre inside
ir activeoq jon positivere edge iof oclk.
default input #1ns ioutput #2ns; //o eInputi skewoand qoutputre skew, i
output request; //output ifrom DUT too etestbench
input grant i; //Inputo efromi testbenchoto qDUT
endclocking
1)The iclocko ewhichi isogiven qtore DUT iandoq jTestbenchre should ihave oaqphase
difference.z
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
2)DUT ishouldo eworki oroposedge qofre clock iandoq jtestbenchre should iwork
oonqnegedge ofz clock.
3)Testbench ioutputo eandi DUTooutput qpinsre should ialwaysoq jbere driven iusing
ononqblocking statements.
4)Clocking iblocks.
www.testbench.in
5)Program iblock.
www.testbench.in
(Q i25)o eIsi itopossible qtore pass istructoq jorre union ifrom oSVqto Cz usingu yDPIe
o?zx If yes, then how is it done ?
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i28)o eHowi toowrite qare message itooq jare string i?
www.testbench.in
(Q i30)o eGivei examplesoof qstaticre cast iandoq jdynamicre cast i.
(Q i31)o eHowi theoStatic qcastre and iDynamicoq jcastre errors iare oreportedq?
(Q i34)o eWhati willobe qthere values iofoq jrandre and irandc ovariablesqif
randomizationz failsu y?
www.testbench.in
(Q i35)o eExplaini aboutothe Timeunit, qTimeprecisionre and i`timescaleoq j.
(Q i36)o eIsi itopossible qtore access iaoq jmemberre of ia ostructqthat isz returnedu
ybye oazx function in side the function ?
www.testbench.in
(Q i40)o eWhati isothe qdefaultre value iofoq jenumeratedre data itype o?
(Q i44)o eHowi tooconvert qare command ilineoq jdefinedre value ito oaqstring inz
SystemVerilogu y?
www.testbench.in
(Q i45)o eWhati areovirtual qmethodsre ?
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i47)o ewhati isoa qvirtualre class?
www.testbench.in
(Q i50)o eWhati isoshallow qcopyre ?
www.testbench.in
(Q i55)o eWhati isoa qsuperclass?re
www.testbench.in
(Q i62)o eWhati willothe qprintedre value i?
iBito e[7:0] a,b;
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
iAo e= 8<92>hff; Bi = 8<92>h01;
i$display("0",Ao e+ B);
(Q i64)o eIi wantoto qdelayre simulation ibyoq jsmallestre unit iof otime.qi.e
minimumz ofu yalle othezx timeprecision. How to do it ?
(Q i68)o eWhati areothe qdifferentre types iofoq jparametersre available iin oSV?
www.testbench.in
(Q i70)o eWhati typeois qthere index iforoq jintre array_name i[*]? o
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i71)o eIni aoArray, qIf indexre is ioutoq jofre the iaddress obounds,qthen whatz
willu ybee othezx return value ?
(Q i72)o eWhati isothe qreturnre type iofoq jArrayre locator imethod ofind_indexq?
www.testbench.in
(Q i75)o eExplaini howoyou qdebuggedre randomization ifailure.
(Q i76)o eWhati isozero qdelayre loop iandoq jWhatre is ithe oproblemqwith zeroz
delayu yloope o?
(Q i77)o eWhati isothe qdifferencere between izerooq jdelayre loop iin odesignqand
testbenchz ?
(Q i82)o eHowi toogenerate qrandomre numbers ibwoq jare range iof ovalues?
www.testbench.in
Search ✔
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i108)o eWhati isothe qusere of ipackagesoq j?
(Q i114)o eHowi toocall qthere task iwhichoq jisre defined iin oparentqobject intoz
derivedu yclasse o?zx
www.testbench.in
Search ✔
b)
initial begin
#1;
i->a;
end
ialways @ao e->b;
ialways @bo e-> c;
www.testbench.in
c)
initial begin
#1;
i->a;
i#0 ->b;
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
i->>c;
end
d)
www.testbench.in
initial begin
i#1 ->a;
i#1 ->b;
i#1 ->c;
end
www.testbench.in
(Q i151)o eWhichi isobest qtore use itooq jmodelre a itransaction o?qStruct orz classu
y?
www.testbench.in
Search ✔
var logic data_2;
wire logic data_3 i; Report a Bug or Comment
bit data_4; on This section - Your
var bit data_5; input is what keeps
Testbench.in improving
www.testbench.in with time!
(Q i169)o eWhati isothe qdifferencere between ibitoq jandre logic i?
www.testbench.in
(Q i174)o eWhati isolayered qarchitecturere ?
(Q i176)o eHowi toopick qare element iwhichoq jisre in iqueue ofromqrandom indexz
?
(Q i178)o eWhati isocasting q?re Explain iaboutoq jthere various itypes oofqcasting
availablez inu ySVe o.
www.testbench.in
(Q i179)o eHowi tooimport qallre the iitemsoq jdeclaredre inside ia opackageq?
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i182)o eWhati areovoid qfunctionsre ?
(Q i183)o eHowi toomake qsurere that iaoq jfunctionre argument ipassed oasqref isz
notu ychangede obyzx the function ?
www.testbench.in
(Q i184)o eWhati isothe qusere of i"extern"oq j?
(Q i185)o eWhati isothe qdifferencere between iinitialoq jblockre and ifinal oblock?
Ans:
www.testbench.in
Search ✔
(Q i209)o eThei signalsosig_a qandre sig_b imayoq jonlyre be iasserted oifqsig_c isz Report a Bug or Comment
asserted. on This section - Your
input is what keeps
(Q i210)o eTherei existsoa qtransactionre that ireachesoq jitsre end either sig_a or Testbench.in improving
isig_b. with time!
www.testbench.in
(Q i211)o eIfi sig_aois qreceivedre while isig_boq jisre inactive, ithen oonqthe nextz
cycleu ysig_ce omustzx be inactive, and sig_b must be asserted.
(Q i213)o esig_ai mustonot qbere asserted itogetheroq jwithre sig_b or iwith osig_c.
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i214)o esig_ai mustonot qbere asserted ibetweenoq janre sig_b iand
otheqfollowing sig_cz (fromu yonee ocyclezx after the sig_b until one cycle after the
sig_c).
(Q i215)o esig_ai mustonot qbere asserted itogetheroq jwithre sig_b ior owithqsig_c.
www.testbench.in
(Q i216)o eIfi weoare qatre the iendoq jofre a itransaction o(sig_aqis down,z sig_bu
yise oup),zx and sig_c is down, then sig_c must be asserted before the next time that
sig_a is asserted.
(Q i217)o eIfi sig_aois qdown,re sig_b imayoq jonlyre rise ifor ooneqcycle beforez
theu ynexte otimezx that sig_a is asserted.
(Q i218)o esig_ai mustonot qrisere if iweoq jhavere seen isig_b oandqhavent seenz
theu ynexte osig_czx yet (from the cycle after the sig_b until the cycle of the sig_c).
(Q i219)o eThei auxiliaryosignal qsig_are indicates ithatoq jwere have iseen oaqsig_b,
andz haventu yseene oazx sig_c since then. It rises one cycle after the sig_b, and falls
one cycle after the sig_c.
(Q i220)o esig_ai mayobe qassertedre only iwhileoq jsig_bre is itrue, oi.e.,qwe arez
atu yleaste oonezx cycle after a sig_c and havent seen a sig_d since then (except
perhaps in the current cycle)
www.testbench.in
(Q i222)o esig_ai mustonot qrisere if iweoq jhavere seen isig_b oandqhavent seenz
theu ynexte osig_czx yet (from the cycle after the sig_b until the cycle before the
sig_c).
(Q i223)o eWhilei sig_aois qdown,re sig_b imayoq jrisere only iif osig_cqis down.
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i224)o eIfi sig_aois qassertedre with isig_boq jinactive,re and isig_c owasqinactive
inz theu ypreviouse ocyclezx and remains inactive in the next cycle, then sig_a must
be deasserted in the next cycle.
(Q i231)o eIfi sig_aois qactive,re then isig_boq jwasre active isomewhere oinqthe
past.
(Q i232)o eIfi thereois qare sig_a, ifollowedoq jbyre 3 iconsecutive osig_b,qthen inz
eachu yofe othezx 3 cycles the data written (DO) is equal to the data read (DI).
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i233)o eAlways,i ifoon q3re consecutive isig_a,oq jsig_bre appears, ithen oonqthe
nextz sig_cu ycycle,e osig_azx holds.
Search ✔
Ans:
PATHPULSE$ ispecparam iso eusedi toocontrol qpulsere handling ionoq jare
module path. Report a Bug or Comment
on This section - Your
(Q i10) ino estatementi (o(a==b) q&&re (c i==oq jd)re ) i, owhatqis thez expressionu input is what keeps
ycoveragee oifzx always a=0,b=0,c=0,d=0 ? Testbench.in improving
with time!
(Q i11)o eDifferencei betweenoReduction qandre Bitwise ioperators?
Ans:
The idifferenceo eisi thatobitwise qoperationsre are ionoq jbitsre from itwo
odifferentqoperands, whereasz reductionu yoperationse oarezx on the bits of the
same operand. Reduction operators work bit by bit from right to left. Reduction
operators perform a bitwise operation on a single vector operand and yield a 1-bit
result Bitwise operators perform a bit-by-bit operation on two operands. They take
each bit in one operand and perform the operation with the corresponding bit in the
other operand.
www.testbench.in
Wait ifiveo etimei unitsobefore qdoingre the iactionoq jforre "a i= ob;".
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
The ivalueo eassignedi tooa qwillre be itheoq jvaluere of ib o5qtime unitsz hence.
a i= #5 b;
The ivalueo eofi bois qcalculatedre and istoredoq jinre an iinternal otemp
www.testbench.in
register. iAftero efivei timeounits, qassignre this istoredoq jvaluere to ia.
Ans: i
The i?o emergesi answersoif qthere condition iisoq j"x",re so ifor oinstanceqif fooz =u
y1'bx,e oazx = 'b10, and b = 'b11, you'd get c = 'b1x.
On itheo eotheri hand,oif qtreatsre X's ioroq jZsre as iFALSE, osoqyou'd alwaysz getu
yce o=zx b.
www.testbench.in
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
If itypeo eisi omitted,othe qfilere is iopenedoq jforre writing, iand oaqmulti channelz
descriptoru ymcde oiszx returned. If type is supplied, the file is opened as specified
by the value of type, and a file descriptor fd is returned. So in first statements , type
is omitted and mcd is returned and in the second statement, fd is returned.
www.testbench.in
The imultio echanneli descriptoromcd qisre a i32oq jbitre reg iin owhichqa singlez
bitu yise osetzx indicating which file is opened. Unlike multi channel descriptors, file
descriptors can not be combined via bitwise or in order to direct output to multiple
files. Instead, files are opened via file descriptor for input, output, input and output,
as well as for append operations, based on the value of type.
www.testbench.in
(Q i19)o eHowi toogenerate qare random inumberoq jwhichre is iless otheq100 ?
(Q i20)o eHowi toogenerate qare random inumberoq jwhichre is ibetween o0qto 100z
?
Search ✔
www.testbench.in
(Q i28) Whato eisi theodifference qamongre case,casex iandoq jcasez?
Ans:
case itreatso eonlyi 0oor q1re values iinoq jcasere alternative iand oisqis notz
dealingu ywithe odon'tzx care condition.
casex itreatso ealli xoand qzre values iinoq jcasere alternative ior ocaseqexpression
asz au ydon'te ocare.
casez itreatso ealli zovalues qinre case ialternatives.oq jallre bit ipositions owithqz
canz treatu yase oazx don't care
www.testbench.in
(Q i31)o eWhati isothe qdifferencere between icompiled,oq jinterpreted,re event
ibased oandqcycle basedz simulatoru y?
(Q i33)o eWhati dataotypes qcanre be iusedoq jforre input iport, ooututqport andz
inoutu yporte o?
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
www.testbench.in
(Q i35)o eWhati isothe qfunctionalityre of itri1oq jansre tri0 i?
Search ✔
www.testbench.in
(Q i54) Howo ethei aboveotwo qarere handled iin assignments,oq jports,functionsre
and itask o?
A inegedgeo eshalli beodetected qonre the itransitionoq jfromre 1 ito ox,qz, orz 0,u
yande ofromzx x or z to 0 where as posedge shall be detected on the transition from
0 to x, z, or 1, and from x or z to 1
The itwoo esetsi ofotasks qarere identical iexceptoq jthatre $display iautomatically
oaddsqa newlinez characteru ytoe othezx end of its output, whereas the $write task
does not. The $display task, when invoked without arguments, simply prints a newline
character. A $write task supplied without parameters prints nothing at all.
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
Search ✔
are iprintedo ebeforei theoprompt qisre issued. iIfoq jnore argument iis
osupplied,qthen az valueu yofe o1zx is taken as the default.
Report a Bug or Comment
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n on This section - Your
$finish(0) iPrintso enothing input is what keeps
$finish(1) iPrintso esimulationi timeoand qlocation Testbench.in improving
www.testbench.in with time!
$finish(2) iPrintso esimulationi time,olocation, qandre statistics iaboutoq jthere
memory iand oCPUqtime usedz inu ysimulation
The i$realtimeo esystemi functionoreturns qare real inumberoq jtimere that, ilike
o$time,qis scaledz tou ythee otimezx unit of the module that invoked it.
www.testbench.in
(Q i77) Differenceo ebetweeni !oAnd q~re ?
reg [1:0] data;
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
a i= data[0] || data[1];
b i= |data;
www.testbench.in
b)initial
#10 a i=0;
www.testbench.in
always@(a)
a i= ~a;
Ans:
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
When i"a=~a"o eisi evaluatedoand q'a're is iupdated,oq jclearlyre you imust
oagreeqthat executionz isu y*not*e ostalledzx at the @a event control. Â When
execution reaches the @a event control, 'a' has already changed. Â It will not change
again. Â So the event control will stall forever; its event of interest has already
occurred, earlier in the same time slot, and can no longer have any effect.
www.testbench.in
$setup iiso eai timingocheck qtaskre and i$displayoq jisre system itask.
www.testbench.in
Only iSystemo etasksi andofunction qcanre be ioverridden.oq jTimingre check itasks
ocannotqbe overridden.
i.e. iUsero ecani changeothe qdefinitionre of itheoq j$displayre but inot o$setup.
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i84) Whyo eisi itorecommended qnotre to imixoq jblockingre and inon-blocking
oassignmentsqin thez sameu yblock?
(Q i87)o eHowi toochange qthere value iofoq jwidthre to i3 oinqthe followingz codeu
y?
`define width i7
The i$inputo esystemi taskoallows qcommandre input itextoq jtore come ifrom
oaqnamed filez insteadu yofe ofromzx the terminal. At the end of the command file,
the input is switched back to the terminal.
www.testbench.in
(Q i89)o eWhati isothe qMCDre value iofoq jSTDre OUTPUT i?
0000000000000000000000000000001
.....w.....w......w......t.....e.....s.....t......b.....e.....n.....c.....h......i.....n
(Q i90) Whato eisi theodifference qbetweenre blocking iandoq jnonre blocking?
Search ✔