command-line-debug-using-uvm-sequences
command-line-debug-using-uvm-sequences
Mark Peryer
Mentor Graphics (UK) Ltd
Rivergate, London Rd., Newbury,
Berkshire, U.K. RG14 2QB
Telephone: +44 1635 811614
[email protected]
ABSTRACT a test class that is responsible for defining the configuration of the
The mainstream use case for the UVM is to create a verification test bench structure, starting the top-down build process and then
environment that supports the running of multiple test cases which starting the execution of the chosen set of sequences.
run sequence based stimulus and use automatic checking and
coverage mechanisms to achieve closure on a verification plan. The typical UVM test bench architecture is orientated around the
However, there is another important use case which is not so well interfaces of the Design under test (DUT), with each hardware
addressed and that is the interactive debug of hardware and test interface having a verification component, or agent, associated with
bench bugs. This paper describes a technique which leverages UVM it. The agent contains a driver which is responsible for converting
sequences to implement a command line debugger which can be used abstract transaction objects called sequence_items into signal level
to facilitate efficient hardware debug, and potentially, the debug of activity. Stimulus is generated for an interface inside sequence
the sequences themselves. In practical terms, the technique is objects which create and shape a series of sequence_item objects and
encapsulated in a command line debug sequence package. send them to the driver via component object called a sequencer. Co-
ordinated stimulus between hardware interfaces is achieved through
Using the package allows a user to debug designs more efficiently by the use of supervisory sequences which execute sequences on
being able to interactively run short, targeted tests and to check the multiple sequencers, these are usually referred to as virtual sequences
result using the debug resources of the simulator. The approach is and they are executed via virtual sequencer component objects which
well suited to the early stages of hardware debug or integration contain handles for the target interface sequencers. This architecture
debug where its interactivity allows users to track down simple, but is illustrated in Figure 1.
blocking issues, very quickly. The technique is lightweight,
leverages existing UVM sequences and is orthogonal to the main
UVM use model of building up regressions of test cases.
General Terms
Verification, Simulation, Sequences.
Keywords
UVM, Sequences, sequence wrappers, testbench architecture, debug
techniques, Registers
1. INTRODUCTION
The Universal Verification Methodology (UVM) is a SystemVerilog Figure 1 – UVM Test Architecture
base class library which allows users to construct verification
Once the UVM verification architecture has been established, the
environments using verification component objects and to create
verification process centres around the creation of test cases based on
stimulus using sequence objects. The UVM encapsulates a number of
standard building blocks with well-defined APIs which makes it the use of sequences. The emphasis of the verification process is on
straight-forward for users to collaborate or to build testbenches generating volumes of stimulus as efficiently as possible using
which are interoperable with third party verification IP. constrained random techniques; re-running test cases with different
seeds to create conditions which flush out corner case bugs in the
DUT. When aligned with a metric based, coverage driven
1.1 The UVM Verification Process verification process the UVM has proved to be an effective means of
The UVM makes a clear separation between stimulus generation and verifying hardware using simulation techniques.
the structure of the verification environment. The structure of the
UVM test bench is created during the build phase when the various Once a test case has passed its initial debug phase, it is passed into a
components are configured and constructed, these structural regression suite which is run in batch mode. In the regression suite
components stay in place for the lifetime of the simulation. However, the test case is run with different seeds to catch corner cases. The
stimulus generation is by means of a library of sequence classes priority is on simulation throughput to explore as many parts of the
which have a transitory life time, being created, executed and de- design state space in a given time. This use model is efficient once
referenced as required. Each UVM simulation starts by constructing
the test bench architecture has been completed and once the DUT has sequence library packages developed for the DUT. The main
reached a reasonable level of maturity, but there is a considerable infrastructure of the system is generic, but there are parts of the
period of time where a more interactive use model can facilitate implementation which need to be customised to address the specifics
rapid debug. This is where the use of sequences controlled from the of an environment. A script has been developed to reduce the
command line can prove effective. extraction and customization effort.
• process_cmd_line() – Function that is called by the The code for the sequence wrapper base class is as follows:
command dispatcher, it parses a command line string and
returns a data structure // Sequence wrapper class:
//
• process_cmd_file() – Task to open and read a command // Takes a sequence and wraps it with other helper methods
file and pass each line to the command dispatcher class //
• dispatcher() – Task which takes the command line and virtual class sequence_wrapper extends uvm_object;
dispatches the relevant sequence(s) for execution function new(string name = "sequence_wrapper");
• virtual sequencer handle super.new(name);
endfunction
The package contains an initialization function which is responsible
// Handle for the target sequencer
uvm_sequencer_base sqr; for constructing each of the wrapper tasks and putting them into an
associative array indexed by a string which corresponds to the name
// Template for the help messaging: of the sequence. When a command line request is received by the
virtual function string help();
`uvm_error("sequence_wrapper",
command line dispatcher, it looks up the wrapper sequence in the
"Help method not implemented") associative array, calls the spawn() method to create a new deep
endfunction: help copied object and then executes it. The spawning is required to
enable multiple copies of a sequence to be run in parallel.
// Returns the number of arguments used by run_sequence
virtual function int no_args();
return 0; The sequence does not return any data to the command line because
endfunction: no_args it cannot process returned values, however the result of the sequence
// Needed to spawn multiple sequences concurrently execution is displayed and recorded in the log file:
virtual function sequence_wrapper spawn();
sequence_wrapper c = new(); # apb_read_seq: addr: 0 data:0
# apb_write_seq: addr:0 data: aaaaaaaa
c.sqr = this.sqr; # apb_read_seq: addr:0 data:aaaaaaaa
return c;
endfunction: spawn
2.2.3 The package generation script
// Assign the handle for the target sequencer In order to make the package code relatively painless for the user to
virtual function void set_sqr( produce, a generation script has been developed. The script works in
ovm_sequencer_base sequencer);
sqr = sequencer; two phases.
endfunction: set_sqr
The first phase takes a list of sequence library packages, parses the
// Task to start the sequence from the wrapper
// Generated code goes here ...
sequence descriptions and generates a reference file containing a list
virtual task run_sequence(int arg0 = 0, of target sequences and arguments that could be used with those
int arg1 = 0, sequences. The user then takes the reference file and comments out
int arg2 = 0, those sequences that he wishes to omit from the command line debug
int arg3 = 0);
`uvm_error("sequence_wrapper", package. The user can also comment out sequence arguments and
"run_sequence method not implemented") specify the name of the target sequencer.
endtask: run_sequence
endclass: sequence_wrapper The second phase takes the edited list and generates the wrapper
tasks, the help functions, the virtual sequencer and the dispatcher
The resultant wrapper class that is generated for the example tasks. The generated code is written into files which are `included
apb_read_sequence is as follows: into the command line debug package.
// This code is generated Once the reference file is in place, the process can be run again to
class apb_read_seq_wrapper extends seq_wrapper; capture any new sequences developed as the environment develops.
`uvm_object_utils(apb_read_seq_wrapper) This enables a new version of the debug package to be produced very
quickly. The process can be used with ordinary sequences or with
function new(string name = "apb_read_seq_wrapper"); virtual sequences.
super.new(name);
endfunction
3 USING THE PACKAGE
function string help();
return "apb_read_seq addr; - target sequencer: APB";
Once the package is in place, it is compiled and imported into the
endfunction: help SystemVerilog package that contains the test case classes. Inside any
test class that is going to allow the use of the package, four things
function int no_args();
return 1;
need to be done in order to get things up and running:
endfunction: no_args
• The package virtual sequencer needs to be declared and
function sequence_wrapper spawn();
apb_read_seq_wrapper c;
constructed.
• The handles for the various target sequencers in the
c = new(); package virtual sequencer have to be assigned.
c.sqr = sqr;
return c;
• The virtual sequencer handle in the package has to be
endfunction: spawn assigned to the virtual sequencer in the test.
• At some point in the execution of the test run method, the
task run_sequence(int arg0 = 0,
int arg1 = 0,
package sv_debug task has to be called to enable the
int arg2 = 0, debugger.
int arg3 = 0);
apb_read_seq seq = apb_read_seq::type_id::create("seq"); The following pseudo code illustrates how the debug functionality
seq.addr = arg0;
seq.start(sqr); would be integrated into an UVM test:
$display("apb_read: addr:%0h data:%0h", arg0, seq.data);
$fdisplay(log_fh, "apb_read: addr:%0h data:%0h", arg0, // Example leaving out irrelevant code
seq.data); class with_debug extends spi_test_base;
endtask: run_sequence
`uvm_component_utils(with_debug)
endclass: apb_read_seq_wrapper
// Debug package virtual sequencer
seq_cli_v_sqr seq_cli_sqr;
// Build method building debug pkg sequencer 5.1 UVM Registers
function void build(); The UVM register base classes enable the package to provide a
super.build(); generic set of methods which allow the user to examine and change
seq_cli_sqr =
seq_cli_v_sqr::type_id::create("seq_cli_sqr", this); memory and register content. The UVM register model provides a
// Assign handle to package virtual sequencer handle: task based API for register accesses, eliminating the need for the user
seq_cli_pkg::vs = seq_cli_v; to provide read and write sequences specific to the target bus.
endfunction: build
// Virtual sequencer target sequencer handle assignment The UVM register model is structured to align with the hardware
function void connect(); structure of the DUT, therefore the command line allows the
super.connect();
seq_cli_v.APB = m_env.m_apb_agent.m_sequencer;
dumping of register content on a system, sub-system, block, register
seq_cli_v.SPI = m_env.m_spi_agent.m_sequencer; or register field level simply by specifying a path. When looking at
endfunction: connect register content, the user has the option of looking at the content of
the register model database (referred to as the ‘mirror’); performing a
task run;
#100 ns; // Wait for reset to go away front door read() access using a bus agent; or by performing a back
sv_dispatcher(); // Calls the debugger door peek() access using the simulator data-structure. This capability
global_stop_request(); enhances the debug process, since it is often inconvenient to do a
endtask: run
front door read access which disturbs the state of the DUT hardware.
endclass: with_debug
The UVM register classes also allow memories, or regions of
Once the debug mode is entered, the normal operation of the UVM memories to be accessed either using front or back door access
environment comes to a halt, since the simulation will be blocked methods. The command line package has been upgraded with generic
from advancing whilst a command is being entered, and will advance commands to allow users to dump memory content; to change
in time only when a sequence is being executed. However, the debug memory locations; to load memory with the content of a file; or to
facilities of the simulator will remain available to the user, allowing fill it with random data.
waveform traces, single stepping through code etc to still be used.
Finally, the UVM register map class allows users to access registers
4 APPLICATIONS and memories from different interfaces, something which is
Variants of the command line debug package have been used by important when verifying the content of SoCs using complex
different users to great effect at different levels of design integration. interconnect fabrics which have several bus master ports. The
capability to specify alternative access interfaces has also been added
The package has been used with block level environments to do using a command line argument.
basic register read and write mode debug. It has also been used to
prototype driver code or to develop initialization routines. It has also 5.2 UVM Resources
proved extremely useful in debugging specific scenarios where Using the UVM resource data base offers the possibility of
multiple interfaces need to be stimulated using several sequences in manipulating handles to the target sequencers and the sequence
parallel. wrapper objects more elegantly than was possible before.
At cluster and SoC levels of integration, the technique has proven 6. CONCLUSION
useful for unpicking interconnect issues such as incorrect address The command line sequence debug package has proven to be useful
decoding and data path issues. It has also allowed firmware to be to OVM users. With the advent of the UVM, there are a number of
debugged before being encapsulated in sequences or processor based potential upgrades which should enhance the ease of use of the
binaries. package.