Sei sulla pagina 1di 20

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

System Verilog + OVM:


Mitigating Verification Challenges & Maximizing Reusability

Authors
Parag Goel [pgoel@amcc.com]
Pushkar Naik [pnaik@amcc.com]

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Abstract
Verification has been becoming a nightmare for engineers with the increasing requirements and
complexity of the design. Mitigating the complexity of a verification environment with the
increasing complexity of design verification can be re-defined as a CHALLENGE. System Verilog
along with its library of classes OVM, provides a platform to face this CHALLENGE.
This paper explains how, in our endeavor to accomplish an ideal verification platform for our
designs using System Verilog and a standard methodology(OVM) plus some in-house ideas over it,
helped us to make a more practical and easy to use verification environment. The challenges
spanned right from configuring the components, injecting the transactions to create various test
scenarios, phasing of the test cases till the end of report generation etc. This paper also explains
how SV & OVM has simplified a whole lot in controlling the messaging policy, sequences &
sequencers layering, OOPs data patterning to fit certain environment architecture requirements,
barrier mechanism to overcome OVM phasing limitations and ready-made harness system for the
sub-system integration, making things simpler & organized.
It also explains how the addition of a thin layer between the OVM Methodology classes and our
projects base classes helped us in shielding our projects from any changes in upcoming OVM
releases as well as served to provide a place holder for any additional functionality in our base
classes, without even touching the OVM source code as such. Towards the end, some points to
ponder have been summarized based on our experience with OVM and some enhancements in
Questasim / OVM are suggested.

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Table of Contents
Contents
1

Introduction -------------------------------------------------------------------------------------------------------------------------------- 4

OOPs Design Patterns (Singleton Instantiating One Object) --------------------------------------------------------- 4

Use of Parameterized Interface(s) in a Package ------------------------------------------------------------------------------ 7

Harness- a Complete Sub-system definition ----------------------------------------------------------------------------------- 8

Sequencer Layering -------------------------------------------------------------------------------------------------------------------- 13

Single Class / Multiple Analysis ports --------------------------------------------------------------------------------------------- 15

SV world to C world - Host Communication ---------------------------------------------------------------------------------- 18

Code References
Code 1 Example for Singleton Statistics collector ........................................................................................ 5
Code 2 Example for Singleton memory implementation ............................................................................... 6
Code 3 Example for Singleton memory usage ............................................................................................. 7
Code 4 DUT definition ................................................................................................................................. 10
Code 5 SVTB Interfaces definition .............................................................................................................. 10
Code 6 Virtual Interface packages .............................................................................................................. 10
Code 7 Connection module - AXI ............................................................................................................... 11
Code 8 Connection module - USB .............................................................................................................. 12
Code 9 Testbench Top................................................................................................................................ 12
Code 10 Monitors to be connected to score-board ..................................................................................... 16
Code 11 Agent code showing monitor & scoreboard connection ............................................................... 16
Code 12 Score-board showing implementation .......................................................................................... 17

List of Figures
Figure 1 Singleton pattern Statistics Collector ........................................................................................... 5
Figure 2 Singleton Pattern Memory Modelling & Sharing .......................................................................... 6
Figure 3 Parameterized Interface(s) in a package ........................................................................................ 8
Figure 4 Verification Setup Requirement ...................................................................................................... 9
Figure 5 Typical Setup Todays Scenario .................................................................................................. 9
Figure 6 Harness The Solution ................................................................................................................ 10
Figure 7 Completely integrated testbench Harness Approach ................................................................ 11
Figure 8 Sequence layering OVM recommended way ............................................................................ 13
Figure 9 Sequence Layering Using Sequencer layering ......................................................................... 14
Figure 10 Analysis FIFO connection model monitor & score-board ........................................................ 15
Figure 11 Host Communication module-level setup ................................................................................ 19
Figure 12 Host communication module/SoC setup ................................................................................. 20

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

1 Introduction
Seventy percent of project time is consumed in verification and still there are Bug(s) in the design
that are revealed after tape-out or at the customer end, that raises question(s) on the ability & the
sincerity of the verification engineer and overall credibility of the organization as such. But the real
question that needs to be raised is Do we have enough technology available to create all possible
stimuli to the DUT and gauge the amount of verification performed so far, quantitatively, in order to
confidently say that the DUT has been satisfactorily verified? Is the verification environment
available to the tester, providing him/her, enough flexibility to exercise the required test scenarios
without modifying the golden test bench?
The Methodology we developed at AMCC tried to answer several such above questions utilizing the
OVM/SV combination and some in-house ideas as mentioned before.
This paper is broadly divided into the following sub-sections:
1. System Verilog concepts making environment simpler
a. Usage of Design patterns
b. Usage of parameterized interface(s) in package(s)
c. Concept of harness for sub-system port mapping
2. Advanced OVM Usage
a. Sequence / Sequencer layering
b. Single Class / Multiple Analysis Ports Usage
c. SV to C world host communication
3. Work done to overcome OVM limitations
a. Messaging control in OVCs
b. OVM barrier enhanced phasing mechanism
4. Miscellaneous topics
a. Sequence initiation methods comparison in OVM
b. Some points to ponder
c. Questasim / OVM Enhancements moving forward

2 OOPs Design Patterns (Singleton Instantiating One Object)


As per the definition from the book Design Patterns: Elements of Reusable Object-Oriented Software
the Singleton design pattern must: Ensure a class only has one instance, and provide a global point
of access to it. Usage of this pattern lets you take away control over the object instantiation process
from the new operator. This kind of pattern can be used over and above the classes available in the
OVM library in cases where one might need to refer one and the same instance of the class across
the components and across the hierarchy. To achieve this objective one can use the concept of the
Singleton pattern available in OOPs.
The two very common applications that can be thought for a VC based on System Verilog are as
described below.
1. Statistics Collector class (Refer to Figure 1) There are situations where you require to display
a summary of information at the end of the simulation which actually helps in deducing the
inferences for a given test case. This may broadly consists of ,
1. The Statistical collection - a summary of injected/collected transactions across the
score-board.
2. Error counters transaction related errors.

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

3. Count of Compares/Mis-Compares of transaction elements etc. can be added to the


scoreboard by the user.

Statistics Collector

Driver

Scoreboard

Bus Monitor

VIP components populating the properties of a single class.


Figure 1 Singleton pattern Statistics Collector

This block will necessarily be a singleton class that will contain all the properties related to the
above mentioned points. These properties shall be populated & updated from several components
sitting in the VIP environment, and at the end of simulation it will display the complete information
collected in a simple & easy to understand manner. Needless to mention, how OVM also aids in such
scenario, by providing certain in-built methods for printing messages uniformly in the report phase
etc.
Lets understand how it works from the code perspective [Refer to Code 1]:
Code 1 Example for Singleton Statistics collector
class report_handler extends ovm_object;
//Properties to collect statistics
int Total_Transfers;
int Read_Transfers ;
int Write_Transfers;
//Register to get built-in methods ready-made
`ovm_object_utils_begin(report_handler)
`ovm_field_int(Total_Transfers , OVM_ALL_ON)
`ovm_field_int(Read_Transfers , OVM_ALL_ON)
`ovm_field_int(Write_Transfers , OVM_ALL_ON)
`ovm_object_utils_end
// object that is created only once
static *_report_handler single[*];
function new();
endfunction
// method to get object
static function report_handler get_instance(int id);
//call the constructor for the first time, if the object has been
//created already return reference to that object else create new one
if(!single.exists(id)) begin //{
// constructor that is called only once
single[id] = new;
end //}
// return the reference to already created object
return single[id];
endfunction
endclass

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

2. Lets take a look at the next application, where one requires modeling a memory with
parameterized address and data width which can be used across classes/models, still referring
to a single memory array. As shown in the figure below (Refer to Figure 2), a memory is being
accessed for reads/writes by the DUT through a Protocol BFM as well as it can be accessed via. a
backdoor path accessing the read/write functions written in the memory. [Code : 2,3]
Backdoor Path

Memory
model

Protocol
BFM
Test sequence
includes
initialization +
traffic

DUT

Figure 2 Singleton Pattern Memory Modelling & Sharing


Code 2 Example for Singleton memory implementation
class slave_memory #(ADDR_WIDTH = 36,DATA_WIDTH = 128);
//declaration of assoc array for memory
bit [DATA_WIDTH-1:0] memory[*];
static slave_memory#(ADDR_WIDTH,DATA_WIDTH) single[*];
. . . . . . . . .
// method to get singleton object
static function slave_memory #(ADDR_WIDTH,DATA_WIDTH) get_instance(int
id);
if(!single.exists(id)) begin //{
// constructor that is called only once
single[id] = new;
end //}
// return the reference to already created object
return single[id];
endfunction
//This task will write the data to a memory using backdoor access.
task mem_write(bit[ADDR_WIDTH-1:0] address, bit[DATA_WIDTH-1:0] data,
bit[DATA_WIDTH-1:0] mask = 'hf);
bit[DATA_WIDTH-1:0] read_data;
if(memory.exists(address)) begin //{
mem_read(address, read_data);
end //}
memory[address] = ((data & mask) | read_data);
endtask
//This task will read the data from a memory using backdoor access
task mem_read(bit[ADDR_WIDTH-1:0] address, output bit[DATA_WIDTH-1:0]
data);
data = memory[address];
endtask
endclass : slave_memory

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Now, lets see what goes into the user side. The steps are as follows:
Code 3 Example for Singleton memory usage
//declaring the handle of memory with parameters
axi_slave_memory #(ADDR_WIDTH,WRITE_DATA_BUS_WIDTH)mem;
//getting singleton handle to memory
mem = mem.get_instance(id);
//memory backdoor read function
mem.mem_read(address, data);
//memory backdoor write function
mem.mem_write(address, data, mask);

To summarize, using this pattern, one can refer to the same instance anywhere within ones
environment. The examples discussed were, when one wants to collect the statistics from all the
VIP components and display the same as the final report at the end of simulation, and when a
single instance of memory is used across environment that is accessed for read/writes by several
VIP components.
Singleton applies to has_a kind of relationship. Now lets see when the class being treated as
Singleton has child classes leading to is_a kind of relationship as well. To achieve the same we can
make the constructor protected, so that various subclasses get to inherit the same constructor. But
as a general thumb rule, Singleton and subclassing should not be mixed to keep things simpler.
Disadvantages:
1. It creates an object in a given namespace, and the whole idea of namespace defies the OOPs
objective to remove the clutter of namespaces
2. Having only one such global object at a particular time doesnt mean another one cant be
created inadvertently in another namespace, giving you some very hard to debug issues.

3 Use of Parameterized Interface(s) in a Package


Classes are dynamic in nature while interfaces are static in nature and hence cannot be directly
instantiated in a class. So, typically, a real interface instance is created in the top module (or
program block) and virtual interface instances are created in various classes where there is a need
to access the interface. But we need to connect the various virtual interfaces to the equivalent real
interface somewhere.
One of the not so elegant ways is to hierarchically pass a virtual interface instance down the layers.
OVM suggests a cleaner solution to this, for OVC development.
Define a virtual interface package and instantiate a virtual interface for each of the real interface(s)
instantiated in the top module or program block[Refer to Figure 5]. Then in the top module or
program block, import the virtual interface package and connect the packages virtual interface(s)
to the corresponding real interface(s) there. In the various classes where interface access is
required, define local instances of the required virtual interface(s). Then import the virtual
interface package in each of these classes and connect the local virtual interface instance(s) to the
corresponding ones in the imported package.

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

DUT

TESTBENCH

Connection
package (pkg)
Virtual
Interface (vif)

Global defines
package
`defines
enums
parameters

Driver
Connection Module

vif

Real Interface (rif)


Monitor
pkg::vif = rif

vif

Figure 3 Parameterized Interface(s) in a package

But what if these interfaces are parameterized, how do we plan to pass parameters across
packages, SV doesnt provide a provision for the same. One way to tackle this is to move the
interface to config class and refer from there instead of package. But still packages provide a better
global visibility. So, the other solution can be a parameterized class inside the package that contains
the parameterized interface instance.
Even simpler solution would be to make a package of global defines containing `defines, enums and
parameters, and import this package in various other component packages where these are
required to refer.

4 Harness- a Complete Sub-system definition


A typical verification setup is shown in Figure 4, wherein, various Test Bench Subsystem definitions
should be able to take care of the respective interfaces defined in the DUT. An SV interface and
associated Class hierarchy together define a Test bench Subsystem. OVM has a well-defined class
hierarchy definition to take care of required functions, but the associated interface and its port
mapping is still done in the top module (or program block) (Refer to Figure 5). This can make the
top messy. Also if a user is integrating this functional entity into a test bench, he/she needs to know
the interface of this functional entity in details in order to integrate. This is not what is desired, as
the integrator is only interested in integrating the functional entity into rest of test bench, the
details of that entitys interface are really to be known by the module owner. This can be avoided if
the module owner defines a connection module for that class hierarchy in which all port mappings
to the corresponding DUT interface are already taken care of, while this connection module gets
simply instantiated in the top by the integrator without knowing the intricacies of that interface.
This connection module along-with the related class hierarchy defines a self-sufficient functional
entity and is termed a Harness (Refer to Figure 6).

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

AXI TB
Subsystem
AXI

DUT

TEST
BENCH

USB

USB TB
Subsystem
DUT PORTS

Figure 4 Verification Setup Requirement

So, as shown in the above requirement setup (Refer to Figure 4), the DUT has two interfaces AXI
and USB. Thus we need two TB subsystems that can drive and receive from these two interfaces.
The two module owners define the OVM based class hierarchies for these two subsystems as shown
below.
TESTBENCH
USB
Agent

module top();

//USB Port Map


..................
..................
..................

USB
Sequenc
er

USB
Driver
USB
Monitor

USB/AXI Class Hierarchies


//AXI Port map
..................
..................
..................
..................

AXI
Agent

AXI
Sequenc
er

AXI
Driver

endmodule

S
V
I
N
T
E
R
F
A
C
E
S

A
X
I

DUT
U
S
B
B

AXI
Monitor

Figure 5 Typical Setup Todays Scenario

Now, along-with the class hierarchies, its this individual module owners responsibility to define
their connection modules as well that port map to the respective DUT interface [Refer to Figure 6].

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

USB Harness

USB
Connection
Module

USB
Agent

USB
Sequencer

USB
Driver
USB
Monitor

AXI Harness

AXI
Connection
Module

AXI
Agent

AXI
Sequencer

AXI
Driver
AXI
Monitor

Figure 6 Harness The Solution

Now, once the above two subsystems are ready, a third person integrating these two subsystems
merely instantiates the respective agents in the environments and instantiates the connection
modules in the top without understanding the interfaces of these two subsystems in details as
shown below. [Refer to Figure 7][Code: 4, 5, 6, 7, 8, 9]

Code 4 DUT definition


module Dut ( clk,

reset,

//USB Intf
txready,
datain,
. . . .
dataout,
txvalid,

input
input

//AXI Intf
Reset,
wrAddr,
. . . .
rdData);
clk;
reset;

//USB
input
txready;
input [15:0]datain;
output [15:0]dataout;
output
txvalid;
//AXI
input
Reset;
input [31:0] wrAddr;
output[63:0] rdData;
endmodule

Code 5 SVTB Interfaces definition


interface axi_intf(input clk);
logic
Reset;
logic [31:0] wrAddr;
logic [63:0] rdData;
endinterface
interface usb_intf (input
clk);
logic
reset;
logic
txready;
logic [15:0] datain;
logic [15:0] dataout;
logic
txvalid;
endinterface
Code 6 Virtual Interface packages
package axi_vif_pkg;
virtual axi_intf axi_vif;
endpackage
package usb_vif_pkg;
virtual usb_intf usb_vif;
endpackage
10

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Top
Module

Test
cases

Test
Environment
AXI
Connection
Module

USB
Connection
Module
USB
Agent

USB
Sequencer

USB
Driver
USB
Monitor

AXI
Agent

AXI
Sequencer

AXI
Driver
AXI
Monitor

Figure 7 Completely integrated testbench Harness Approach


Code 7 Connection module - AXI
import axi_vif_pkg::*;
module axi_connect(input clk, reset);
//make real interface instance
axi_intf
axi_rif(clk);
//port map corresponding dut signals
always @ (posedge clk) begin
axi_rif.Reset = reset;
//DUT Inputs
top.dut_inst.reset
= axi_rif.Reset;
top.dut_inst.wrAddr = axi_rif. wrAddr;
//DUT Outputs
axi_rif.rdData
= top.dut_inst.rdData;
end
//Map the floating Virtual Interface instance in the
package to the real interface instance
initial begin
axi_vif_pkg::axi_vif = axi_rif;
end
endmodule
11

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Code 8 Connection module - USB


import usb_vif_pkg::*;
module usb_connect(input clk, reset);
//make real interface instance
usb_intf
usb_rif(clk);
//port map corresponding dut signals
always @ (posedge clk) begin
usb_rif.reset = reset;
//DUT Inputs
top.dut_inst.reset
= usb_rif.reset;
top.dut_inst.txready
= usb_rif.txready;
top.dut_inst.datain
= usb_rif.datain;
//DUT Outputs
usb_rif.dataout
= top.dut_inst.dataout;
usb_rif.txvalid
= top.dut_inst.txvalid;
end
//Map the floating Virtual Interface instance in
the package to the real interface instance
initial begin
usb_vif_pkg::usb_vif = usb_rif;
end
endmodule

Code 9 Testbench Top


module top();
bit clk = 0;
bit reset = 0;
initial begin
forever clk = #TP ~clk;
end
initial begin
@ (posedge clk);
reset = 1b1;
repeat (5) @ (posedge clk);
reset = 1b0;
end
//instantiate axi connection module
axi_connect axi_connect_inst(clk, reset);
//instantiate usb connection module
usb_connect usb_connect_inst(clk, reset);
//instantiate dut
Dut dut_inst;
endmodule

12

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

5 Sequencer Layering
OVM allows layering of the Sequences, hierarchically, to achieve any complex functionality. But the
Sequencer, on which these sequences or hierarchy of sequences is started, expects a given type of
ovm_sequence_item derivative, as specified in the Sequencer definition.
There can be a requirement in a Verification Environment that few Sequences work on one type of
ovm_sequence_item derivative and the output of these Sequences is required to be fed to another
type of ovm_sequence_item derivative. Thus a translation is required in between, to convert one
type of ovm_sequence_item derivative to another, before the Sequencer and Driver configured to
accept second ovm_sequence_item derivative, can consume it.
OVM suggested way to handle this would be to arrange these two processing logic in a hierarchical
Sequence fashion, as shown below (Refer to Figure 8). But the problem here is that the Translation
Sequence not only has to translate between the Trans1 and Trans2, but also has to implement
complex arbitration logic to arbitrate between Sequences 1, 2 & 3.

Transaction
(Trans2)

Transaction
(Trans1)

Seq4

Driver

Translation Sequence

Sequencer

Seq1

Seq2

Seq3
Seq6

Sequencer
arbitration
Indicates a conversion sequence to convert the Trans1 from Seq1,2,3 to
Trans2 as required by Sequencer. Arbitration logic implemented in
sequence by user

Figure 8 Sequence layering OVM recommended way

Here we suggest an OVM reusable approach, where Sequencers Arbitration Logic can be reused in
achieving the above objective [Refer to Figure 9].

13

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Transaction
(Trans2)

Transaction
(Trans1)

Seq4

Seq1

Translation
Sequence

Sequencer2

Seq2

Sequencer1

Driver
Seq3

Seq6
user_req_port

seq_item_port

user_rsp_export

rsp_port
Sequencer2
arbitration

Sequencer2
arbitration

Indicates a conversion sequence to convert the Trans1 from


Sequencer1 to Trans2 as required by Sequencer2. Uses
m_sequencer.user_req_port.get() to get the transaction from the
Sequencer1
Figure 9 Sequence Layering Using Sequencer layering

Sequences 1, 2 & 3 as well as Sequencer1 work on ovm_sequence_item derivative type Trans1.


Sequencer1s internal arbitration logic (provided by OVM) is used to arbitrate between these
Sequences. Now, the output of Sequencer1 needs to be fed to a Translation Sequence as shown. This
Translation Sequence is started on Sequencer2 along with Sequences 4 & 5 and all these work on
ovm_sequence_item derivative type Trans2. Thus the incoming transaction Trans1 need to be
converted into Trans2. Once again, Sequencer2s internal arbitration logic (provided by OVM) is
used to arbitrate between Sequences 4,5 & Translation Sequence
The point to be noted here is that, we need a path to send the Trans 1 out of Sequencer1 and be
received by Translation Sequence. The problem is, Sequences being derived from ovm_sequence and
ultimately ovm_object, does not support TLM channel declarations. One way to achieve this would
be to define the required TLM channels (user_req_port & user_rsp_export) in Sequencer2 with which
Translation Sequence is associated already. As the Translation Sequence has a readymade
m_sequencer handle from OVM to access the associated Sequencer2, Translation Sequence simply
has to say
m_sequencer.user_req_port.get() to get the transactions from Sequencer1.
One care that needs to be taken for the response path to work in the above scenario is that the
respective seq_id, transaction_id and m_sequencer/p_sequencer fields of Trans1 & Trans2 need to be
separately maintained without intermixing them, so that during the translation, only user fields get
translated. For this, one way is to maintain extra set of seq_id, transaction_id and
14

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

m_sequencer/p_sequencer fields in Trans2 for Trans1 so that the response received can be properly
co-related to the correct sequence and transaction numbers.
Another way would be to maintain a req queue in the Trans2 so that when the response is received,
it can be matched wih the reqs in the local queue and then co-related to the correct sequence and
transaction numbers.

6 Single Class / Multiple Analysis ports


In a typical Scoreboard, we are required to connect two or more monitors. In OVM, this is done
using analysis imports. Now, the Scoreboard will require to provide the write() function
implementation for every analysis import instantiated. But a class cannot have two or more
functions with same signature.
This can be resolved by using an analysis FIFO after the analysis import so that the write() function
implementation is provided by the analysis FIFO instance as shown below. (Refer to Figure 10)
(Code 10, 11, 12)
fifo.analysis_export
ovm_analysis_export

SCOREBOARD
Write
Monitor

write()
tlm_analysis_fifo

Read
Monitor

write()

fifo.get()
Scoreboarding
Logic
fifo.get()

ovm_analysis_port

Figure 10 Analysis FIFO connection model monitor & score-board

But, at times there is a requirement to provide a write() function implementation by the user,
customized to take care of some project requirements. Thus we need a solution to have multiple
write() functions defined in the same Scoreboard class.
OVM provides a macro to do this, known as `ovm_analysis_imp_decl(<_userString>). User passes a
string name to the macro that he/she wishes to have appended. This basically provides:
1. An import class with a ovm_analysis_imp<_userString> as its signature
2. It also provides a signature to a write function with write<_userString> () as its name.
User simply instantiates above import and connects to the respective monitor. Also, user codes the
above function that gets called whenever the connected monitor writes to its analysis port. This
function is coded by user as per his/her project requirements. Note that though monitor simply
calls its port.write() function, in turn the connected subscribers import.write<_userString>()
function gets called automatically.

15

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

Code 10 Monitors to be connected to score-board


class MyReadMonitor extends
ovm_monitor;
ovm_analysis_port #(MyTrans1) ap;
task run();
MyTrans1 Tr;
//Monitor logic
------ap.write(Tr);
endtask
endclass: MyReadMonitor

class MyWriteMonitor extends


ovm_monitor;
ovm_analysis_port #(MyTrans1) ap;
task run();
MyTrans1 Tr;
//Monitor logic
------ap.write(Tr);
endtask
endclass: MyWriteMonitor

class MyAgent extends ovm_agent;


MyWriteMonitor wrMon;
MyReadMonitor rdMon;
MyScoreboard
scbd;
function void connect();
wrMon.ap.connect(scbd.userWrData_imp);
rdMon.ap.connect(scbd.userRdData_imp);
endfunction
endclass: MyAgent
Code 11 Agent code showing monitor & scoreboard connection

16

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

`ovm_analysis_imp_decl(_UserWrData)
`ovm_analysis_imp_decl(_UserRdData)
class MyScoreboard extends ovm_scoreboard;
ovm_analysis_imp_UserWrData
ovm_analysis_imp_UserRdData

#(MyTrans1, MyScoreboard) userWrData_imp;


#(MyTrans1, MyScoreboard) userRdData_imp;

MyTrans2 WrTransQue[$];
MyTrans2 RdTransQue[$];
function void write_UserWrData (MyTrans1 uWrTrans);
MyTrans2 WrTrans2;
//Convert uWrTrans to WrTrans2
----------WrTransQue.push_back(WrTrans2);
endfunction : write_UserWrData
function void write_UserRdData (MyTrans1 uRdTrans);
MyTrans2 RdTrans2;
//Convert uRdTrans to RdTrans2
----------RdTransQue.push_back(RdTrans2);
endfunction : write_UserRdData
task void run ();
MyTrans2 WrTrans2;
MyTrans2 RdTrans2;
fork
begin
forever begin
if(WrTransQue.size() > 0) begin
WrTrans2 = WrTransQue.pop_front();
//Process Write Trans
----------end
end
end
begin
forever begin
if(RdTransQue.size() > 0) begin
RdTrans2 = RdTransQue.pop_front();
//Process Read Trans
----------end
end
end
endtask : run
endclass: MyScoreboard

Code 12 Score-board showing implementation

17

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

7 SV world to C world - Host Communication


In case of SOC projects, often there is a need to communicate across from SV World to C World and
back, to accomplish a particular test scenario.
Now, in case of Module Level Verification Environments, where embedded host processor is
typically absent, SV to C communication and back can simply be SV DPI Calls. But when embedded
host processor is in place at Chip Level Verification Environment, shared memory is one way to
achieve the communication between the SV and C Worlds.
Typically, we randomize the control parameters in the SV World as per the constraints specified in
the test-case/sequence/transfer class, but the programming of DUT registers for DUT initialization
has to be performed by the embedded processor only, as per the real world SOC requirement.
The idea here is to reuse the C code written at Module Level Verification into the Chip Level
Verification.
Thus there is a need to send across the randomized set of data from SV World to the C World. Once
the C program executes on the embedded processor (or through DPI call at Module Level) and
utilizes the data that came from SV World, it now has some programming sequence data ready to
program the DUT registers. But to actually perform this programming, this data has to be brought
back from the C World to the SV World where some SV module can drive the DUT Register
Programming interface using the data received from the C World.
To accomplish the above communication, reusable verification blocks can be defined to be used
across various project modules. One of the proposed definitions of these blocks is that we define a
Host Adapter block and a Host Requester block. [Refer to figure 11] There will be a Singleton
instance of Host Adapter in a project at any given time. Every SV Module that wishes to send data to
the C World first extends the host requester block for customizing the data to be sent across as per
that modules requirement and then connects to the singleton Host Adapter instance using a host
requester channel (TLM Channel).
A generic data structure can be defined that is interpreted by any Host Requester and Host Adapter.
This data structure can contain following fields: block_id, task_id, data[], control[]. The contents of
data [] and control[] can be customized by the individual modules as per their requirement.
Every Module Level Verification Environment provides a C file containing the tasks required to
execute to achieve that Modules DUT Register Programming. Also, in that file, it provides a host
task table consisting of entries of task string name and corresponding function pointer.
When a Host Requester sends a request in the form of a structure defined above, to the Host
Adapter, it gets stored in the Adapters in-built Queue (FIFO). The various barriers defined in
Adapter like the init_barrier, run_barrier, check_barrier etc pops out the request from Queue oneby-one at the appropriate barrier timing and calls the Host Adapter Generic C function process
requests() for handling the requests.
In case of Module Level Verification Environment, as discussed before, this will be purely a DPI-C
call.
In case of Chip Level Verification Environment, this will be through a shared memory so that the
Adapter Generic C function(s) running on embedded host processor can pick up the request
through shared memory and execute it.[ Refer to figure 12]
This Generic C function looks at the block_id from the request and figures out which host task table
to look into. Then it uses the task_id in the form of a string from the request to lookup for this
function in this table. Once it finds it, it simply calls the mapping function pointer in the found entry

18

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

with the data [] and control[] as arguments else flags a fatal error. This User C function called by
the Generic C function may result in a call, back to SV World.
Again in case of Module Level Verification Environment, this will simply be a DPI SV call to the SV
Adapter exported function(s). In case of Chip Level Verification Environment, this will be through a
shared memory so that some Adapter SV process waiting for the C side to setup data in shared
memory gets kicked off seeing the data there and then executes the associated tasks in the DUT
Register Programming module in the SV domain to get the appropriate DUT Registers programmed.
In a similar fashion, interrupts handling can be taken care of in the Module Level Verification
Environments where actual host processor is missing, so the ISR routine gets called through the DPI
C calls. At Chip Level, there will be actual processor to handle the interrupts anyways.
Block Test bench
Host Environment

Block Environment

Host Master
Agent

Host Sequence
Block C
Routines

DPI

Host
Requestor
Channel
Host Adaptor

Host Requester

Figure 11 Host Communication module-level setup

19

System Verilog + OVM: Mitigating Verification Challenges & Maximizing Reusability

PCIe

SATA

USB

PCIe Host
Requestor

SATA
Host
Requestor

USB Host
Requestor

Host
Requestor
Channel

Singleton
Host Adaptor

DUT
Programming
Interface/Module

DPI/Shared
Memory
communication

PCIe user C
functions &
func table

Host
Adaptor
Generic
C code

SATA user C
functions &
func table

USB user C
functions &
func table

DUT

Figure 12 Host communication module/SoC setup

To be continued..........

20

Potrebbero piacerti anche