Virtual sequencer UVM: choose the right child sequencer
I have a question about the virtual sequencer in UVM. Suppose I have N equal interfaces driven by N equal drivers, each associated with its own sequencer. I want to make a transaction like:
class my_transaction extends uvm_sequence_item;
logic data;
int num_if;
endclass
which when executed with `uvm_do () is sent to the driver number num_if. My idea is that for this kind of work I need a virtual sequencer that "translates" the transaction into the right sequencer (number num_if). It is right? If so, how can this be done? Thank.
source to share
While Tudor's answer will work technically, conceptually deciding which of the interfaces to run (num_if) is a value that shouldn't belong to the transaction, but to the sequence that calls it (which of course should also be randomized) ... Transactions should only contain a representation of the value that moves from A to B and the way it moves for that protocol. Specification A and B are usually not included in the transaction price.
In this case, a variation on your Tudor transaction and sequence would look like this:
class my_transaction extends uvm_sequence_item;
rand logic data;
endclass
.. and ..
class some_virtual_sequence extends uvm_sequence;
`uvm_declare_p_sequencer(virtual_seqr)
rand int num_if; constraint.....
task body();
my_transaction trans = my_transaction::type_id::create("my_transaction");
start_item(trans, , p_sequencer.seqrs[num_if]);
trans.randomize(); // randomization should be done after start_item()
finish_item(trans);
endtask
endclass
.. runs on a virtual sequencer, as Tudor says:
class virtual_seqr extends uvm_sequencer;
my_sequencer seqrs[10];
endclass
The above approach also allows you to randomize in the correct place: after start_item () returns and immediately before calling finish_item (), which ends the sequence item.
source to share
You are right about the virtual sequencer. I'll show you an idea of how to do this (all pseudocode, you'll have to work with the details yourself).
Let's say we have a virtual sequencer containing an array of all bus sequencers:
class virtual_seqr extends uvm_sequencer;
my_sequencer seqrs[10];
endclass
We will assume that these descriptors are passed correctly. In our virtual sequence, we can create a transaction, randomize it, and then send it to the appropriate sequencer.
class some_virtual_sequence extends uvm_sequence;
`uvm_declare_p_sequencer(virtual_seqr)
task body();
my_transaction trans = my_transaction::type_id::create("my_transaction");
my_transaction.randomize();
start_item (my_transaction, , p_sequencer.seqrs[my_transaction.num_if]);
finish_item(my_transaction);
endtask
endclass
We cannot use uvm_do
because it does not know where to send. We also can't use it uvm_do_on
, because the field num_if
must be randomized before knowing where to send the item.
source to share