0% found this document useful (0 votes)
8 views

21EC71_Module3

Module 3 of the Advanced VLSI Design course covers verification guidelines and methodologies in System Verilog, emphasizing the importance of a structured testbench environment, stimulus generation, and the verification process. It details components of a testbench, including DUT, stimulus generators, and monitors, as well as advanced features like constrained-random stimulus and functional coverage. Additionally, it discusses layered testbench architecture and various data types introduced in System Verilog to enhance design verification efficiency.

Uploaded by

susyspecific
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

21EC71_Module3

Module 3 of the Advanced VLSI Design course covers verification guidelines and methodologies in System Verilog, emphasizing the importance of a structured testbench environment, stimulus generation, and the verification process. It details components of a testbench, including DUT, stimulus generators, and monitors, as well as advanced features like constrained-random stimulus and functional coverage. Additionally, it discusses layered testbench architecture and various data types introduced in System Verilog to enhance design verification efficiency.

Uploaded by

susyspecific
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

21EC71 Advanced VLSI Design Module3

Module 3
Verification Guidelines:
The verification process, basic test bench functionality, directed testing, methodology basics,
constrained random stimulus, randomization, functional coverage, test bench components, layered
testbench.
Data Types:
Built in Data types, fixed and dynamic arrays, Queues, associative arrays, linked lists, array methods,
choosing a type, creating new types with type def, creating user defined structures, type conversion,
Enumerated types, constants and strings, Expression width.
---------------------------------------------------------------------------------------------------------------------------
The typical features of an HVL (System Verilog) that distinguish it from a Hardware Description
Language such as Verilog or VHDL are
 Constrained-random stimulus generation
 Functional coverage
 Higher-level structures, especially Object Oriented Programming
 Multi-threading and interprocess communication
 Support for HDL types such as Verilog‘s 4-state values
 Tight integration with event-simulator for control of the design

These features allow the HVL to generate higher level abstraction test bench than HDL or C.

Verification Process

The verification process in System Verilog is an essential part of hardware design to ensure that a
digital circuit behaves as expected. System Verilog, being a hardware description and verification
language, provides various constructs and methodologies for efficient and thorough verification. The
verification process generally involves the following stages:

1. Define Testbench Environment

The testbench is an essential part of the verification process. It includes all the components needed to
simulate and verify the design (DUT - Device Under Test). A typical testbench consists of:

 DUT Instantiation: This is the module or block being tested.


 Testbench Components: These include signal generators, monitors, checkers, and other
helper modules that assist in verifying the DUT.

A testbench in SystemVerilog is typically written as a class-based environment to make it reusable


and scalable.

2. Create the verification plan

Before starting any verification activities, a verification plan needs to be created. This test plan
identifies:

 The functionality to be tested.


 The coverage goals.
 The corner cases.
 Timing and performance constraints.
 Expected behaviors and error conditions.

The test plan provides a roadmap for verification and helps ensure all aspects of the design are
covered.

Agalya P, SCE, ECE Page 1


21EC71 Advanced VLSI Design Module3

3. Generate Stimulus

Stimulus generation is the process of creating input signals to the DUT. There are several approaches
to this:

 Random Stimulus Generation: System Verilog's random capabilities allow for random
input generation. This is typically used in constrained random verification to explore a wide
range of input combinations.
 Directed Tests: These are test cases that are specifically written to target particular behaviors
or functions of the DUT.
 Constrained Random Testing: A combination of random stimulus generation with
constraints to ensure legal or meaningful inputs are generated while still exploring a wide
variety of scenarios.

SystemVerilog's randc (random cyclic) and constraint mechanisms are key tools in this process.

4. Simulate the Design

The testbench and DUT are compiled and run in a simulation environment. During simulation, the
various parts of the testbench interact with the DUT to verify its functionality. The simulation process
checks if the DUT behaves as expected under the given stimulus.

 Simulator: A tool like ModelSim, VCS, or XSIM is used to run the simulation. These
simulators offer waveform viewers, command-line interfaces, and scripting capabilities to
monitor the simulation and analyze results.
 Waveform Analysis: During simulation, the waveform viewer helps in inspecting the signals
and verifying the timing and functional correctness.

5. Assertions and Coverage

Assertions and functional coverage are critical for validating the correctness of the DUT.

 Assertions: SystemVerilog provides powerful assertion mechanisms (e.g., assert, assume,


cover) to verify that the design satisfies certain properties during simulation. Assertions can
be used to check conditions at runtime, such as signal values, timing, and other properties.
o Immediate Assertions check conditions at a specific point in time.
o Concurrent Assertions monitor conditions over time.

Assertions help in detecting issues early in the design process and provide feedback for debugging.

 Functional Coverage: This helps track which parts of the design have been exercised by the
testbench. SystemVerilog provides coverage constructs like covergroup, coverpoint, and cross
to measure functional coverage. Functional coverage ensures that all scenarios are tested and
helps identify untested regions of the design.

6. Debug and Analyze Failures

When a failure is encountered, debugging is an essential part of the verification process. Common
steps in debugging include:

 Waveform inspection to trace the problem.


 Reviewing log files for error messages and assertion violations.
 Backtracking the sequence of events leading to a failure.

Agalya P, SCE, ECE Page 2


21EC71 Advanced VLSI Design Module3

Using assertions and coverage information makes debugging easier because it pinpoints areas of the
design that may need further attention.

7. Regression Testing

Once the design has been thoroughly tested and the issues resolved, a set of tests is usually run as a
regression to ensure that new changes do not introduce errors in the design. This is important for
ongoing development where the design might evolve and new features are added.

 Regression Suites: A set of test cases is run automatically on each new version of the design
to ensure all features continue to work as expected.
 Continuous Integration (CI): Often automated to run regression tests on every commit or
change to the codebase to detect issues as early as possible.

8. Verification Closure

Verification closure is the process of ensuring that all aspects of the design have been verified. This
includes:

 Achieving Full Coverage: All coverage metrics should meet the specified goals. This
includes functional coverage and code coverage.
 No Open Bugs: All bugs should be fixed, and no new issues should remain.
 Sign-off: The design is considered verified when it satisfies the test plan and meets the
required performance and functional objectives.

Verification closure typically involves a sign-off report to provide documentation of the verification
results and the areas that have been covered.

Basic Testbench Functionality

The purpose of a testbench is to determine the correctness of the design under test (DUT). This is
accomplished by the following steps.
�Generate stimulus
�Apply stimulus to the DUT
�Capture the response
�Check for correctness
�Measure progress against the overall verification goals.
Some steps are accomplished automatically by the testbench, while others are manually determined
by the verification Engineer.
Directed Testing

Traditionally directed tests are used to verify the correctness of a design. Using this approach, the
verification engineer has to look at the hardware specification and write a verification plan with a list
of tests, each of which concentrated on a set of related features.
Armed with verification plan, the verification Engineer
• Write stimulus vectors that exercise these features in the DUT.
• Simulate the DUT with these vectors
• Manually review the resulting log files and waveforms to make sure the design does what you
expect.

Agalya P, SCE, ECE Page 3


21EC71 Advanced VLSI Design Module3

Once the test works correctly, the verification engineer check off the test in the verification plan and
move to the next. Directed test is an incremental approach that makes a steady progress.

In directed testing, the test progress slope remains the same irrespective of the complexity of th
design. When the design complexity doubles, it takes twice as long to complete or requires twice as
many people. Neither of these situations is desirable. So it is needed to have a methodology that finds
bugs faster in order to reach the goal of 100% coverage.

Figure 1-2 shows the total design space and the features that get covered by directed test cases. In this
design space there are many features, some of which have bugs.

Testbench Components
In simulation, the testbench wraps around the DUT (Design under Test) by applying the stimulus to
DUT and record the responses from DUT through the monitors. So the primary components of a
testbench are

(i) DUT
(ii) Stimulus Generator
(iii) Monitors

Agalya P, SCE, ECE Page 4


21EC71 Advanced VLSI Design Module3

(i) Design Under Test (DUT)


The DUT is the module or unit of the design that you are testing. It could be any piece of digital
hardware that has been written in Verilog or SystemVerilog. The DUT is instantiated within the
testbench, and the testbench interacts with it to simulate its behavior.
(ii) Stimulus Generator
The stimulus generator creates the input signals (test vectors) required to drive the DUT during
simulation. This component generates input values and can follow various testing styles such as
directed, random, or constrained random testing.
Types of Stimulus:
Random Stimulus: Random test inputs generated using SystemVerilog's randomization features.
Directed Stimulus: Hand-written test cases that target specific behaviors or features of the DUT.
Constrained Random Stimulus: A mix of random inputs with constraints to avoid illegal or
meaningless values while still covering a wide range of scenarios.
(iii) Monitors
A monitor observes the outputs and internal signals of the DUT without interfering with the
simulation. It gathers information to be used later for checking correctness or coverage.
Testbench block is also made of many bus functional models (BFM) like the verilog models for
AMBA, PCI, USB and SPI buses that generate stimuls to DUT that you can think of as testbench
components to the DUT and check the responses.

Layered Testbnch
Layered testbench is a modern verification methodology that helps to make the verification task
easier. If the testbench has been written as a single routine that can randomly generate all types of
stimulus, both legal and illegal, plus inject errors with a multi-layer protocol, then the routine quickly
becomes complex and unmaintainable. Layered testbench organizes the testbench into multiple layers,
each with a specific responsibility, which improves the scalability, reusability, and maintainability of
the verification environment. The idea is to separate the different functionalities of the testbench into
logical layers, each layer interacting with the DUT (Device Under Test) in a structured manner.

Agalya P, SCE, ECE Page 5


21EC71 Advanced VLSI Design Module3

The signal and command layers


Signal and command layers form the lower layers of a testbench. Signal layer is the bottom layer and
command layer is the next upper layer. Signal layer contains the design under test and the signals that
connect it to the testbench. Command layer contains driver, assertions and monitor. The DUT‘s inputs
are driven by the driver that runs single commands such as bus read or write. The DUT‘s output
drives the monitor that takes signal transitions and groups them together into commands. Assertions
also cross the command/signal layer, as they look at individual signals but look for changes across an
entire command.
The functional layer
The functional layer feeds the command layer. It consists of Agent, scoreoard and checker. The agent
block (called the transactor in the VMM) receives higher-level transactions such as DMA read or
write and breaks them into individual commands. These commands are also sent to the scoreboard
that predicts the results of the transaction. The checker compares the commands from the monitor
with those in the scoreboard.
The scenario layer
The Scenario Layer in a layered testbench refers to the level of the testbench that manages and
orchestrates different test scenarios or test cases. The functional layer is driven by the generator in the
scenario layer. Generator block in this layer is responsible for defining, controlling, and executing
specific test sequences that verify different aspects of the DUT (Device Under Test) or design block.
For example an MP3 player has to concurrently play music from its storage, download new music
from a host, and respond to input from the user, such as volume and track controls. Each of these
operations is a scenario. Downloading a music file takes several steps, such as control register reads
and writes to set up the operation, multiple DMA writes to transfer the song, and then another group
of reads and writes. The scenario layer of the testbench orchestrates all these steps with constrained-
random values for parameters such as track size and memory location.
Data types
SystemVerilog offers many improved data structures compared with Verilog. SystemVerilog
introduces new data types with the following benefits.
 Two-state: Better performance, reduced memory usage
 Queues, dynamic and associative arrays and automatic storage: Reduced memory usage,
built-in support for searching and sorting
 Unions and packed structures: Allows multiple views of the same data
 Classes and structures: Support for abstract data structures
 Strings: Built-in string support

Agalya P, SCE, ECE Page 6


21EC71 Advanced VLSI Design Module3

 Enumerated types: Code is easier to write and understand.


Built in Data types
System verilog supports the two common data types supported by verilog 1995 as variables (reg) and
net (wire) that holds 4 state values (‗0‘,‘1‘,‘x‘,‘z‘). Variables can be unsigned single or multi-bit (reg
[7:0] m), signed 32-bit variables (integer), unsigned 64-bit variables (time), and floating point
numbers (real). A net is used to connect parts of a design such as gate primitives and module
instances
System-Verilog improves the classic reg data type so that it can be driven by continuous assignments,
gates and modules, in addition to being a variable. It is given the new name logic so that it does not
look like a register declaration. The one limitation is that a logic variable cannot be driven by multiple
drivers such as when you are modeling a bidirectional bus.
Two-state types

SystemVerilog introduces several two-state data types to improve simulator performance and
reduce memory usage over four-state types. The simplest type is the bit, which is always unsigned.
There are four signed types: byte, shortint, int, and longint.

byte is a 8 bit signed variable which will take the value in the range of -128 to +127. Logic [7:0] and
bit [7:0] are 8 bit unsigned variable which will take its value in the range of 0 to 255. Signed variables
may cause unexpected results with randomization. Care has to be taken while connecting two-state
variables to the design under test, especially at its outputs. If the hardware tries to drive an X or Z,
these values are converted to a two-state value, and your testbench code may never know.
Fixed-Size Arrays
SystemVerilog offers several flavors of arrays beyond the single-dimension, fixed-size Verilog-1995
arrays. Many enhancements have been made to these classic arrays.
Verilog requires that the low and high array limits must be given in the declaration. Almost all arrays
use a low index of 0, so SystemVerilog uses the shortcut of just giving the array size, similar to C:
Example for Declaring fixed-size arrays
int lo_hi[0:15]; // 16 ints [0]..[15]
int c_style[16]; // 16 ints [0]..[15]
Multidimensional arrays
Multidimensional fixed-size arrays can be created by specifying the dimensions after the variable
name. This is an unpacked array. The following creates several two-dimensional arrays of integers, 8
entries by 4, and sets the last entry to 1. Multidimensional arrays were introduced in Verilog-2001, but
the compact declarations are new.
Example for Declaring and using multidimensional arrays
int array2 [0:7][0:3]; // Verbose declaration
int array3 [8][4]; // Compact declaration
array2[7][3] = 1; // Set last array element

Agalya P, SCE, ECE Page 7


21EC71 Advanced VLSI Design Module3

SystemVerilog stores each element on a longword (32-bit) boundary. So a byte, shortint, and int are
all stored in a single longword, while a longint is stored in two longwords.
Example for Unpacked array declarations
bit [7:0] b_array[3]; // Unpacked
The unpacked array of bytes, b_array, is stored in three longwords.

An array can be initialized using an array literal that is an apostrophe and curly braces.1 You can
set some or all elements at once. Array values can be replicated by putting a count before the curly
braces.
Example for Initializing an array
int ascend[4] = ’{0,1,2,3}; // Initialize 4 elements
int decend[5];
int md[2][3] = ’{’{0,1,2}, ’{3,4,5}};
descend = ’{4,3,2,1,0}; // Set 5 elements
descend[0:2] = ’{5,6,7}; // Set first 3 elements
ascend = ’{4{8}}; // Four values of 8
Basic array operations — for and foreach
The most common way to manipulate an array is with a for or foreach loop. In a for loop, the loop
variable i is declared local to the for loop. The system verilog function $size returns the size of the
array. In the foreach statement, if the array name and an index in square brackets are specified, then
the system verilog automatically steps through all the elements of the array. The index variable is
local to the loop.
Example for Using arrays with for and foreach loops
initial begin
bit [31:0] src[5], dst[5];
for (int i=0; i<$size(src); i++)
src[i] = i;
foreach (dst[j])
dst[j] = src[j] * 2; // dst doubles src values
end
In the syntax of the foreach statement for multidimensional arrays, instead of listing each subscript in
separate square brackets – [i][j] – they are combined with a comma – [i,j].
Example for Initialize and step through a multidimensional array
initial begin
$display("Initial value:");
foreach (md[i,j]) // Yes, this is the right syntax
$display("md[%0d][%0d] = %0d", i, j, md[i][j]);
$display("New value:");
md = ‘{{9, 8, 7}, 3{5}}; // Replicate last 3 values
foreach (md[i,j]) // Yes, this is the right syntax
$display("md[%0d][%0d] = %0d", i, j, md[i][j]);

Agalya P, SCE, ECE Page 8


21EC71 Advanced VLSI Design Module3

end
Basic array operations – copy and compare
Aggregate compare and copy of arrays can be performed without loops. (An aggregate operation
works on the entire array as opposed to working onjust an individual element.) Comparisons are
limited to just equality and inequality.
Example shows several examples of compares. The ? : operator is a mini if-statement. Here it is
choosing between two strings.
Example for Array copy and compare operations
initial begin
bit [31:0] src[5] = ’{0,1,2,3,4}, dst[5] = ’{5,4,3,2,1};
// Aggregate compare the two arrays
if (src==dst)
$display("src == dst");
else
$display("src != dst");
// Aggregate copy all src values to dst
dst = src;
// Change just one element
src[0] = 5;
// Are all values equal (no!)
$display("src %s dst", (src == dst) ? "==" : "!=");
// Are last elements 1-4 equal (yes!)
$display("src[1:4] %s dst[1:4]",
(src[1:4] == dst[1:4]) ? "==" : "!=");
End
Aggregate arithmetic operations such as addition cannot be performed on arrays. Arithmetic and
logical operations on arrays can be performed only using loops.
Packed arrays
For some data types, you may want both to access the entire value and also divide it into smaller
elements. For example, A 32-bit register has to be sometimes treated as four 8-bit values and at other
times as a single, unsigned value. A System Verilog treats packed array as both an array and a single
value. It is stored as a contiguous set of bits with no unusedspace, unlike an unpacked array.
Packed array examples
The packed bit and word dimensions are specified as part of the type, before the variable name. These
dimensions must be specified in the [lo:hi] format. The variable bytes is a packed array of four bytes,
which are stored in a single longword.
Example for Packed array declaration and usage
bit [3:0] [7:0] bytes; // 4 bytes packed into 32-bits
bytes = 32’hdead_beef;
$displayh(bytes,, // Show all 32-bits
bytes[3], // most significant byte "de"
bytes[3][7]); // most significant bit "1"

Agalya P, SCE, ECE Page 9


21EC71 Advanced VLSI Design Module3

Packed and unpacked dimensions can be mixed. You may want to make an array that represents a
memory that can be accessed as bits, bytes, or longbytes words.
Example for Declaration for mixed packed/unpacked array
bit [3:0] [7:0] barray [3]; // Packed: 3x32-bit
barray[0] = 32’h0123_4567;
barray[0][3] = 8’h01;
barray[0][1][6] = 1’b1;
The variable bytes is a packed array of four bytes, which are stored in a single longword. barray is an
array of three of these elements.

A longword of data, barray[2] can be accessed with a single subscript. A byte of data, barray[0][3]
can be accessed with two subscripts. A single bit, barray[0][1][6] can be accessed with three
subscripts.
Dynamic Arrays
If the size of the array is fixed at compile time, then it is called fixed-size array. If the size of the array
is not known till the run time, it is called as dynamic arrays. System Verilog provides a dynamic array
that can be allocated and resized during simulation. A dynamic array is declared with empty word
subscripts []. This means that an array size is not given at compile time; instead, it is specified at run-
time. The array is initially empty, and the new[] operator is called to allocate space, passing in the
number of entries in the square brackets. If the name of an array is passed to the new[] operator, then
the values are copied into the new elements.
Example for using dynamic arrays
int dyn[], d2[]; // Empty dynamic arrays
initial begin
dyn = new[5]; // Allocate 5 elements
foreach (dyn[j])
dyn[j] = j; // Initialize the elements
d2 = dyn; // Copy a dynamic array
d2[0] = 5; // Modify the copy
$display(dyn[0],d2[0]); // See both values (0 & 5)
dyn = new[20](dyn); // Expand and copy
dyn = new[100]; // Allocate 100 new integers // Old values are lost
dyn.delete; // Delete all elements
end
Dynamic arrays have several specialized routines, such as delete and size. Fixed-size array can be
assigned to dynamic arrays as long as they have the same base type such as int. A dynamic array can
be assigned to a fixed array as long as they have the same number of elements. When a fixed-size

Agalya P, SCE, ECE Page 10


21EC71 Advanced VLSI Design Module3

array is copied to a dynamic array, System Verilog calls new[] constructor to allocate space, and then
copies the values.
Queues
Queue is one of the new data type introduced by system verilog which provides easy searching and
sorting in a structure that is as fast as a fixed-size array but as versatile as a linked list. Like a dynamic
array, queues can grow and shrink, but with a queue you can easily add and remove elements
anywhere.
Example for queue operations
int j = 1,
b[$] = {3,4},
q[$] = {0,2,5}; // {0,2,5} Initial queue
initial begin
q.insert(1, j); // {0,1,2,5} Insert 1 before 2
q.insert(3, b); // {0,1,2,3,4,5} Insert whole q.
q.delete(1); // {0,2,3,4,5} Delete elem. #1
// The rest of these are fast
q.push_front(6); // {6,0,2,3,4,5} Insert at front
j = q.pop_back; // {6,0,2,3,4} j = 5
q.push_back(8); // {6,0,2,3,4,8} Insert at back
j = q.pop_front; // {0,2,3,4,8} j = 6
foreach (q[i])
$display(q[i]);
end
When a queue is created, the SystemVerilog actually allocates extra space so that extra elements can
be added quickly. Queue automatically grows or shrinks based on the elements added or removed
from the queue. It is very efficient to push and pop elements from the front and back of a queue,
taking a fixed amount of time no matter how large the queue. Adding and deleting elements in the
middle is slower, especially for larger queues, as SystemVerilog has to shift up to half of the
elements. The contents of a fixed or dynamic array can be copied into a queue.
Associative Arrays
SystemVerilog offers associative arrays that store entries in a sparse matrix. This means that while
you can address a very large address space, SystemVerilog only allocates memory for an element
when it is wriiten to it. In the following picture, the associative array holds the values 0:3, 42, 1000,
4521, and 200,000. The memory used to store these is far less than would be needed to store a fixed or
dynamic array with 200,000 entries.

Example for declaring, initializing, and using associative arrays


initial begin
logic [63:0] assoc[*], idx = 1;
// Initialize widely scattered values
repeat (64) begin

Agalya P, SCE, ECE Page 11


21EC71 Advanced VLSI Design Module3

assoc[idx] = idx;
idx = idx << 1;
end
// Step through all index values with foreach
foreach (assoc[i])
$display("assoc[%h] = %h", i, assoc[i]);
// Step through all index values with functions
if (assoc.first(idx))
begin // Get first index
do
$display("assoc[%h]=%h", idx, assoc[idx]);
while (assoc.next(idx)); // Get next index
end
// Find and delete the first element
assoc.first(idx);
assoc.delete(idx);
end
Example above has the associative array, assoc, with very scattered elements: 1, 2, 4, 8, 16, etc. A
simple for loop cannot step through them; but it needs to use a foreach loop, or, if you wanted finer
control, you could use the first and next functions in a do...while loop. These functions modify the
index argument, and return 0 or 1 depending on whether any elements are left in the array.
Linked Lists
SystemVerilog provides a linked list data-structure that is analogous to the STL (Standard Template
Library in C++) List container. The container is defined as a parameterized class, meaning that it can
be customized to hold data of any type.
Array Methods
There are many array methods that can be used on any unpacked array types: fixed, dynamic, queue,
and associative. These routines can be as simple as giving the current array size to sorting the
elements.
Array reduction methods
A basic array reduction method takes an array and reduces it to a scalar. The most common reduction
method is sum, which adds together all the values in an array. Be careful of SystemVerilog‘s rules for
handling the width of operations. By default, if you add the values of a single-bit array, the result is a
single bit. But if you store the result in a 32-bit variable or compare it to a 32-bit variable,
SystemVerilog uses 32-bits when adding up the values.
Example for Creating the sum of an array
bit on[10]; // Array of single bits
int summ;
initial begin
for each (on[i])
on[i] = i; // on[i] gets 0 or 1
// Print the single-bit sum
$display("on.sum = %0d", on.sum); // on.sum = 1

Agalya P, SCE, ECE Page 12


21EC71 Advanced VLSI Design Module3

// Sum the values using 32-bits as summ is 32-bits


summ = on.sum;
$display("summ = %0d", summ); // summ = 5
// Compare the sum to a 32-bit value
if (on.sum >=32’d5) // True
$display("sum has 5 or more 1’s");
end
Other array reduction methods are product, and, or, and xor.
Array locator methods
The array locator methods are used to find data (e.g. largest data) in an unpacked array. These
methods always return a queue.
Example for Array locator methods: min, max, unique
int f[6] = ‘{1,6,2,6,8,6};
int q[$] = ‘{1,3,5,7};
tq[$];
tq = q.min; // {1}
tq = q.max; // {7}
tq = f.unique; // {1,6,2,8}
Example above 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. 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.
An element in an array can be searched using foreach loop or through a single operation using array
locator method find. The with expression tells SystemVerilog how to perform the search.
When the array reduction method such as sum and with clause is combined, then the sum operator is
adding up the number of times that the expression is true.
Array locator methods
int count, d[] = ‘{9,1,8,3,4,4};
count = d.sum with (item > 7); // 2: {9, 8}
count = d.sum with (item < 8); // 4: {1, 3, 4, 4}
count = d.sum with (item == 4); // 2: {4, 4}
Choosing a storage datatype
The guidelines for choosing a storage data type based on flexibility, memory usage, speed, and sorting
are as follows.
Flexibility
 Use a fixed-size or dynamic array if it is accessed with consecutive positive integer indices: 0,
1, 2, 3… Choose a fixed-size array if the array size is known at compile time, or choose a
dynamic array if the size is not known until run-time.
 Choose associative arrays for nonstandard indices such as widely separated values because of
random data values or addresses. Associative arrays can also be used to model content-
addressable memories.
 Queues are a good way to store data where the number of elements grows and shrinks a lot
during simulation, such as a scoreboard that holds expected values. Lastly, queues are great
for searching and sorting.

Agalya P, SCE, ECE Page 13


21EC71 Advanced VLSI Design Module3

Memory usage
 The simulation memory usage is reduced by using two-state elements.
 Data sizes that are multiples of 32 bits must be chosen to avoid unused space.
 Simulators usually store anything smaller in a 32-bit word.
 For arrays with a thousand to a million active elements, fixed-size and dynamic arrays are the
most memory efficient.
 Queues are slightly less efficient to access than fixed-size or dynamic arrays because of
additional pointers.
 Modeling memories larger than a few megabytes should be done with an associative array.
Speed
 Array type has to be chosen based on how many times it is accessed per clock cycle. Array
size and type matters only when the array has to be accessed often.
 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.
 Queues have almost the same access time as a fixed-size or dynamic array for reads and
writes.
 Associative arrays are the slowest as it requires more computation than other arrays.
Sorting
 SystemVerilog can sort any single-dimension array (fixed-size, dynamic, and associative
arrays plus queues), based on how often the data is added to the array.
 fixed-size or dynamic array can be chosen if the data is received all at once so that you only
have to allocate the array once.
 Queue can be chosen if the data slowly dribbles in, as adding new elements to the head or tail
of the queue is very efficient.
 Associative arrays can be chosen If you have values that are noncontiguous such as ‗{1, 10,
11, 50}, and are also unique.
Creating New Types with typedef
In system verilog new data types using the typedef statement. If an ALU that can be configured at
compile-time to use on 8, 16, 24, or 32-bit operands, then in Verilog a macro for the operand width
and another for the type can be created. In SystemVerilog a new datatype can be created with the
typedef statement.
Example for User-defined type-macro in Verilog
// Old Verilog style
`define OPSIZE 8
`define OPREG reg [`OPSIZE-1:0]
`OPREG op_a, op_b;
Example for User-defined type in SystemVerilog
// New SystemVerilog style
parameter OPSIZE = 8;
typedef reg [OPSIZE-1:0] opreg_t;
opreg_t op_a, op_b;
Creating User-Defined Structures
One of the biggest limitations of Verilog is the lack of data structures. In SystemVerilog a new
structure can be created using the struct statement, similar to C.

Agalya P, SCE, ECE Page 14


21EC71 Advanced VLSI Design Module3

struct {bit [7:0] r, g, b;} pixel; creates a structure called pixel that has three unsigned bytes for
red, green, and blue.
typedef struct {bit [7:0] r, g, b;} pixel_s;
pixel_s my_pixel; creates a structure called pixel_s than can be shared to ports and routines.
Using the suffix ―_s‖ when declaring a struct makes it easier to share and reuse code
Union of several types
In hardware, the interpretation of a set of bits in a register may depend on the value of other bits. It is
possible to store data of two different types in the same location. For example
typedef union { int i; real f; } num_u;
num_u un;
un.f = 0.0; // set un in floating point format
un.i = 0; // set un in integer format
The above code creates a new datatype num_u of type union to store an integer and real number in the
same location to save memory. Unions are useful when it is frequently required to read and write a
register in several different formats.
Packed structures
SystemVerilog allows to have more control on how data is laid out in memory by using packed
structures. A packed structure is stored as a contiguous set of bits with no unused space.
typedef struct {bit [7:0] r, g, b;} pixel_s;
pixel_s my_pixel;
The struct for a pixel in the above example uses three data values which is stored in three longwords,
even though it only needs three bytes. But if it is specified as a packed structure, it will use the
smallest space possible as three bytes.
Example for Packed structure
typedef struct packed {bit [7:0] r, g, b;} pixel_p_s;
pixel_p_s my_pixel;
Packed structures are used when the underlying bits represent a numerical value, or when it is
required to reduce memory usage. For example several bit-fields are packed together to make a single
register
Enumerated Data Types
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. The simplest enumerated type declaration contains a list
of constant names and one or more variables.
Example for a simple enumerated type
enum {RED, BLUE, GREEN} color;
Usually a named enumerated type is created to easily declare multiple variables, especially if these are
used as routine arguments or module ports. First the enumerated type is createed, and then the
variables of this enumerated type is created.
Example for Enumerated types
// Create data type for values 0, 1, 2
typedef enum {INIT, DECODE, IDLE} fsmstate_e;
fsmstate_e pstate, nstate; // declare typed variables
initial begin

Agalya P, SCE, ECE Page 15


21EC71 Advanced VLSI Design Module3

case (pstate)
IDLE: nstate = INIT; // data assignment
INIT: nstate = DECODE;
default: nstate = IDLE;
endcase
$display("Next state is %0s",
nstate.name); // Use name function
end
The suffix ―_e‖ has to be used when declaring an enumerated type. Default values of Enumerated type
are set to integers starting at 0 and then increase.
Example for Specifying enumerated values
typedef enum {INIT, DECODE=2, IDLE} fsmtype_e;
The above example uses the default value of 0 for INIT, then 2 for DECODE, and 3 for IDLE.
Enumerated constants also follow the same scoping rules as variables. Consequently, if the same
name is used in several enumerated types (such as INIT in different state machines), they have to be
declared in different scopes such as modules, program blocks, routines, or classes.
Example for Incorrectly specifying enumerated values
typedef enum {FIRST=1, SECOND, THIRD} ordinal_e;
ordinal_e position;
Example for Correctly specifying enumerated values
typedef enum {ERR_O=0, FIRST=1, SECOND, THIRD} ordinal_e;
ordinal_e position;
Routines for enumerated types
SystemVerilog provides several functions for stepping through enumerated
types.
�first returns first member of the enumeration.
�last returns last member of the enumeration.
�next returns the next element of the enumeration.
�next(N) returns the Nth next element.
�prev returns the previous element of the enumeration.
�prev(N) returns the Nth previous element.
The functions next and prev wrap around when they reach the beginning or end of the enumeration.
Constants
There are several types of constants in SystemVerilog. The classic Verilog way to create a constant is
with a text macro. On the plus side, macros have global scope and can be used for bit field definitions
and type definitions. On the negative side, macros are global, so they can cause conflicts if you just
need a local constant. Lastly, a macro requires the ` character so that it will be recognized and
expanded.
In SystemVerilog, parameters can be declared at the $root level so they can be global. This approach
can replace many Verilog macros that were just being used as constants. typedef can be used to replace
those clunky macros.
The next choice is a parameter. A Verilog parameter was loosely typed and was limited in scope to a
single module. Verilog-2001 added typed parameters, but the limited scope kept parameters from

Agalya P, SCE, ECE Page 16


21EC71 Advanced VLSI Design Module3

being widely used. SystemVerilog also supports the const modifier that allows you to make a variable
that can be initialized in the declaration but not written by procedural code.
Example for Declaring a const variable
initial begin
const byte colon = ":";
...
End
Strings
The SystemVerilog string type holds variable-length strings. An individual character is of type byte.
The elements of a string of length N are numbered 0 to N-1. Unlike C, there is no null character at the
end of a string, and any attempt to use the character ―\0‖ is ignored. Strings use dynamic memory
allocation, so it is not required to worry about running out of space to store the string.
The function getc(N) returns the byte at location N, while toupper returns an upper-case copy of the
string and tolower returns a lowercase copy. The curly braces {} are used for concatenation. The task
putc(M) writes a byte into a string at location M, that must be between 0 and the length as given by
len. The substr(start,end) function extracts characters from location start to end.
Example for String methods or functions
string s;
initial begin
s = "SystemVerilog";
$display(s.getc(0)); // Display: 83 (‘S’)
$display(s.toupper()); // Display: SYSTEMVERILOG
s = {s, "3.1b"}; // "SystemVerilog3.1b"
s.putc(s.len()-1, "a"); // change b-> a
$display(s.substr(2, 5)); // Display: stem
// Create temporary string, note format
my_log($psprintf("%s %5d", s, 42));
end
task my_log(string message);
// Print a message to a log
$display("@%0d: %s", $time, message);
endtask

Agalya P, SCE, ECE Page 17

You might also like