Chapter 4 – Sequences and sequencers

The first step in verifying a RTL design is defining what kind of data should be sent to the DUT. While the driver deals with signal activities at the bit level, it doesn’t make sense to keep this level of abstraction as we move away from the DUT, so the concept of transaction was created. A transaction is a class object, usually extended fromuvm_transaction oruvm_sequence_itemclasses, which includes the information needed to model the communication between two or more components.

Transactions are the smallest data transfers that can be executed in a verification model.
They can include variables, constraints and even methods for operating on themselves.
Due to their high abstraction level, they aren’t aware of the communication protocol
between the components, so they can be reused and extended for different kind of tests if
correctly programmed.
An example of a transaction could be an object that would model the communication bus
of a master-slave topology. It could include two variables: the address of the device and
the data to be transmitted to that device. The transaction would randomize these two
variables and the verification environment would make sure that the variables would
assume all possible and valid values to cover all combinations.
In order to drive a stimulus into the DUT, a driver component converts transactions into
pin wiggles, while a monitor component performs the reverse operation, converting pin
wiggles into transactions.
After a basic transaction has been specified, the verification environment will need to
generate a collection of them and get them ready to be sent to the driver. This is a job for
the sequence. Sequences are an ordered collection of transactions, they shape
transactions to our needs and generate as many as we want. This means if we want to
test just a specific set of addresses in a master-slave communication topology, we could
restrict the randomization to that set of values instead of wasting simulation time in invalid
values.
Sequences are extended from uvm_sequence and their main job is generating multiple
transactions. After generating those transactions, there is another class that takes them to
the driver: the sequencer. The code for the sequencer is usually very simple and in simple
environments, the default class from UVM is enough to cover most of the cases.

They can include variables, constraints and even methods for operating on themselves.
Due to their high abstraction level, they aren’t aware of the communication protocol
between the components, so they can be reused and extended for different kind of tests if
correctly programmed.
An example of a transaction could be an object that would model the communication bus
of a master-slave topology. It could include two variables: the address of the device and
the data to be transmitted to that device. The transaction would randomize these two
variables and the verification environment would make sure that the variables would
assume all possible and valid values to cover all combinations.
In order to drive a stimulus into the DUT, a driver component converts transactions into
pin wiggles, while a monitor component performs the reverse operation, converting pin
wiggles into transactions.
After a basic transaction has been specified, the verification environment will need to
generate a collection of them and get them ready to be sent to the driver. This is a job for
the sequence. Sequences are an ordered collection of transactions, they shape
transactions to our needs and generate as many as we want. This means if we want to
test just a specific set of addresses in a master-slave communication topology, we could
restrict the randomization to that set of values instead of wasting simulation time in invalid
values.
Sequences are extended from uvm_sequence and their main job is generating multiple
transactions. After generating those transactions, there is another class that takes them to
the driver: the sequencer. The code for the sequencer is usually very simple and in simple
environments, the default class from UVM is enough to cover most of the cases.

A representation of this operation is shown in Figure 4.1


Figure 4.1 - Relation between a sequence, asequencer and a driver

The sequence englobes a group oftransactions and the sequencer takes a transaction

from the sequence and takes it to thedriver.

To test our DUT we are going to define asimple transaction, extended

from uvm_sequence_item. It will include thefollowing variables:

 rand bit[1:0] ina

 rand bit[1:0] inb

 bit[2:0] out

The variables ina and inb are going to berandom values to be driven to the inputs of the

DUT and the variable out is going to storethe result. The code for the transaction is

represented in Code 4.1.

class simpleadder_transaction extendsuvm_sequence_item;

rand bit[1:0] ina;

rand bit[1:0] inb;

bit[2:0] out;

function new(string name = "");

super.new(name);

endfunction: new

`uvm_object_utils_begin(simpleadder_transaction)

`uvm_field_int(ina, UVM_ALL_ON)

`uvm_field_int(inb, UVM_ALL_ON)

`uvm_field_int(out, UVM_ALL_ON)

`uvm_object_utils_end

endclass: simpleadder_transaction

Code 4.1 – Transaction for the simpleadder


An explanation of the code will follow:

 Lines 2 and 3 declare the variables forboth inputs. The rand keyword asks the

compiler to generate and store randomvalues in these variables.

 Lines 6 to 8 include the typical classconstructor.

 Lines 10 to 14 include the typical UVMmacros.

These few lines of code define theinformation that is going to be exchanged between the

DUT and the testbench.

To demonstrate the reuse capabilities ofUVM, let’s imagine a situation where we would

want to test a similar adder with a thirdinput, a port named inc.

Instead of rewriting a differenttransaction to include a variable for this port, it would be

easier just to extend the previous class tosupport the new input.

It’s possible to see an example in Code5.2.

class simpleadder_transaction_3inputsextends simpleadder_transaction;

rand bit[1:0] inc;

function new(string name = "");

super.new(name);

endfunction: new

`uvm_object_utils_begin(simpleadder_transaction_3inputs)

`uvm_field_int(inc, UVM_ALL_ON)

`uvm_object_utils_end

endclass: simpleadder_transaction_3inputs

Code 5.2 – Extension of the previoustransaction


As a result of the classsimpleadder_transaction_3inputs being an extension

of simpleadder_transaction, we didn’t needto declare again the other variables. While in

small examples, like this one, this mightnot look like something useful, for bigger

verification environments, it might save alot of work.

Sequence

Now that we have a transaction, the nextstep is to create a sequence.

The code for the sequencer can be found inCode 5.3.

class simpleadder_sequence extendsuvm_sequence#(simpleadder_transaction);

`uvm_object_utils(simpleadder_sequence)

function new(string name = "");

super.new(name);

endfunction: new

task body();

simpleadder_transaction sa_tx;

repeat(15) begin

sa_tx = simpleadder_transaction::type_id::create(...

start_item(sa_tx);

assert(sa_tx.randomize());

finish_item(sa_tx);

end

endtask: body

endclass: simpleadder_sequence

Code 5.3 - Code for the sequencer


An explanation of the code will follow:

 Line 8 starts the task body(), which isthe main task of a sequence

 Line 11 starts a cycle in order togenerate 15 transactions

 Line 12 initializes a blank transaction

 Line 14 is a call that blocks until thedriver accesses the transaction being created

 Line 15 triggers the rand keyword of thetransaction and randomizes the variables

of the transaction to be sent to the driver

 Line 16 is another blocking call whichblocks until the driver has completed the

operation for the current transaction

Sequencer

The only thing missing is the sequencer.The sequence will be extended from the

classuvm_sequencer and it will beresponsible for sending the sequences to the driver.

The sequencer gets extended fromuvm_sequencer. The code can be seen on Code 5.4.

1 typedefuvm_sequencer#(simpleadder_transaction) simpleadder_seque

ncer;

Code 5.4 – Extension of the previoustransaction

The code for the sequencer is very simple,this line will tell UVM to create a basic

sequencer with the default API because wedon’t need to add anything else.

So, right now our environment has thefollowing structure



Figure 4.2 State of the verification environment after the sequencer





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值