SystemVerilogVerificationUVM1 1LabGuide
SystemVerilogVerificationUVM1 1LabGuide
SystemVerilogVerificationUVM1 1LabGuide
SystemVerilog Verification
UVM 1.1 Workshop
Lab Guide
40-I-054-SLG-003 2011.12
www.synopsys.com
Copyright Notice and Proprietary Information
Copyright © 2012 Synopsys, Inc. All rights reserved. This software and documentation contain confidential and
proprietary information that is the property of Synopsys, Inc. The software and documentation are furnished under a
license agreement and may be used or copied only in accordance with the terms of the license agreement. No part of the
software and documentation may be reproduced, transmitted, or translated, in any form or by any means, electronic,
mechanical, manual, optical, or otherwise, without prior written permission of Synopsys, Inc., or as expressly provided by
the license agreement.
Disclaimer
SYNOPSYS, INC., AND ITS LICENSORS MAKE NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Trademarks (™)
AFGen, Apollo, Astro, Astro-Rail, Astro-Xtalk, Aurora, AvanWaves, Columbia,Columbia-CE, Cosmos, CosmosEnterprise,
CosmosLE, CosmosScope, CosmosSE, DC Expert, DC Professional, DC Ultra, Design Analyzer, Design Vision,
DesignerHDL, Direct Silicon Access, Discovery, Encore, Galaxy, HANEX, HDL Compiler, Hercules, Hierarchical
Optimization Technology, HSIMplus, HSPICE-Link, iN-Tandem, i-Virtual Stepper, Jupiter, Jupiter-DP, JupiterXT,
JupiterXT-ASIC, Liberty, Libra-Passport,Library Compiler, Magellan, Mars, Mars-Rail, Milkyway, ModelSource, Module
Compiler, Planet, Planet-PL, Polaris, Power Compiler, Raphael, Raphael-NES,Saturn, Scirocco, Scirocco-i, StarRC, Star-
SimXT, Taurus, TSUPREM-4, VCS Express, VCSi, VHDL Compiler, VirSim, and VMC are trademarks of Synopsys, Inc.
SystemC is a trademark of the Open SystemC Initiative and is used under license. ARM.and AM BA are registered
trademarks of ARM Limited. Saber is a registered tradem ark of SabreMark Limited Partnership and is used under license.
All other product or company names may be trademarks of their respective owners.
Lab Duration
45 minutes
In this first lab, you will start the process of build a UVM verification environment
using the UVM base classes and macros following the UVM coding guidelines:
Lab Overview
After you log in, you will see three directories: labs, solutions and rtl.
For each individual lab, you will work in the specified lab directory. Should you
have a question during the lab and want to know what the potential solution is, you
can reference the sample solution provided in the solutions directory.
For this first task, you will create a simple test and a program block to execute this
simple test. Use the lecture material as your reference.
2. Open the existing test_collection.sv file with an editor, and look for
the comment that start with: “/ / Lab 1: task 1, step 2”.
• Enter the class declaration as described in the comment
3. Look for the “// Lab 1: task 1. Step 3” comment.
• Register the class with the factory
4. Look for “// Lab 1: task 1. Step 4” comment.
• Enter the constructor code as described in the comments
Note: You will be asked to enter the following statement at the beginning
of each method. This is to help you during debugging. With this
statement embedded in every method, you can easily see how
things are being executed sequentially by setting the report
verbosity to UVM_HIGH. Within the statement, %mis a format
specifier that prints the current hierarchical path.
5. Near the bottom of the file, look for “// Lab 1: task 1, step 5”
comment in start_of_simulation_phase () method.
• Enter the helpful debugging code as described in the comments
6. Save and close the file.
7. Open a new file, call it t e s t .sv. Enter the following test code:
import uvm_pkg::*;
initial begin
$timeformat(-9, 1, "ns", 10);
run_test();
end
At the end of simulation, you should see something like the following:
In this task, you will build a simple environment that includes sequence_item
(packet), sequence (packet_sequence), sequencer (sequencer), driver
(driver) agent (input_agent) and environment (router_env). With very
little effort, you can start to generate stimulus and see interactions between the
sequencer and the driver.
1. Open the packet.sv file with an editor, and look for the comments that
start with: “/ / Lab 1” and enter the following: (If necessary, look in the
slides for the exact syntax)
• The class declaration
• The sa, da, and payload properties packet
To create the supporting methods (print, copy, compare, etc.) for properties in
a UVM class, you should use ' uvm_f ield_* macros embedded within the
' uvm__ob ject_utils_begin/end macros (to be covered in the next
unit). These are already done in the file for you, along with a constraint.
2. Save and close the file.
3. Open the packet_sequence .sv file with an editor, and look for the
comments that start with: “/ / Lab 1”.Enter the following:
• The class declaration packet_sequence
• And the body() method (see comments) ' packet
4. Save and close the file.
5. Open the driver.sv file with an editor, and look for the comments that
start with: “// Lab 1”.Enter the following: .... __.. ........... t
,
• The class declaration 5 i
i
• Print the request (req) sequence item {
in the run_phase () method ..-™, ........................
For now, the driver just gets a packet (req) from the sequencer via the
built-in seq_item_port and displays the content on the console. In future
labs, more functionality will be added.
6. Save and close the file.
7. Open the input_agent . sv file with an editor, and look for the comments
that start with: “/ / Lab 1”. Enter the following:
• Use typedef to create a packet_sequencer class for packet
• Declare an input_agent class
• Create an instance of packet_sequencer and driver
• Create these in the build phase
• Connect the driver’s and sequencer’s TLM ports in the connect phase
Type Name
factory.print() result.
All class type registered in the factory
driver 4 —
via thevuvm_component_utils() and the
input__agent
'uvm_obj ect_utils() macro are printed.
packet
packet__sequence
router_env
If you name your tests properly, you
test__base
can easily identify all of your tests here.
In the previous task, you may have noticed that none of the embedded uvm_info
messages were printed. This is because the default display verbosity of the UVM
reporting mechanism filters out all levels below UVM_MEDIUM. In the
router_env, each of the ' uvm._i.nfo message were set to the verbosity level
UVM_HIGH. The verbosity being filtered out are: UVM_HIGH, UVM_FULL and
UVM_DEBUG. The recommended way to treat these verbosity levels is to use:
Answers / Solutions
test.sv Solution:
test__collection.sv Solution:
class test_base extends uvm_test:;
suvm__component„utils (test_base) ;
router__env env; :
function new(string .name, uvm_component parent);
super .new (name, parent ):;
'uvm_inf o ("TRACE1’, $sf ormatf ("%m" ), UVM__HIGH) ;
endfunction: new
virtual function void build__phase (uvm__phase phase) ;
super .build__phase (phase);
'uvm__info ("TRACE" , $sf ormatf ("%im" ), UVM_HIGH) ;
env = router_env::type_id ::create ("env" , this) ;
endf unction: build__phase
virtual function void start„of__simulat ion__phase (uvm__phase phase) ;
super .start__of_simulation_phase (phase);
'uvm_inf o ("TRACE" , $sf ormatf ("%m" ), UVM_HIGH) ;
uvm_top .print___topology () ;
factory.print();
endfunction: start__of„simulation__phase
endclass: test_base
d r iv e r . sv Solution:
packet,. sv Solution:
'uvm__component_utils (input_agent)
endclass: input_agent
router_env. sv Solution:
class ro:ut;e:
r_env extends uvnrwenv; :.
input__age:nt ,i_agent:';
'uvm_component__utils (router___env)
endclass : ^roiiter__env
packet__s@qu©nce. sv Solution:
task body();
Nuvm_info("TRACE", $sformatf("%m"), UVM_HIGH) ;
if (starting_phase != null)
starting__phase .raise_objection (this) ;
repeat(1 0 ) begin
'uvm_do(req);
end
if (start ing__jphase != null)
starting__phase .drop__object ion (this);
endtask: body
endclass: packet_sequence
Lab Duration
15 minutes
In Lab I, you built a UVM testbench environment class with a packet class that
fully randomized the source address and the destination address. In this lab, you
will create a modified packet class to set specific set of address of interest and
develop a test to execute it.
b u ild
Environment class
connect
s t a r t o f /.simulation
run
extract
Scoreboard Monitor
check
TBD 1 1 1 !!
. . 'f in a l v
DUT
What does it mean to write a test? Often time, it just means to change constraints
within stimulus classes. In this lab, you will create a directed test to exercise only
source address 3 port of the DUT.
In this task, create a simple contraint which constrains the destination address to 3.
If you have time, try writing one more test to override all instances of packet with
packet_da_3. Call this test test_da_3_type. Compile and simulation to
make sure it works properly.
A n s w e r s / S o lu t io n s
test_collection. sv Solution:
class test_Joase extends uvm_test;
packet_da_3.sv Solution:
constraint da___3 {
da == 3;
Lab Duration
30 minutes
Many runs,
Add/Change ^ T e s t c a s e Functional
constraints I
Modifications / 1 holes
p ro g ra m automatic test;
// class definitions
initial begin
runjtest ();
end
endprogram
Environment class
Agent Agent
TBD TBD
DUT
•.... ————
Sequences are where stimulus are created. The ability to manage what happens
within sequences is important in the development of individual tests. In this task,
you will add configuration fields to constrain the source address and the destination
address in each packet object. You will also add a field to control how many
packets objects to generate per execution of the sequence’s body () task.
In lab 2, you used OOP inheritance to set the packet’s da to 3. With the updated
packet_sequence, you can do the same thing by setting the sequence configuration.
If you set the ID and Message fields of the UVM Report mechanism appropriately,
you can make use of them during debugging to quickly isolate issues.
With sequence configuration, you now have the capability for both minimal code
and constrainable stimulus generation!
In the interest of lab time, the reset agent has been done for you. You just need to
embed it into the environment.
There are times when you need to trace the problem in simulation by conducting an
interactive source code debugging session. The following steps will take you
through a simple example.
You will see that run-time switch used for the interactive session is -gui
2. Start DVE in interactive mode
> make dve_i
Y o u r te s tb e n c h
F \u vrn_neg_seq ue n ce_0 .. 33 de x x r,c UVK~ PKG : V
* \uvrn_callbacks initialize .A
f \u v m _ p h a s e :add unnarn 25 x nc 1 ude ‘1 r o s ^s vfe ‘'
F \u v m _ phase get_dom ain
26
if n d e f Nu nvh IN PKG
f \u v m _ c o m p o n e n t"n e w u %%
r ,.uvm_neg_iterri d o _oop y ' e n d if
S o u r c e c o d e p a n e w i l l d is p la y t h e
f \uvm_neg_tlrn_adapter b 30
21 ' ifd e ± m o d u l e / i n t e r f a c e /p r o g r a m /c la s s
r ^ v m _ m e m configure .u...
\uvm_reg__map s et_sub 22 'mclu t h a t y o u d r a g a n d d r o p i n t o it.
f
r \uvm_reg__map get_sub
33 'defin F o r t h is la b , i t d e f a u lt s t o t h e
34 "e n d i f
r \uvm _ re g _ m a p X get_bu 35 U V M p a c k a g e . I f in te r e s t e d , y o u
f \u vm _reg _m ap Xget__bu 3*8 c a n b r o w s e t h r o u g h th e e n t ir e
F \u vm _reg _m ap Xget_bu... n me
r \ uvm _callbacks_0"initia1 1 58 me U V M s o u r c e c o d e h e r e .
f \uvm _callbacks_1 imtiali
'include 1comps/coraps.svh11
40 'include ";eq;seq.svh"
f \uvm _ c a llb a c k s _ 2 mitiali
41 'include 111Ira2/1lm2.svh11
f \u vm _ca 11ba ck s _ 3 ■■i n itia 11 42 ' include 1reg/uvm__reg_jiQdel.svh"
F \u v m callbacks 4 .mitiali
Slmh
hierarchy T yps ’
Variable Value; Type
- Q te s t (test) Prograrr D uvrr_start_uvrn Bit
+ 3 driver Class Def ■0 uvrr_aa_string.. String
: + @ iri p ut_age nt Class Def D uvrr__global__ra.. Int
: + @ packet Class Def 0 max[31:0] Int
Expanded
; + Q packet_da_3 Class Def ■■ D U V M JJN B O U ... Int
content
■ + Q packet_seque Class Def D s_conriection_. String
x : + £ i reset_agent
: + Q reset_sequerice
Class Def
Class
D s_connectiori_..
DefD s__spaces
String
String
Para...
+ @ reset_tr Class Def UVM_HDL_MA.
; 4- 0 router_env Class Def # uvrr_rngc_copy Para...
■ t @ test_base Class D ot uvrr_cdn_copy. Para...
+ CS test_da_3_inst Class De 7\pt uvrr_snps_cop Para.
j + ® test_da_3_seq C lassJD gp^ Wr~w uvrr_cy_copyri. Para..
! + 0 test_da_3_type Class Def # uvrr_nevision[7 Para...
!+ unnarred$$_4 Named Begn # UVM_STREAM. Para...
Q j vrrr_cu sto m_i... Mod u le m UVM_RADIX[3.. Para...
gf uvrr_pkg (uvrn... Package # UVM_MACRO_ Para...
+ (^_MCS_unit__1 (... $unit « UVM_DEFAUL.. Para..
m UVM_ALL_ON[. Para...
m UVM_FLAGS_.. Para...
m UVM FLAGS .. Para...
Within the source code pane, if you entered a source code, you can return back to
where you were by clicking on the scope forward and backward buttons:
\ r -J
m!k.
ill
Source code debugging of simulation involves two general mechanisms: break point
and single-stepping .
For break point, browse through the source code and click on the line number where
you want to set the break point. On the first click, a solid circle will appear next to
the line number. 1 B. program av;toraa 1i c test ;
2 import uvru pkg::*;
3
4 " ine1 ude "test collection.s v 1'
S in itia l begin
WllgSgM $tim e fo r m a t(- 9 , 1, "ns", 10) ;
m $
9 end
10
11 endprogram
On each subsequent clicks on the same line, the solid circle will change to a clear
circle, then disappears, then back to a solid circle and so forth:
i w
| i n i t i a l bet'- i in it ia l b e g in
6 w m m . i n i t i a l b e g in £
7 ] $tim e fo rm a t (- m n s>time form at ( ? £ tim e fo r m a t
• 8 O B (BEBKSBBB s
9 1end end 9 end
h h h h
10 10 10
1 .
.. \J
program autom atic te
n b e rT \
import uvTivjpkg: : *;
end
The solid circle is an enabled break point. When you click on the continue button,
(or F5 key) simulation will execute up to that line (yellow arrow) and halt.
The clear circle is a disabled break point. It will have no effect when the continue
button is clicked. It’s a convenient reminder of where a break point can/should be
for that debugging session.
Single step controls for all Single step through Step out of
code including modules all Testbench threads subroutine
6. Click on the |||l button to single step through all threads in testbench
You are now in r u n j t e s t () subroutine scope.
7. Look at the bottom of the source code window, you should be able to see what
file the source code is in and where to locate the file:
p <5oto |%*>bai&pps3/vcg_201l.Q3-l,fetc/uw>-1.G/basewvm_globals.s\*h
§ uvmjjfobals.svh I
z z r ^ ~ ....
File in which the current
source code resides
You should see that m_inst is a static uvm_root handle. The find
mechanism combined with the file location can be very helpful for you to
quickly pin point where to examine and correct code when necessary.
Do you see that uvm_top is created at the beginning of simulation via the
get () subroutine?
What about uvm_test_top? How is that created. Continue to find out.
11. Click on to leave the subroutine and go back to the caller scope
What is top handle pointing to now?
12. Click on a couple of times to enter the uvm_root’s run_test ()
method
The source code now starts to get complicated. So, we will focus just on the
creation of the uvm_test_top object
13. Click on £ jj| a few times to get to the following statement:
test_name_count = clp.get_arg_values ("+ U V M _ T E S T N A M E = " ,test_name) ;
Here is where your + U V M _ T E S T N A M E run-time option is read and stored as
the test_name.
14. Click on until you get to the following statement:
$cast (uvm_test_top, factory.create_component_by_name (test_name,
"" , "uvm_test_top", null));
At this point, you have the full initial structure! Components with parent
handle set to null are
children of uvm_top
■uvm t e s t , to p
You can step through the rest of the base class code if desired. However, you
will find it overwhelming. So, you will better off to go to your own source
code and see what’s happening.
The rest of the lab is left up to you for experimenting with DVE debugging.
Just a few more notes:
If you want to restart the simulation, just click on the Restart button:
If you want to see the value of local properties of the scope that the source
code pane is in, look under the Local tab:
JIIIIIIIU" .........IJ".......
;* II
Vena Die Value Type
f-.this class test_base j
Answers / Solutions
test__e©llection. sv Solution;
packet_sequence.sv Solution;
valid__da .delete () ;
for (int i= 0; i<16; i++)
if (da_enable[i])
valid_da.push__back(i);
endfunction
task body();
'uvm__inf o ("TRACE" , $sf ormatf ("%m" ), UVMJHIGH) ;
if (starting_phase != null)
starting_phase .raise_ob jection (this) ;
endclass
reset_sequence.sv Solution:
f unctaon;:;.;;new'(s'tring VhameV'^.:.T-xes-Bt_s0c3la;e:
n-ce'*r.)7
super.new(name);
'uym__i.nfo ("TRACE", $sf ormatf (”%m" );, UVM__HIGH) ;
endfunction
task body();
suvrn_info ("TRACE" , $sf ormatf ("%m"), UVM_HIGH) ;
if (starting_phase !- null)
starting_phase.raise_objection(this) ; ■
if (starting„phase != null)
starting__phase *drop„obj ection (this ) ;
'::.endt>a;s:k■;';; . ■ . ■ ■ ■■
endclass
router_env. sv Solution:
suvm_component_uti 1s (router__env)
p *? Lab Duration:
30 minutes
Modifications / holes
./ L—
DUT
Lab Overview
Up to this point, you have not driven any test stimulus through the DUT. In order to
do this, you need to embed and configure DUT virtual interfaces in physical drivers
and implement the device drivers.
In this lab, you will add the DUT virtual interface and other configuration fields to
the driver, reset sequence, agent and environment. The device drivers will be
written for you.
3. Add the ability to designate the driver to only drive a chosen port with an int
property called port_id with the default value of -1:
Notice that the virtual interface handle (sigs) is not added to the
uvm_component_utils macro list. This is because there is no support in
the uvm_component_utils macro to accommodate virtual interfaces.
seq_item_port.item_done () ;
endtask
To save lab time, the start__of_simulation phase and the physical device driver
methods are done for you.
7. Save and close the file
The agent which contains the sequencer, driver and monitors should configure its
own sub-components. Then, at the test/env level, the focus of configuration will
only need to target the agent of a given interface.
Since the configuration calls are the same as what you have already done, there is no
learning point in going through a typing exercise to enter the code in the agent. All
the configuration code have been done for you in input_agent.sv.
Take a look at the code if you are interested. Otherwise, continue on to the next
task.
Even though the DUT virtual interface was added in the driver, you have not yet
configured it in the test. This is a fatal error that you must correct.
How many packets did the driver process? (Hint: DRV_RUN count)
But, did these packets propagate correctly through the DUT? Check it in the
DVE waveform window.
2. Open DVE with the following command:
> make dve
You should see that all output values are red (unknown)! This is because the
DUT needs to be reset before it can successfully process inputs.
3. Exit DVE
task body();
'uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
if (starting_phase != null)
starting_phase .raise__ob jection (this) ;
if (starting_phase != null)
starting_phase.drop_objection(this) ;
endtask
You should now see that the output signals no longer are red. However, the
base test was designed to send 10 packets through the DUT. In the waveform
window, this is not what you are seeing. There is still a problem.
With the reset agent and reset sequence, the only thing that happened was the
assertion and de-assertion of the reset signal. How about the other control signals of
the interfaces? The reset agent and the reset sequence should not be responsible for
taking care of all signals of the DUT. Doing so will complicate the development of
individual tests and integration.
There two ways to resolve this problem. One, create and configure a sequence to
de-assert the the control signals. Or, two, de-assert the control signals with the
pre_reset_phase () and reset_phase () methods.
In this lab, you will embed the de-assertion of control signals within the individual
driver of a given interface. You will implement the pre_reset_phase () and
reset_phase () methods.
You should now see the correct behavior: 10 packets came out of the DUT.
3. Try and run the destination address is 3 and 20 packets test:
> make test=test_da_3_seq
There are times when you need to trace the problem in simulation by conducting an
interactive source code debugging session. The following steps will take you
through a simple example.
You should see the following panes in the lower portion of the DVE window:
i
i f ji^: '105500 ' :req action req $agent$seqr ■ NORM XACl START
i" p 130500 ;uvrrjest,< ...r::catch ver $DRV_RUN■ NORM NOTE START
m p 'l3 0 5 0 0 " " ; req action neq $agent$seqr * NORM XACl START
amstacKJ
Stream browser
(for UVM - components and log messages)
For UVM, the automatically recorded streams are the UVM sequence
transactions and the UVM log messages. For this lab, you will only be
looking at the VMM/UVM - ms l o g folder.
| Tff
■■■■ill User - msglog ■ 0 reporter [LOW]: ...:catch j report_serMrer
■■••fll User - tblog L+i W o .............. iuvrr^testJop,env.r .: ...:catch i report server
m VMM/UVM - msglog i+: () juvtr mte s t jo p ,env . \ j i catch : report_server
••••Es; LOG5 RNTST * W o .............. juvrr^tesMop.env.i^;i catch j repo rt___seu rer
S S o............... i reset_sequence ...action ! reset_sequence
■■••iEsi LOG5 RSTCFG
* W o .............. | req ...action : req
•■••ED LOG$DRV_CFG 1500 |req
+ : ...action ; req
■■•■ilo LOG$AG NTCFG • 16500 | packe't_sequence i ...action | packet_sequence
■■■■05! uvm_test_top$env$r_agent$seqr Si 16500..... i req ; ...action req
-•
■■■■ uvm_test_top$env$i_agent$seqr ' i " 61500..... ju v r r j e s tjc .p env ij i .: catch report_server
-!M!LOG$DRV__RUN r°"
m
■■• LOG$ UVMTOP
J ~3(sw*:F
User - msglog
User - tblog Type of message:
VMM/UVM - msglog
TjLOG$RNTST XACTION for transactions
Z3LOGSRSTCFG
Ji_agent$seqnw NORMAL :TION j START i
-ni LOG$DRV_CFG XA(%ION START
NORMAL
3LOG$AGNTCFG lL i XACTION : START ;
Z3 uvm_1est_top$env$ r_age nt$seqr $i_agent$seqn« NORMAL"" iN j START :
■i uvm_te st__top$env$i_agent$seqr .$i_agent$seqrj» NORMAL jXACTldft^TARfl
,$i_agent$seqns NORMAL XACTION TSTART ]
Severity of message:
Transaction stream recorded NORMAL for transactions
For example, in the driver code, there is a s uvm_info embedded with the
message id of DRV_RUN. This will show up in the browser window under
LOG$DRV_RUN.
Component Configuration Lab 4-11
SystemVerilog UVM Workshop
Lab 4
5. Click on LOG$DRV_JRUN in the browser window to see all the log messages
for mess^ e id DRV.RUN:
Verbosity of message: Severity of message:
Use filter to quickly locate Where message was generated MEDIUM, HIGH, FATAL, ERROR,
message id of interest FULL and BEDUG WARNING and NORMAL
l& re d Frorr begin Sgver^^'iiifilP^Vpelll|
S're~T
] Tirne 5ave-dr;-
-IM I LOG$RSTGFG
+ - 49500 i uvrr_test_top.env.i___agent.dr/ [MEDIUM] :i ...r::catch ; .ver ...$DRV__RUN!« NORMAL jf c T E iS TAR TI
- [S3 LO G $ D RV_C F G
>. + - 114500 : uvrr_te st_to p .e nv. i_age nt.drv j M E D1UM] i ...r::catch 1 ...ver: Z$DRV__r u n ;b ’ n o r m a l ” [NOTE...... ....[ s t a r t
~E§3LOG$AGNTCFG - - 187500... uvrr_test_top.env.i_agent.drv [MEDIUM]... ;i ...r::catch | ...ven [[$DRV__RUN:n ' n o r m a l ”I n c it e ...... .....fSTART*
- Eli uv r n je st_to p $e nv$ r_age nt$: + 276 5 0 0... : uv rr J s st_to p ,env. i_age nt.d rv [ M E D1U M]... . ..r::eaten j ...ver; ...$DRV _RUNi*' n o r m a l ”Tn o t e ...... .....[ s t a r t s
- ESI uvm_te st_to p $e nv$ i_age ntE ikS 333500 i uvir_tBSt_top.env.i_agent.drv [MEDiUM]... r::catch | ...ver; ...$DRV_[ r UN:* n o r m a l ” [ n o t e ...... .....VSTARTs
-vLOG$DRV RUN
.I..0.0.$ I..IVMT.OP User errorsJP
Type of message:
Simulation time when message was generated Method that created message
NOTE for UVM log messages
At the upper right hand corner of the transaction pane, there are two drop
down tabs for severity and type. Clicking on them will enable you to display
only the severities and types of the messages of interest:
dw height rwghrfi “3
j7 f a il u r e
eriiy Severity Type Targr
V NOTE
TtfOTTt
m ttM r
a NORMAL NOTE STpRT |7 DEBUG
DRMAL ; NC ■ NORMAL NOTE START 17 REPORT
3RM AL NC > NORMAL ; NOTE jTTART
17 NOTIFY
DRMAL INC t WARNING NOTE I tart
EARNING N O ] # ERROR NOTE I tart 17 TIMING
Once you located the transaction and UVM log messages, you would typically want
to see the transaction/log message on the Wave window. One quick way of finding
a stream is to make use of the stream filter.
J Strsarr Scope
P,1 User - msglog
. Q j User - tblog
- n VMM/UVM - msglog
E 3 uvtr _te st_to p $e nv$ r_age nt$ seq r
111 uvirjest_top$env$i_agent$seqr
;
f ] VMM/UVM -tblog :|
As you type, you should notice that the stream source browser window is
updated dynamically to show you the result of the filter.
7. Click on uvm _t@ st__top$@ nv$reagent$s@ qr
This will display the reset„sequence and reset_.tr object re q .
| VM M /U V M -tb lo g I
1
s 0
i ~ 1500 \ •kind: ASSERT
: ...nsaction
,-i ...nsaction
m
m ' l y Z c :L
1CHILD
^ F IN IS H
I I + •• 1 5 0 0 - 1 6 5 0 0 ^ ve q ...nsaction neq Ft,r \XACTION jS T A R T
You will see the START and FINISH times of the transaction
9. Click on the Right Mouse Button on the transaction, add it to Wave window
B H H I I | Message m M n M H Streamscope seventy Type
3 0 - 16500 j re s e t_ s e q u e n c e ..nsaction : ...encej ...$r_agent$secjrj« NORMAL iXACTION iSTART
j re s e t_ s e q u e n c e l S i : : : ;:f ‘i ;' : rV'::4r^^ V::5 ? * ' ' ^ : ; V ; - ' r [ S T A RT
= 165 0 0 .. n sa ctio n i e ?'; ?| . ; • •• • •?$ ^ qri ■ N ■::;R iv•,■ I i.;<.*>.07?O N j FINIS H
Sr_agent$seqn NORMAL iXACTION ISTART
= 0 | req □ Show Source START
•I : C H IL D ...
Add To Waves
= 1 50 0 k L r td r ij T [ f in is h
~ 1 50 0 - 1 6 5 0 0 sneq
Add vanabte? T o Wsvec ION TS TAR T
Sync Tran radian Q onM p Create new group
ShowTfsns&cta Rgl<one-
10. In the Wave window, click on the zoom out button a few time to see the
reset_sequence fully displa^H tfthe start time and clear at the finish time.
~U!!i » i ____________
rressHsequeice
wrV mri^
(Mi u'vmje st_to p., @ 0 @ 1500
*00 @ 76500
With only transaction displayed, it’s hard to tell what’s going on. You need to
see the DUT signals to start to be able make sense of things.
11. Click on Window -> TopLevel. 1 to go back to the Hierarchy pane
m Bfc dm Vjftw K jirifiJ^f Signal
1 0 ^1&0ps - ^ N&w
1 3&M j^ ^ p n y F d g r set Tfa* f-rame rartj*t *
; - : J | ro u te r_ te s t_ to p ... M i j--©-clk
! $ f | | d u t (ro u te r) tm h i reset_n
Ih o s t f h o s t J o ) Irlj B - 1 fra m e _ n [1 5:0]
I f me Copy
B H ...si..
.QteS^ — llllllll ro u te r
H Shaw Source lllllll
Q Show Schematic i 5:0] 12 in it ia l
13 $vcdp
U Show Path Schematic 5 0]
lllflllj fo re ’,
Add To W aves £sfew W mm View
Add To y e ts Recent (Wave. 1) Ctrl+4
ftdcl To ofc-up^ P Ofe&te new grc u p
AGd To watches
W ave 1
13. Go back to the Wave window, you should be able to see the reset_sequence
timing with respect to the actual DUT interface signals
rr r^ tlSQO.HSSOCt j
■tojuvrr_test_top... neq I & 0 @ 1500
!1*00 0 16500
•B- C!K 0
■0 reset_n 1'bo:
• 0 frame_n[15:0] 16'hxxxx
■0 valid_n[15:0] 16'hxxxx
14. Go back to DVE TopLevel. This time, in Stream browser pane, add
uvm_test_top$env$i_agent$seqr to the Wave window.
_ _ _ _ _
*seqr
1 Options * | Iime:(RDm3f
j Scope
User - msglog r Ttrre(100psl
I"*! User - tblog
!+ ‘ 16500 packet_s
+ 16500 req
□ VMM/UVM - msglog | +' ” 81500 neq
U u v m je st_to p$env$ r_age nt$seqr
{+“ 211500 eq
Acid To W aves New Wave view
VMM/UVM - tblog
Arid Variables To Waves * Re oe nt (Wave. 1) Ctrl+4
Expand Atl r create rew group
C&H&pse All Wave 1
Sgl&ct All j -----------------------------
h'E;- elk
i ■B reset_n
0 do u t[1 5 :0 ]
a busy_n[15:0]
+ D va lido_ri[16:Q ] \ I fffe ). If7ff ( { dfff i i bfff i
+ B fra rre o _ n j 1 5:0] bfff II fff7
15. Place the cursor over the triangle table for each transaction to see the content
of that transaction
@ 260500
payload[0]: fO
payload[1]: S'c
payload[2]: 38
payload[3]: 65
For the UVM log messages, you can do the same thing.
16. In the Stream browser pane, change to filter to *LOG
You will now see only the log message streams.
*l o g | ..... ...............................
1User - msglog
2 3 User - tblog
- ^ V M M /U V M - msglog
SLO G $R N TST
JT3 LOG$DRV_RUN
r"JLOG$UVMTOP
rMM/UVM - tblog
17. Right-click on LOG$DRV_RUN and add the stream to the Wave window
Once again, you can place the cursor over the triangle tab to see the content of
the message. One thing you should notice, UVM log messages do not have
start and finish time. Yet, in the display, the UVM log messages spand over a
period of time. This is not entirely accurate, but is done for visualization. The
simulation time at which the UVM log message is generated is treated by
DVE as the start time. The UVM log message then persists until the next
UVM log message of that stream is generated. So, in DVE, once the UVM
log message stream starts, you will never see a gap in between the messages.
The knowledge that you gained in this exercise may help you to debug your
code in future labs.
The rest of the lab is left for you to do your own exploration.
For more information on the DVE debugger, consult the user guide for DVE.
(see $VCS_HOME/doc/UserGuide/pdf/dve_ug.pdf)
Answers / Solutions
test_Gollection.s v Solution:
class test_Joase:extends uvm_test;
suvm„component„utils (test__base)
router_env.env;
d r i v e r . s v Solution:
suvm__component_utils_begin (driver)
vuvm__field__int (port_id, UVMJ3EFAULT I UVMJDEC)
vuvm_component_utils_end
forever begin
seq_item_port.get„next__item (req) ;
if (port__id inside { -1, req.sa }) begin
send(req);
'uvm„info("DRVJRUN" , {"\nn, req.sprint() }, UVM_MEDIUM) ;
end
seq__item__port.item__done () ;
end
endtask: run_phase
//
// See file* for device drivers
S lK I S l^
endclass: driver
reset__sequence. sv Solution:
task body();
suvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
if (starting_phase != null)
starting._pb.ase .raise_ob jection (this);
if (starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
Lab Duration
60 minutes
hh■ *0m«m1
Getting Started
check.
Identify
Modifications holes
........
—
DUT
wmmU
Lab Overview
You have now driven the test stimulus sequence through the DUT.
Similarities: both need access to DUT virtual interface. For the labs in this
workshop, both need to be configured to handle a specified port of the DUT.
Differences: driver has a built-in TLM port for communication with the sequencer,
but monitors require the implementer to create the required TLM port(s).
Two monitor types will be needed for the lab, one for monitoring the input to the
DUT and one for monitoring the output of the DUT. The input monitor is called
iMonitor. The output monitor is called oMonitor.
In this task, you will implement TLM analysis port in the input monitor. The
physical device drivers and the fields identical to the driver are coded for you.
Note: TLM ports in UVM do not have factory support. You cannot
construct the TLM port with the proxy create () method. You
must construct it with the constructor new ().
Lab 5-4 Monitor and Scoreboard
SystemVerilog UVM Workshop
Lab 5
forever begin
tr = packet::type_id: :create ("tr", this);
tr.sa = this.port_id;
get_packet(tr);
'uvm_info("Got Input Packet", ("\n", tr.sprint ()>, UVMJMEDIDM) ;
analysis_port.write(tr) ;
endtask
The input_agent class currently only contains a sequencer and a driver. You
need to add a monitor to the agent to complete the class definition.
Agents can operate in one of two possible modes: active or passive. When
configured to operate in the active mode, all three members (sequencer, driver and
monitor) must be constructed. If the agent was configured to operate in the passive
mode, only the monitor will be constructed. In the active mode, the sequencer's
TLM port also need to be connected the driver's TLM port.
In the uvm_agent base class, the is_active flag is built in for this purpose.
You will construct and connect the sub-component based on the state of this flag.
The existing environment only has one instance of the agent. Whereas the DUT has
16 ports that need to be tested. In this task, you will change the single instance of
the agent in the environment to an array o f 16 agents. Because there are 16
individual agents, they will each need to be configured to a dedicated port.
You should see that 160 packets were processed (16 ports X 10 items each)
UVM has minimal scoreboard support. Here you will try out the bare bone
scoreboard implemenation.
You will need two TLM analysis exports to bring in packets from the input
monitor and the output monitor.
3. Add the following TLM exports: Passing iMonitor
packet to comparator
uvm_analy sis__export # (packet:) be£ore_export;
uvm_analysis_export # (packet) a£ter_export ; Passing oMonitor
packet to comparator
4. In the build phase, construct the comparator and set the analysis exports to
reference the comparator’s ports:
'include 11scoreboard.sv"
Ninclude "output_agent.sv”
endfunction
5. In the connect phase, connect the scoreboard to the agents’ analysis ports:
endfunction
** Report counts by id
[Comparator Match] 153
[Comparator Mismatch] 6
[DRV_RUN] 160
[MISCMP] 12
The simulation is reporting that 160 packets were detected in the input but only 159
packets were observed at the output.
This is the expected behavior. The cause of the missing output is due to the latency
of the transaction flowing through the DUT. Since the objection were only raised
and dropped on the input side, as soon as the input is done, as far as the UVM
simulation is concerned, everything is done because there are no existing objections.
This is a common problem in UVM testbench. There are multiple ways to solve this
problem. One can add objection mechanisms to the monitors, but it will be costly in
terms of performance.
One way to correct this is to take care of the expected latency on the input side by
implementing an objection drain time. If an objection drain time is set, then when
the objection count reaches 0, the phase must wait for the drain time to elapse before
terminating the phase. If another objection is raised during the drain time, the phase
objection mechanism starts over and waits for objection count to reach 0 again.
** Report counts by id
::::Mfttp:ar:;at:t;ii§:|K:ft;- J ; : ® # : ::W;::ii-n^ :^ ::C;:;;:::;^ ;;:K■;:i];ii;!:Iv'
[Comparator Mismatch] 6
[Scoreboard Report] 1
You should see that 320 packets (20 packets per input port) were successfully
matched. If you see other error, then you have made a mistake in your
testbench code that needs to be corrected.
If it passes, what’s the problem? The problem is that UVM only provides a
mechanism for checking in-order sequence comparison. The DUT you are
testing can have simultaneous input and output packet observed at different
ports. Which one of these output packet will be checked against the input
packet? It is non-deterministic. Thus the lab problem arises.
Again, this is a common problem in UVM testbenches.
How can one solve this problem? I f the sequence is truly out-of-order, then
one must write an out-of-order scoreboard from scratch. If the sequence is in-
order, but, there are multiple streams of in-order sequences at the same time,
then the UVM’s uvm_in_order_class_comparator class can still be
used to implement a multi-stream scoreboard.
A multi-stream scoreboard has been coded for you. Try it out in the next step.
7. Open the router_env.sv file in an editor
8. Replace the include statement for scoreboard.sv with an include
statement for ms_scoreboard.sv
9. Save and close the file
A n sw e rs / S o lu tio n s
test.__collection.sv Solutions
class test„base extends uvm_test;
\uvm_component__utils (testjoase)
router__env env;
factory.print();
endfunction
endclass
router„env.sv Solution:
suvm_component__utils (router__env)
endfunction
endclass
in p u t _ a g e n t . s v Solution:
'uvm^componentmutils„begin(input__agent) ::
Nuvm_f ieldjnt (porf__id, UVMJDE FAULT | UVM„DEC)
suvm_eomponent_ut ils__end
endclass
suvm_component_utils_begin (iMonitor)
suvm_fie.ld_int (port_id, UVM_DE FAULT | UVMJDEC)
vuvm_component_utils__end
//
// See file for the device driver code
endclass
oMonitor. s v Solution;
suvm_component__utils_begin (oMonitor)
suvni^field„int (port_id, UVI^LDEFAULT 0:
\uvm_component__utils_jend '
function ,new:
(string name, uvm_component parent):; ::
super.new(name, parent);
'uvm„info("TRACE", $sformatf ("%m" ), UVM__HIGH) ;
:
en:
dfunction
endtask
endclass
scoreboard, sv Solution
xuvm__component__utils (scoreboard)
comparator =
uvm_in_order_class_comparator# (packet) ::type_id ::create ("comparator ”, this);
bef ore_export = comparator .bef ore_export;
after__export : = comparator ,after„export;
endfunction
endclass
ms_s c o r e b o a r d , sv Solution
'uvm__analysis__imp__decl (_before)
suvm_analysis_imp_decl (_after)
.8u-ym_eomp9 n.ent_ut.ilS:(.scoreboard)'
endclass
Getting Started
Through the first five labs, you have developed a complete verification platform to
ise the DUT. In the next two labs, you will expand the testbench to add greater
ity for even more productivity.
'''■ ■ ■ • ''. .- ■■■' -.
Constrainable Many runs,
Random Stimulus
Generation
Directed
Add/Change jf^Testcase
constraints
Identify §
Modifications holes f
Environment class
Agent
Driver Monitor
Sequence Library
You now have a complete self-checking verification environment. How can you
raise the productivity of the verification environment even higher? One way to do
this is to create a sequence library that can be reused through integration of blocks
and across projects.
endfunction
In this task, you will prepare the existing packet sequence for possible registration
into the sequence library.
// 'include "packet.sv"
import packet_seq_lib_pkg::*;
If you do not add the above code, you will find that when you execute this
sequence from the sequence library, the starting_phase will be null.
Therefore, phase objection will not be available for setting the drain time.
The potential consequence is that the final outputs of the DUT may not be
observed.
6. Save and close the file
Up to this point, you have created the sequence library and set the sequencers to
execute the sequence library. However, there is currently no sequence registered
with the sequence library. If you were to run the test now, nothing will happen.
In this task, you will add the packet_sequence to the sequence library.
endfunction
You should see that 1600 packets were processed. The reason that you are
seeing 10 times more transaction than you did before is because the sequence
library executes 10 of its registered child sequences by default. (10 sequences
X 16 ports X 10 items each) This can be changed.
To configure the sequence library to execute n number of sequences and to set the
execution type, you will use the uvm_sequence_library_cfg class.
Answers / Solutions
t e s t _ c o l l e c t i o n . sv Solution:
package packet_seq__lib_pkg;
import uvrnjpkg::* ;
constraint valid {
payload.size inside { [1:10] };
endpackage
p a c k e t _ s e q u e n c e . s v Solution;
import paDke:t^seq_„lib_pkg: :* ; ,
class packet_sequence extends uvm_sequence # (packet);
int itern__count ■= 10;
int port_id = -1
bit [15:0] da__enable = f1
int
vuvm__ob ject___utils__begin (packet_sequence)
■uvm__f ield___int (item_count, UVM_ALL_ON)
;uvmjield„int (port_id, ;UVM_ALL_ON)
suvm_field„int (da_enab 1e, :U¥M_ALL___ON)
suvm_f ield„_.queue__int (valid„da, UVM__ALL^.ON)
Nuvm__ob jeet__utils_end
function void pre__randomize () ;
:uvm_conf ig„db# (int) ::get (m_sequencer, nitem__count",■.'ifcein^QuntO};
uvm_conf ig__db# (int)::get (m_sequencer , "", nport___id", port_id) ;
uvrr^Gonf ig__db# (bit [15 :0]) ::get (irr_sequencer, ""r "da__enable",
da__enable) ;
if (! (port__id inside {-1, [0:15]})) begin
suvm_fatal ("CFGERR" , $sformatf ("Illegal port__id value of %0d",
port__.id) );
end
valid__da .delete () ;
for (int i= 0 ; i<16; i++)
if (da___enable [i ])
valid__da .push_back (i);
endfunction
function new(string name = "packet_sequence") ;
super.n e w (name);
'uvm_info ("TRACE" , $sf ormatf ("%m" ) , UVM_HIGH) ;
endfunction
virtual task body();
uvm_sequence_base parent;
'uvm_info ("TRACE" f $sf ormatf ("%m" ) , UVM„HIGH);
uvm__conf ig_db# (int) ::get (m_sequencer, »* ^ "itern_count", item__count)
parent = get _parent_sequence();
if (parent != null) begin
starting_phase = parent.starting__phase;
end
if (starting_phase i= null) begin
uvm_obj ection objection = starting_phase .get_objection () ;
objection.set_drain_time(this, lus);
starting__phase .raise_ob jection (this) ;
end
repeat(item_count) begin
'uvm__do_with (req, {if (port_id -1) sa inside {[0:15]}; else sa
port__id; da inside valid_da; });
end
router_env.sv Solution:
uvm_component_utils (router_env)
endclass
Lab Duration
60 minutes
Modifications
Environment class
Agent Agent
Host
sequencer
sequence Register
n
Host
Driver
model
Figure 1.
At address 0x0000, two read-only fields exist: chip id (CHIP_ID) and revsion id
(REV_ID). The static values are as shown in the following table.
| HOST_ID Register
| Field CHIP_ID REVJD
1 Bits 15-8 7-0
Mode ro ro
Reset Qx5A 0x03
At address 0x0100, there is a port locking field (LOCK). If a bit has the value of 1,
the corresponding port of the DUT will be disabled. To enable a port, the LOCK bit
must be cleared with a write-one-to-clear. (writing a one to that bit location will
clear the bit). The default value is 16’hffff, meaning that all ports are disabled at
reset. The reading and writing of the field is word based.
PORT_LOCK Register
Field LOCK
Bits 15-0
Mode w1c
Reset Oxff
REG_ARRAY[256] Registers
Field HOST_REG
Bits 15-0
Mode rw
Reset 0x00
RAM (4K)
Bits 15-0
Mode rw
You should see that 160 packets were observed at the input, but there were no
observed output! This is the expected behavior. You need to configure the
DUT to unlock the ports.
The host data class is created for you in host_data.sv. It’s pretty simple. It
contains data and address field with two possible kinds of operation: read and write.
endclass
A host agent class is also created for you in host_agent.sv. If interested, you
can examine the file. However, aside from the DUT specific device drivers, it
contain the same things that you have already done in the previous labs. So, there is
not much to gain in going through it in detail.
PORT_LOCK Register
Address Map
Field LOCK
HO STJD 0x0000 15-0
Bits
PORTJLOCK 0x0100 Mode w1c
REG_ARRAY 0x1000-0x1 OFF Reset Oxff
RAM (4K)
Bits 15-0
Mode rw
Save and close the file when done
1. Convert the RAL file content into UVM register classes with ralgen:
> ralgen -uvm -t host_regmodel host.ralf
You should see a file called ral_host_regmodel.sv created by ralgen.
If interested, take a look at the content. Otherwise, continue on to the next
task.
In order for the UVM Register content to be processed correctly by the host driver,
you must implement a UVM register to host bus and host bus to UVM register
translator.
3. In the build phase, check to see if regmodel is null. If yes, do the following:
• Add a string called hdl_path
• Use uvm_conf ig_db to retrieve hdl_path . If hdl^path is not
configured, issue a warning message.
• Contruct the regmodel object
• Call the regmodel’s build () method to build the RAL representation
• Call the regmodel’s lock__model () to lock the RAL structure and
create the address map
• Set hdl root path using regmodel’s set_hdl_path_root () method.
When done, the modified build_phase () should contain the following:
s t r in g h d ljp a t h ;
re g m o d e l « r a l„ b lo c k _ h o s t „ r e g m o d e l: :t y p e _ id : : c r e a t e ( " r e g m o d e l" , t h is ) ;
r e g m o d e l. b u i l d ( ) ;
r e g m o d e l . l o c k j n c t o d e l () ;
r e g m o d e l. s e t h d l p a th r o o t ( h d l_ p a t h ) ;
!!|i|i|(j!;!!!!!!!!!!!!!!!j;!!!!l!!!!!l
endfunction
llillillllll^^
The last piece of the RAL puzzle is to execute the RAL sequence. You should do
this in a test.
Answers / Solutions
test__collection.sv Solutions
endclass
host___data. s v Solution:
host__agent:.sv Solutions
endfunction
virtual task pre_reset_phase(uvm_phase phase);
sigs.wr_n = ’x;
sigs.address = rx ;
sigs.data = ’x;
endtask
virtual task reset_phase(uvm_phase phase);
h o s t „ s e q u e n c e . sv Solution:
host.ralf Solution:
register HOST__ID {
field REV_ID {
bits 8;
access ro;
reset ’h03;
; ) .
field CHIP_ID: { ;
bits 8;
access ro;
1 reset ’h5A;
}
}
register PORT__LOCK {
field LOCK {
bits 16;
access wlc;
reset ’hffff;
register REG_ARRAY {
field USER__REG {
bits 16;
access rw;
reset ’hO}
i
memory RAM {
size 4k;
bits 16;
access rw;
block host_regmodei {
bytes 2;
register HOSTJD (host__id) @ 1hOOOO
register PORT_LOCK (lock) 0 fhOlOO
register RE G__ARRAY [256] (host_reg [%d] ) @ fhl000 # array must specify index
memory RAM (ram) 0*h4OOO
endfunction