Module 3 Complete Notes
Module 3 Complete Notes
Verification
Guidelines:
The
Randomization, verification
process,
methodology directed
basics, testing,
Module 3 b
Data
Types:
Built in
Data
types,
fixed and
dynamic
arrays,
Queues,
associativ
e arrays,
linked lists,
array
methods,
choosing a
type,
Why was System Verilog created?
Tight integration
with event-
Support for HDL simulator for
types such as control of the
Verilog’s 4-state design
especially Object values „
Oriented
Programming „
Multi-threading
Higher-level and inter process
structures, communication „
Constrained-
random
stimulus
generation „
Functional
coverage „
The Verification Process
Is it Find
Bugs ?
Yes No
The Verification Process
What types of bugs are lurking in the design? The easiest ones
to detect are at the block level, in modules created by a single
person.
After the block level, the next place to look for discrepancies is
at boundaries between blocks
The Verification Process
As you start to integrate design blocks, they can stimulate each other,
reducing your workload. These multiple block simulations may uncover more
bugs, but they also run slower.
At the highest level of the DUT, the entire system is tested, but the simulation
performance is greatly reduced.
Once you have verified that the DUT performs its designated
functions correctly, you need to see how it operates when there are
errors.
Can the design handle a partial transaction, or one with corrupted data or control fields?
Just trying to enumerate all the possible problems is difficult, not to mention how the
design should recover from them. Error injection and handling can be the most challenging
part of verification
The Verification Plan
For a more
complete
discussion on
These steps may verification see
include directed Bergeron (2006).
or random
testing,
assertions, HW/
The verification plan SW co-
is closely tied to the verification,
hardware emulation, formal
specification and
contains a proofs, and use of
description of what verification IP.
features need to be
exercised and the
techniques to be
used.
Basic Test bench Functionality
The purpose of a test bench is to determine the correctness of the design under test (DUT).
This is accomplished by the following steps.
Generate stimulus „
„Test-specific
„Constrained- „Layered test code kept
random bench using separate from
stimulus transactors test bench
A directed test finds the bugs you expect to be in the design, while a random test can find bugs
you never anticipated.
All these principles are related. Random stimulus is crucial for exercising complex designs. A directed
test finds the bugs you expect to be in the design, while a random test can find bugs you never
anticipated.
When using random stimulus, you need functional coverage to measure verification progress.
once you start using automatically generated stimulus, you need an automated way to predict the
results, generally a scoreboard or reference model.
A layered testbench helps you control the complexity by breaking the problem into manageable
pieces.
With appropriate planning, you can build a testbench infrastructure that can be shared by all tests and
does not have to be continually modified.
You just need to leave “hooks” where the tests can perform certain actions such as shaping the
stimulus and injecting disturbances.
Building this style of testbench takes longer than a traditional directed testbench,
especially the self-checking portions, causing a delay before the first test can be
run. This gap can cause a manager to panic, so make this effort part of your
schedule.
In Figure 1-3, you can see the initial delay before the first random test runs.
Constrained-Random Stimulus
Figure 1-4 shows the coverage for constrained-random tests over the total
design space. First, notice that a random test often covers a wider space than
a directed one.
This extra coverage may overlap other tests, or may explore new areas that
you did not anticipate.
If these new areas find a bug, you are in luck! If the new area is not legal, you
need to write more constraints to keep away.
Lastly, you may still have to write a few directed tests to find cases not
covered by any other constrained-random tests.
Figure 1-5 shows
the paths to Start at the upper left
with basic
achieve constrained-random
complete tests.
coverage.
In a real world environment, the DUT’s configuration becomes more random the longer it
To test this device, the engineer had to write several dozen lines of directed testbench cod
configure each channel.
In the real world, your device operates in an environment containing other components.
When you are verifying the DUT, it is connected to a testbench that mimics this environme
You should randomize the entire environment configuration, including the length of the
simulation, number of devices, and how they are configured.
Of course you need to create constraints to make sure the configuration is legal
Input data
A test that uses the shortest delays runs the fastest, but it won’t
create all possible stimulus. You can create a testbench that talks
to another block at the fastest rate, but subtle bugs are often
revealed when intermittent delays are introduced
You can create a testbench that talks to another block at the
fastest rate, but subtle bugs are often revealed when
intermittent delays are introduced.
A block may function correctly for all possible permutations of
stimulus from a single interface, but subtle errors may occur
when data is flowing into multiple inputs.
. What if the inputs arrive at the fastest possible rate, but the
output is being throttled back to a slower rate? What if stimulus
arrives at multiple inputs concurrently? What if it is staggered
with different delays? Use functional coverage to measure what
combinations have been randomly generated
Parallel random testing
A random test consists of the testbench code plus a random seed. If you run the
same test 50 times, each with a unique seed, you will get 50 different sets of
stimuli. Running with multiple seeds broadens the coverage of your test and
leverages your work
You need to plan how to organize your files to handle multiple simulations. Each
job creates a set of output files such as log files and functional coverage data.
You can run each job in a different directory, or you can try to give a unique
name to each file.
Functional Coverage
• The previous sections have shown how to create stimuli that can
randomly walk through the entire space of possible inputs. With
this approach, your testbench visits some areas often, but takes
too long to reach all possible states.
• Unreachable states will never be visited, even given unlimited
simulation time. You need to measure what has been verified in
order to check off items in your verification plan.
• The process of measuring and using functional coverage
consists of several steps.
• First, you add code to the testbench to monitor the stimulus
going into the device, and its reaction and response, to
determine what functionality has been exercised.
• Next, the data from one or more simulations is combined into
a report.
• Lastly, you need to analyze the results and determine how to
create new stimulus to reach untested conditions and logic
Feedback from functional coverage to stimulus
21EC71
34
Flat Test Bench
21EC71
3.9 Layered Testbench
21EC71
36
22
21E C 71
Module 3 b
Data
Types:
Built in
Data
types,
fixed and
dynamic
arrays,
Queues,
associativ
e arrays,
linked lists,
array
methods,
choosing a
type,
Data Types
System Verilog offers
many improved data
structures compared with
System Verilog
„Strings: built-in string introduces new data
support types with the following
benefits.
Logic
Declaring Packed
Fixed – array
size
arrays
System Verilog offers much flexibility in
building complicated data structures
through the different types of arrays.
Static Arrays or fixed array
Dynamic Arrays
Associative Arrays
Queues
Fixed Array or static Array
SystemVerilog offers several flavors of arrays beyond the single-dimension,
fixed-size Verilog-1995 arrays.
Many enhancements have been made to these classic arrays.
A static array is one whose size is known before compilation time. In the
example shown below, a static array of 8-bit wide is declared, assigned some
value and iterated over to print its value.
For some data types, you may want both to access the entire
value and also divide it into smaller elements.
For example, you may have a 32-bit register that sometimes
you want to treat as four 8-bit values and at other times as a
single, unsigned value.
A System Verilog packed array is treated as both an array and a
single value. It is stored as a contiguous set of bits with no
unused space, unlike an unpacked array.
A packed array is used to refer to dimensions declared before
the variable name.
A packed array is guaranteed to be represented as a
contiguous set of bits. They can be made of only the single bit
data types like bit, logic, and other recursively packed arrays.
Choosing between packed and unpacked arrays
Using the earlier examples, you can block on the variable lw,
and barray[0], but not the entire array barray unless you
expand it: @(barray[0] or barray[1] or barray[2]).
Dynamic Arrays
It is very efficient to
If you add enough
push and pop elements
elements so that the
from the front and back
queue runs out of space,
of a queue, taking a
SystemVerilog
fixed amount of time no
automatically allocates
matter how large the
additional space.
queue
Example 2-22 uses a fixed-size array, f[6], a dynamic array, d[], and a queue, q[$].
The min and max functions find the smallest and largest elements in an array.
Note that they return a queue, not a scalar as you might expect.
These methods also work for associative arrays.
The unique method returns a queue of the unique values from the array — duplicate values
are not included
You could search through an array using a foreach loop, but
SystemVerilog can do this in one operation with a locator method. The
with expression tells System Verilog how to perform the search.
Method name Description
Choose your array type based on how many times it is accessed per clock cycle.
For only a few reads and writes, you could use any type, as the overhead is
minor compared with the DUT.
Fixed-size and dynamic arrays are stored in contiguous memory, so any element
can be found in the same amount of time, regardless of array size.
If you need to insert new elements into a large queue, your testbench may slow
down, so consider changing how you store new elements.
When reading and writing associative arrays, the simulator must search for the
element in memory.
The LRM does not specify how this is done, but popular ways are hash tables
and trees. These requires more computation than other arrays, and therefore
associative arrays are the slowest.
2.9.4 Sorting
In hardware, the interpretation of a set of bits in a register may depend on the value
of other bits.
Unions are useful when you frequently need to read and write a
register in several different formats.
However, don’t go overboard, especially just to save memory.
Unions may help squeeze a few bytes out of a structure, but at the
expense of having to create and maintain a more complicated data
structure
2.11.3 Packed structures
An enumeration creates a strong variable type that is limited to a set of specified names such as
the instruction opcodes or state machine values.
Using these names, such as ADD, MOVE, or ROTW, makes your code easier to write and maintain
than using literals such as 8’h01.
The simplest enumerated type declaration contains a list of constant names and one or more
variables. This creates an anonymous enumerated type.
Enumerated
types are stored
as int unless you
specify
otherwise. .
Be careful when
assigning values
to enumerated
constants, as
the default
value of an int is
2.13 Constants
Localparam constants are constants that cannot be modified by defparam statements or instance
parameter value assignments.
They are defined using the localparam keyword followed by the name and value of the constant.
Localparam constants are helpful when you need to set a value that should not be altered by the
user.
For instance, consider the following code that defines a Memory module with a parameter
named EntryNum and a localparam named AddrWidth.
The localparam is utilized to set the width of the address bus based on the value of
the EntryNum parameter, which should be calculated, and the user should not modify it.
Specparam Constants in Verilog and SystemVerilog
• Specparam constants are used to provide timing and delay values for
Verilog and SystemVerilog simulations.
• They are declared within a module or a specify block and are used
to override the timing and delay values.
• Specparam constants are defined using the specparam keyword
followed by the name and value of the constant.
2.14 Strings
Semantics
Operator
Returns 1 if the two strings are
Equality Str1 == Str2
equal and 0 if they are not
Returns 1 if the two strings are not
Inequality Str1 != Str2
equal and 0 if they are
Str1 < Str2
Str1 <= Str2 Returns 1 if the correspondig
Comparison
Str1 > Str2 condition is true and 0 if false
Str1 >= Str2
{Str1, Str2, ..., All strings will be concatenated into
Concatenation
StrN} one resultant string
Replicates the string N number of
Replication {multiplier{Str}} times, where N is specified by the
multiplier
Returns a byte, the ASCII code at
Indexing Str[index] the given index. If given index is
out of range, it returns 0
The dot(.) operator is used to call
Methods Str.method([args])
string functions
Basic String Methods
SystemVerilog also includes a number of special methods to work with strings,
which use built-in method notation.
Usage Definition Comments