Lets say I have a sequence that, before sending any transactions, needs to wait on a certain event to happen. E.g. Reset to deassert, 100 clock cycles, etc.
Is there a way to do this without using a virtual interface passed into the sequence?
Lets say I have a sequence that, before sending any transactions, needs to wait on a certain event to happen. E.g. Reset to deassert, 100 clock cycles, etc.
Is there a way to do this without using a virtual interface passed into the sequence?
In reply to bmorris:
Yes. I will make a system agent that connects to resets, clocks and other auxiliary signals. I will then define sequences for this agent that will wait for a specific reset signal level, wait for a given number of clocks, etc. These sequences will be used in the test to handle any timing specific requirements.
In reply to cgales:
I was hoping you would reply; we’ve discussed this before but I haven’t quite drank the Kool-Aid.
An example of the transaction class used on this synchronization agent would probably answer all all my questions.
In reply to bmorris:
The generation of sequence items/transactions is starting when you are performing your get command in the driver. The most simple solution is to handle this behavior there.
In reply to bmorris:
package utility_parameters_pkg;
parameter string CONFIG_NAME = "utility_agent_cfg";
typedef enum bit[1:0] {MASTER, SLAVE, MONITOR} agent_mode_t;
typedef enum bit[1:0] {DRIVE_RESET, WAIT_RESET, WAIT_CLOCKS} agent_cmd_t;
endpackage
//----------------------------------------------------------------------
// utility_item
//----------------------------------------------------------------------
class utility_item extends uvm_sequence_item;
// factory registration macro
`uvm_object_utils(utility_item)
// user stimulus variables (rand)
rand int unsigned repeat_count;
rand agent_cmd_t cmd = WAIT_CLOCKS;
// user response variables (non rand)
constraint repeat_count_c { soft repeat_count inside {[5:1000]};};
//--------------------------------------------------------------------
// new
//--------------------------------------------------------------------
function new (string name = "utility_item" );
super.new(name);
endfunction: new
endclass
The driver will look at the cmd field in the sequence item and act appropriately. It can drive reset for the repeat_count number of clocks, wait for the repeat_count number of clocks, or wait for the reset signal to go high/low.
In reply to cgales:
Thanks. For system signals like clock/reset I can understand the approach, and you could reuse the agent. What about application specific DUT signals? If you tuck those into the same agent, you can’t reuse it anymore.
Furthermore, everytime I’m interested in a new signal to observe, I’ve got to update the interface, the transaction object, and the driver just to get access to it, versus just the interface.
In reply to cgales:
I do not believe this is a flexible approach.
You should follow what I have recommended. Then your ae focused on the driver only.
BTW a new transaction is only generated when you have completed the processing of the last on.
I believe you should try to understand the TLM approach.
A transaction does not know anything about time units and clock cycles.
In reply to chr_sue:
I completely agree that handling of transaction delays and wait for resets should be handled in the UVC driver. I will typically include a delay field in a sequence item that will allow you to delay a transaction for a given number of interface clocks.
However, the utility agent can give some more flexibility in creating various sequences where perhaps you want two transactions to start at the same time even if they have different interface clocks. By using a utility agent, you can start the two sequences at the same time after a delay.
In reply to bmorris:
You can create a signal bus which you can then assign each individual signal to a DUT signal (Kind of like a GPIO bus). You can then create commands which would wait until a specific bit of the bus goes high or low. Pass in the index of the signal and the value that you want to wait for. This keeps the agent generic yet flexible for reuse.
In reply to chr_sue:
cgales approach uses TLM, and the driver does all the signal interactions. The sequence is not stalling, etc, it issues utility transactions to a utility agent.
“A transaction does not know anything about time units and clock cycles.”
If you want your driver to do some waiting, where does it get the num_of_cycles_to_wait from? It has to be from the txn.
In reply to cgales:
That helps. thanks.
I’ve got a vseq that needs to check if a buffer is available before sending a packet.
Options are:
I’ll bind in a gpio bus and create a generic-as-possible utility agent.
In reply to bmorris:
I will take the same approach that a user will. Does the user have to poll a register? Is there a top-level signal or interrupt that indicates there is space? What happens if data is written when the buffer is full?
If all these are potential use cases, then they should all be tested. I find that using backdoor access to determine status is not a good approach since the user won’t ever be able to do the same thing.
In reply to cgales:
Understood. The user must request the information from the DUT. In application, I would set a reasonable polling delay to ask for this information. thanks!
In reply to chr_sue:
In reply to cgales:
I do not believe this is a flexible approach.
You should follow what I have recommended. Then your ae focused on the driver only.
BTW a new transaction is only generated when you have completed the processing of the last on.
I believe you should try to understand the TLM approach.
A transaction does not know anything about time units and clock cycles.
This makes a lot of sense. Yet I’m not sure of pro/cons of adding delays in sequence, a lot of good books on SystemVerilog/testbench mentions that, only driver and monitor deals with interface. While when moving for top level components, they take TLM approach.
It is important to understand TLM and whether it should deal with low level interface or delays. I think adding interface/delay in sequence means we are diving driver functionality and putting it there in sequence, and same thing needs to be repeated with every sequence we create.