[go: up one dir, main page]

0% found this document useful (0 votes)
102 views6 pages

Beyond UVM: Creating Truly Reusable Protocol Layering: Abstract-Protocols That Are Transported by Other Lower-Level

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 6

Beyond UVM:

Creating Truly Reusable Protocol Layering


Janick Bergeron, Fabian Delguste, Steve Knoeck, Steve McMaster, Aron Pratt, Amit Sharma
Synopsys, Inc
Mountain View, CA

Abstract—Protocols that are transported by other lower-level level protocols can be transparently tunneled through a higher-
protocols are modeled using a layering structure that mirrors the layer protocol. For example, an IP stream (itself carrying a
layering of the protocol. In UVM, it is recommended that the variety of higher-layer protocols) can be encrypted then
layering be performed using a layering sequence. However, the wrapped into TCP packets and tunneled through a TCP
many examples of protocol layering sequences in the UVM transport layer to be decrypted and processed at the other end
literature show that it requires implementation techniques that as if they had been natively transported.
are not scalable and often not reusable. This paper details a UVM
protocol layering approach that uses a layering driver as an Transfers Transfers
implementation that is both scalable and reusable.
Host Endpoint
Keywords—UVM; protocol; layering; delayering; reusable;
Transactions Transactions
scalable; sequence
Master Device
I. INTRODUCTION
Packets Packets
Communication protocols are specified and implemented
according to layers. These layers are often labeled using the Serializer Deserializer
popular OSI modelError! Reference source not found.. A
higher-layer protocol is transparently transported on a lower- Serial 1’s & 0’s Serial 1’s & 0’s
layer protocol. That lower-layer protocol may in-turn be
transparently transported on an even lower-layer protocol. For Figure 2. USB Protocol Layers
example, as illustrated in Figure 1. , TCP protocol packets can
first be segmented into IPv4 frames; the IPv4 frames can then When implementing protocol verification IP, it is important
be encapsulated into Ethernet frames then transmitted over a that the independence of the protocol layering structure be
XAUI interface onto a fiber optic medium. Another example maintained, The output of a higher-layer protocol VIP can thus
illustrated in Figure 2. , USB transfers are composed of USB be transported by different lower-layer protocol VIPs.
transactions which are composed of USB packets. Similarly, a single instance of a lower-layer protocol VIP must
TCP Packets TCP Packets
be able to transport multiple higher-layer protocols coming
from multiple instances of different higher-layer protocol VIPs.
Segmentation Reassembly Conversely, lower-layer protocol monitors must be able to feed
a variety of higher-layer protocol monitors.
IPv4 Frames IPv4 Frames
II. PROTOCOL LAYERING IN UVM
Encapsulation Decapsulation

Ethernet Frames Ethernet Frames A. UVM Stimulus Generation


As illustrated in Figure 3. UVM dictates that stimulus be
Media Access Signal Decode generated using sequences executing on a sequencer. While
executing, sequences create transactions using a random,
XAUI 8b10b XAUI 8b10b algorithmic or directed specification that are then executed by a
driver, usually by transmitting them over physical signals.
Figure 1. TCP/IP over Ethernet

Because the transport layer is transparent to the higher-


layers it carries, a higher-layer protocol may be transported on
a variety of lower-level protocols. For example, a TCP packet
may be transported over an IPv4, IPv6 or PPP protocol.
Conversely, a lower-layer protocol may transport different
higher-layer protocols, often at the same time. For example, an
Ethernet link may transport a mix of IPv4 frames, IPv6 frames
or UDP packets. To complicate matters even further, lower-
Figure 3. Architecture of UVM Stimulus Agent
Conversely, UVM dictates that a monitor observes the Because layering sequences have a function that is very
execution of transactions and reports them on an analysis port, similar to drivers, they are significantly different from usual
usually using the same transaction objects that are exchanged sequences in a several aspects.
between the sequencer and driver.
Firstly, layering sequences execute continuously throughout
This abstraction level works well if the protocol the run phase. Regular sequences are started on demand and
functionality under verification is at the same layer as the terminate once they have completed their stimulus
transactions that are executed by the driver. But if it is at a requirements by returning from their body() task. But just like
higher layer, it becomes cumbersome to create stimulus that is drivers never return from their run_phase() task, layering
relevant to the verification objectives at hand, and to interpret sequences must always be available to execute higher-layer
the low-level transaction stream into higher-level response. It transactions and thus cannot ever return.
thus requires more effort and increases the time required to
verify the design to the desired degree of confidence. Secondly, layering sequences must be started at the
beginning of the run phase so they can be ready to execute
higher-layer transactions as soon as possible. This is just like
B. Layering Sequences drivers implementing their functionality in their run_phase()
Transaction-based verification is about abstracting the low, task which is automatically started at the beginning of the run
signal-level operations into higher-level transactions. The same phase.
abstraction process can be recursively applied to lower-level
transaction: verification can be performed at a higher level of Thirdly, UVM recommends that layering sequences accept
abstraction by abstracting the low-level transactions into higher-layer transactions to be executed via a sequencer port.
higher-level ones. Whereas regular sequence take their input from local variables
defined before the execution of their body() task, layering
One possible approach would be to create a set of sequences take their input using the same mechanism as a
monolithic protocol VIPs, each using a different higher-level driver. As shown in Figure 4. , this allows a higher-level
protocol on the testbench side that can be connected to the sequencer to be connected to a layering sequencer in the same
same physical signals. But this would require one VIP for way it could be connected to a driver.
every combination of higher-level and low-level protocols.
Furthermore, it would be next-to-impossible to combine
different higher-level protocols onto the same lower-level
protocol.
That is why UVM recommends the use of protocol layering
sequences. Just like drivers execute transactions by wiggling
physical signals, a layering sequence will execute higher-layer
transactions by executing a set of lower-level transactions.
Similarly, a delayering monitor will observe lower-level
transactions on a lower-level analysis port and report higher-
layer transactions onto its analysis port.

Figure 5. Complex Protocol Stack

A layering sequence, even though it behaves like a driver,


remains a sequence. And because a sequencer can concurrently
execute multiple sequences, it is possible to execute multiple
layering sequences on the same sequencer, each layering
different protocol or additional streams of the same protocols
onto the same lower-layer protocol. And because a layering
sequence is fed by a higher-layer sequencer, that higher-layer
sequencer may also be executing a layering sequence,
executing even higher-layer transactions. As shown in Figure 5.
, this allows an arbitrary number of protocol layers to be
stacked and multiplexed in arbitrary (but compatible)
combinations.
Layering sequences can concurrently execute with regular
sequences to inject lower-level stimulus (such as errors or
Figure 4. Layered Sequencers and Monitors spurious traffic or protocol exception transactions) in a protocol
stack. Furthermore, the relative priority of the layering and
normal sequences can be adjusted to shape the resulting traffic. get_next_item(hli);
Although traffic shaping is a fascinating topic, it is outside the while (...) begin
scope of this paper. `uvm_create(lli)
// Slice and dice hli to form lli’s
lli.data[i] = ...;
III. PRIOR ART ...
Several examples of layering sequences have been `uvm_send(lli)
published[1][3]. However, each exhibit limitations that prevent end
them from being truly reusable and scalable. p_sequencer.hli_port.item_done();
end
endtask
A. Layering inside one Sequencer
Section 6.5.2.3.1 of the UVM User’s Guide[2] shows how a This second example is more reusable than the first one: it
higher-layer transaction is created, randomized then translated only needs to be started on the appropriate sequencer without
into lower-level sequence items that are then executed on the requiring any modifications. It is also more scalable as the
driver: higher-layer sequences are executed independently on the
higher-layer sequencer and the layering sequence takes care of
task body(); the layering. All existing higher-layer sequence can be reused,
`uvm_create(hli) without modifications on any layering sequence. In an
hli.randomize(); environment where N higher-layer protocols, each with S
send_high_layer(hli);
higher-layer sequences, need to be layered on M lower-layer
endtask: body
protocols, it requires N x M additional sequences.
task send_high_layer(hli_typ hli); The problem though lies in the location of the higher-layer
while (...) begin sequencer port: in a specialization of the lower-level sequencer.
`uvm_create(lli); This is approach hinders reusability and scalability in three
// Slice and dice hli to form lli’s ways:
lli.data[i] = ...;
... First, should the lower-layer sequencer not be of the
`uvm_send(lli) appropriate type, it will not be able to execute the layering
end sequence. In an environment where N higher-layer protocols
endtask : send_high_layer need to be layered on M lower-layer protocols, this approach
This layering sequence is reusable only by extending it to requires N x M additional sequencer types (to go with the N x
redefine its body() task and create different higher-layer M additional layering sequences). Adding a new higher-layer
transaction items to reuse the layering send_high_layer() task. protocol does not require any additional sequences. Adding a
Because SystemVerilog lacks multiple inheritance, it is new lower-layer protocol requires N additional layering
impossible to leverage existing higher-layer sequences and sequences. However, should the environment already have
combine them with the layering send_high_layer() task without specialized a lower-level sequencer to provide configuration
re-implementing them for each lower-layer sequence. In an information to the normal sequences it runs, the single-
environment where N higher-layer protocols, each with S inheritance nature of SystemVerilog will make this approach
higher-layer sequences, need to be layered on M lower-layer unusable.
protocols, it requires N x S x M additional sequences. Adding a Second, should it be necessary to layer more than one
new higher-layer protocol requires N x M additional sequences. protocol stream on the same lower-layer sequencer, there is
Adding a new lower-layer protocol requires N x S additional only one higher-layer sequencer port to connect to. It is not
sequences. This approach is clearly not scalable. possible to connect more than one sequencer to the same
sequencer port, thus it will be impossible to connect more than
B. Layered Sequencer one sequencer to the layering sequence.
Section 6.5.2.6 of the UVM User’s Guide[1] shows how a Third, should it be necessary to layer different protocols on
layering sequence can pull higher-layer items from a sequence the same lower-layer sequencer, it becomes necessary to
port on the parent sequencer accessed via p_sequencer, declare multiple sequencer ports of different higher-layer
translate them into lower-level sequence items and execute protocol types in the same lower-layer sequencer to enable
those. their respective layering sequence to refer to their respective
class hli_to_lli_sqr extends higher-layer port. In an environment where N higher-layer
uvm_sequencer#(lli_typ); protocols need to be layered on M lower-layer protocols, this
uvm_seq_item_pull_port#(hli_typ) hli_port; approach requires N different sequencer ports in N x M
endclass additional sequencer types. Adding a new higher-layer protocol
requires modifying M sequencer types. Adding a new lower-
class hli_to_lli_seq extends layer protocol requires one new sequencer with N sequencer
uvm_sequence#(lli_typ); ports and N new layering sequences.
task body();
forever begin Reusable? Yes. Scalable? Definitely not.
p_sequencer.hli_port.
C. Reference to Higher-Layer Sequencer As shown in Figure 4. , delayering monitors are connected
The layering example shown in [3] recommends putting a in a structure that mirrors the layering sequence structure.
reference to the high-layer sequencer in the layering sequence. Because an analysis port can be connected to multiple analysis
The layering sequence then directly accesses the exports, as many delayering monitors can be connected as there
implementation of the get_next_item() and item_done() are layering sequences running on the sequencer.
methods. All of the sequence layering examples in the existing literature
class hli_to_lli_seq extends use a straight forward unidirectional protocol layering. The
uvm_sequence#(lli); timing and content of the lower-level layer transactions are
task body(); solely determined by the timing and content of the higher-level
forever begin transactions. Unfortunately, the behavior of real-world
hl_sequencer.get_next_item(hli); protocols are often affected by the responses received from the
while (...) begin lower layer. For example, executing a USB transaction
`uvm_create(lli) involves the correct back-and-forth exchange of several USB
packets. Should a reply packet contain a negative response or
// Slice and dice hli to form lli’s go missing, the transfer must be aborted. Or should forward
lli.data[i] = ...; packets be send without waiting for the preceding response, the
...
rules of the protocol will have been broken. In other protocols,
`uvm_send(lli)
end
such as PCIe, a lower-layer transaction may not be sent unless
hl_sequencer.item_done(); the layering sequence possesses the necessary data flow credits.
end Therefore, the sequence layering mechanism must be able
endtask to handle duplex protocol, where the result and timing of the
This approach can be a lot more reusable and scalable than layering is a function, not only of the upper-layer sequencer,
the previous ones. Layering different protocols or multiple but of transactions observed by the lower-level monitor. Thus,
streams of the same protocol onto a lower-layer sequencer the layering sequence must be connected to the analysis port of
simply requires that the appropriate number of layering the lower-level agent as well, as shown in Figure 6. .
sequences be started. In an environment where N higher-layer
protocols need to be layered on M lower-layer protocols, this
approach requires N x M layering sequences. Adding a new
higher-layer protocol requires creating only one new layering
sequence. Adding a new lower-layer protocol requires N new
layering sequences.
The major fault with this approach is that it violates the
TLM connection methodology that is integral to UVM by
calling the implementation methods directly. Further, should
multiple layering sequence instances be erroneously connected
to the same higher-layer sequencer, they will interfere with
each other, resulting in difficult-to-explain behavior.

IV. DELAYERING
If protocols are layered on the way down, they must
similarly be “delayered” on the way up. Reference [3] does
show how a delayering monitor can observe lower-level
transactions through an analysis export and report observed
higher-layer transactions through its own analysis port. Figure 6. Layered Duplex Protocol
function write(lli_typ lli);
// Only consider lower-level items
The only problem with connecting the analysis port of a
// that belong to us monitor to the layering sequence (or any sequence for that
if (lli.dest != addr) return; matter) is that analysis exports must be implemented by a
write() method located in a uvm_component type.
// Collect lower-level items and Unfortunately, because sequences are not components, they
// re-constitute higher-layer items cannot have analysis exports. That is why [3] encapsulates the
hli.data[i] = lli.data; layering sequence and delayering monitor in a layering
if (hli.data.size() == hli.len) begin uvm_subscriber component that includes an analysis export for
ap.write(hli); the lower-layer protocol.
hli = hli_typ::type_id::create(“hli”);
end This puts the onus on the users to encapsulate each protocol
endfunction layering operation into individual components so the analysis
ports can be properly connected. In an environment where N
higher-layer protocols need to be layered on M lower-layer seq_item_port.item_done();
protocols, this approach requires N x M layering sequences end
encapsulated in N x M components. Adding a new higher-layer endtask
protocol requires creating M new layering components. Adding
a new lower-layer protocol requires N new layering endclass
components. The layering driver should be implemented as an extension
of the default agent driver. This will make it possible to replace
V. LAYERING AGENTS the original driver in the higher-level agent using the factory.
All of the existing layering examples seem to assume that
higher-level protocols can only be layered onto a lower-level
protocol and that no agent already exists for that protocol. They
assume that the user is free to create and instantiate a sequencer
for those higher-level protocols. But what if a sequencer for
that particular protocol already exists? What if it needs to be
connected to the monitor or driver in specific ways because of
the reactive nature of the protocol? What if the protocol
transactions require configuration information from the agent
context to be properly randomized? That is why UVM defines
the agent as the smallest unit of protocol-level reuse, not the
sequencer or the monitor.
Furthermore, some higher-level protocols may very well
have a physical transport implementation and thus need not
necessarily be layered. For example, Ethernet frames can be
transmitted over a variety of physical interfaces for which a
driver would be available. But they may also be transported by
another protocol (for example Ethernet-over-PPP) and thus
would require layering.
Layering agents is a more efficient reuse strategy, as it Figure 7. Layering Drivers
enables reusing the sequencer and monitor they contain instead
of instantiating and connecting new one. The only component The layering driver should be connected to the lower-layer
that needs replacing is the driver: should it remain in place, it sequencers using a simple passthru sequence. That passthru
will compete with the layering sequence for the agent’s sequence is functionally equivalent to the virtual interface of a
sequence items and break the execution of the higher-layer “regular” driver and thus should similarly be passed via the
protocol. configuration database. A passthru sequence is used in
preference to using the uvm_sequencer_base::send_request()
VI. A REUSABLE AND SCALABLE IMPLEMENTATION or uvm_sequencer_base::execute_item() methods so it can be
configured with state information, such as priority, to shape the
Because the driver in a protocol agent needs to be replaced
lower-level protocol traffic.
or shut down when that protocol needs to be layered, and since
layering sequences connect sequencers and are therefore class ll_passthru_seq extends
essentially components, the layering should be implemented in uvm_sequence#(lli_typ);
a layering driver, more specifically in its run_phase() method.
A layering driver is implemented using the same familiar lli_typ req;
techniques used to implement a “regular” driver, except that a int priority = -1;
sequence item is executed in terms of lower-level transactions
task body();
instead of pin wiggling through a virtual interface.
forever begin
class h2l_layering_driver extends ll_driver; wait (req != null);
... start_item(req, priority);
virtual task run_phase(uvm_phase phase); finish_item(req, priority);
forever begin req = null;
seq_item_port.get_next_item(hli); end
while (...) begin endtask
`uvm_create(lli) endclass

// Slice and dice hli to form lli’s class h2l_layering_driver extends ll_driver;
lli.data[i] = ...;
... virtual task run_phase(uvm_phase phase);
execute(lli) ll_passthru_seq ll_seq;
end uvm_config_db#(ll_passthru_seq)::get(this,
“seq”, ll_seq); The concept of the layering driver is also in keeping with
forever begin the current concept of a driver in UVM. What is a driver if not
seq_item_port.get_next_item(hli); a layering device between a sequence item and physical
while (...) begin signals?
`uvm_create(lli)

// Slice and dice hli to form lli’s VII. SUMMARY


lli.data[i] = ...; TABLE I. shows a comparative summary of using layering
... sequences vs. layering drivers for N higher-level protocols and
ll_seq.req = lli; M lower-level protocols, and the incremental effort for adding
wait (ll_seq.req == null);
a high-level and low-level protocol. It clearly shows that using
end
seq_item_port.item_done(); layering drivers is the more scalable approach.
end
endtask TABLE I. COMPARISON OF LAYERING APPROACHES

class layered_env extends uvm_env; Layering Sequence Layering Driver


... Number Of (as in [3])
ll_passthru_seq ll_seq;
Protocols NxM N+1 M+1 NxM N+1 M+1
function build_phase(uvm_phase phase); Sequences NxM M N M 0 1
hl = hl_agent::type_id::create(“hl”, this);
set_inst_override_by_type(“hl.drv”, Sequencers N 1 0 0 0 0
ll_driver::get_type(),
h2l_layering_driver::get_type()); Components NxM M N NxM M N
endfunction

function connect_phase(uvm_phase phase); VIII. LOOKING FORWARD


ll_seq = new(); In most networking application, it is necessary to verify the
uvm_config_db#(ll_passthru_seq)::set(this, dynamic reprovisioning of components and the ability of
“”, “seq”, ll_seq); components to adapt to changes in the protocol topology. For
endfunction example, adding and removing devices and hubs from a USB
network is a normal operation of that protocol. Similarly, it is
task run_phase(uvm_phase phase);
ll_seq.start(hl.sqr);
normal for TCP sessions to appear and disappear, or for the
endtask bandwidth of an OC-192 channel to be reconfigured between a
... variable number of tributaries of different lower bandwidth.
endclass Therefore, it should be possible for the layered protocol
Because the layering driver is a component, it can have and VIP structure to adapt to dynamic changes in the modeled
implement an analysis export for duplex protocols. network, and be able to add and remove additional protocol
layers and sibling protocol streams.
class h2l_layering_driver extends ll_driver;
uvm_analysis_imp#(lli_typ) ap; These normal protocol network operations must be verified.
In keeping with the constrained-random philosophy of UVM, it
function write(lli_typ lli); would be desirable to be able to randomly modify the protocol
// Only consider lower-level items structures at random times. Using layering, these varied
// that belong to us protocol structures can be implemented in a reusable and
if (lli.dest != addr) return; scalable way. Unfortunately, due to the static nature of UVM
components, the entire protocol hierarchy cannot be
// Process the response/credits dynamically modified at run-time. All alternative protocol
...
hierarchies must be created entirely at build time.
endfunction
endclass To support these verification scenarios, a future UVM
should allow the dynamic modification of the component
Different higher-level protocols or multiple streams of the
hierarchy.
same higher-level protocol may be layered onto the same
lower-level agent by simply starting multiple concurrent
passthru sequences on the lower-level sequencer. REFERENCES
[1] Open Systems Interconnection (OSI) model, ISO/IEC 7498-1.
In an environment where N higher-layer protocols need to
[2] Accellera, “Universal Verification Methodology (UVM) 1.1 User’s
be layered on M lower-layer protocols, this approach requires Guide, May 2011
N x M layering drivers and M passthru sequences. Adding a
[3] Mentor Graphics, “Layering in UVM”, Verification Horizon, Vol 7, no
new higher-layer protocol requires creating M new layering 3, pp 25-27
drivers. Adding a new lower-layer protocol requires only one
passthru sequence.

You might also like