How to pause a sequence based on event

Hi,

I have a question about how to pause a uvm_sequence based on events.

My test setup is like this:

  1. I am trying to simulate a QoS-based flow control traffic
  2. I have one driver and 4 sequences, all the four sequences are being arbitrated on the same sequencer. Each sequence represents a QoS class.
  3. During the simulation, all four sequences will be driving data via the same driver. In the meantime, the environment will generate a pause-event to pause a certain sequence (let’s say sequence 0).

What I want to achieve:

  1. When the environment generates the pause-event to pause sequence0, only sequence0 should be paused, while seq1,2,3 should continue to drive data to the DUT
  2. After some time, when the environment generates the clear_pause-event to unpause sequence0, sequence0 should resume driving data

I wonder is there any existing UVM mechanism to let me do this? Or I have to extend the sequencer and write my own arbitration policy?

Thanks in advance for your help!

Hao

In reply to peterjin:

Because there are multiple sequences share the same sequencer, then you need to pause sending the stumilus in your particular sequence. The simplest way:

  • Declare the pause event flag in sequence-config, set the config to your sequences
  • Get the config and check the condition of pause event in order to generate stimulus in your sequences
  • Control the pause event flag in your environment when you want to pause/unpause.

In reply to peterjin:

What you are trying to do is useless. The sequencer does not actively send a seq_item to the driver. This happens only when you are using the uvm_push_sequencer.
In your case the driver is retrieving a seq_item from the sequencer. The sequencer is only providing the seq_item. The consequence is all timing related activity has to be in the driver. Stopp your driver and it will not retrieve a new seq_item. Very simple to implement.

Hi Hao,

In reply to peterjin:

Hi,
I have a question about how to pause a uvm_sequence based on events.
My test setup is like this:

  1. I am trying to simulate a QoS-based flow control traffic

This immediately gets me thinking about using the priority feature of the sequencer.

  1. I have one driver and 4 sequences, all the four sequences are being arbitrated on the same sequencer. Each sequence represents a QoS class.
  1. During the simulation, all four sequences will be driving data via the same driver

When not throttled, do they all have equal priority?

In the meantime, the environment will generate a pause-event to pause a certain sequence (let’s say sequence 0).
What I want to achieve:

  1. When the environment generates the pause-event to pause sequence0, only sequence0 should be paused, while seq1,2,3 should continue to drive data to the DUT

This would correspond to lowering the priority of a sequencer.

  1. After some time, when the environment generates the clear_pause-event to unpause sequence0, sequence0 should resume driving data

This would correspond to restoring the priority.

[br]It sounds like you could use set_arbitration() to put the sequencer in either UVM_SEQ_ARB_STRICT_FIFO or UVM_SEQ_ARB_STRICT_RANDOM mode, and then alter the priority of sequences as needed. If your environment has a handle to all of the sequences which need to have their QoS modified, it would simply call set_priority() on the sequence you want to pause or unpause.

The change in priority will apply to the next item the sequence tries to send. If there is already a pending item already started on the sequencer, it’s priority won’t be changed.

-Ryan

In reply to warnerrs:

Setting the sequencer priority only changes the order of traffic to driver, it does not make a sequence stop sending stimulus (pause), Then, I think the simplest way is controlling the generation in sequence if you want to pause/unpause traffic for a particular sequence.

In reply to cuonghle:

In reply to warnerrs:
Setting the sequencer priority only changes the order of traffic to driver, it does not make a sequence stop sending stimulus (pause), Then, I think the simplest way is controlling the generation in sequence if you want to pause/unpause traffic for a particular sequence.

Note, the traffic between sequencer and driver is determined by the driver NOT the sequencer.
The sequencer doe NOT send any transactionn to the driver. The driver is polling a seq_item. It is just easy to implement your behavior in the driver.

In reply to cuonghle:

Setting the sequencer priority only changes the order of traffic to driver, it does not make a sequence stop sending stimulus (pause), Then, I think the simplest way is controlling the generation in sequence if you want to pause/unpause traffic for a particular sequence.

I forgot about the case where only the paused sequence is trying to send items. Still, QoS is a form of arbitration, so putting it in the sequencer is a natural fit. If this scenario requires that the paused sequence stay paused, even when there are no other sequences trying to send items, then the UVM_SEQ_ARB_STRICT_* modes won’t work.

User defined arbitration ( UVM_SEQ_ARB_USER ) could be added to the sequencer to handle this without requiring adding anything into the sequences. The advantage of that is, you can write sequences that aren’t even aware the QoS mechanism exists. Any sequence ran on that sequencer would be affected. You still need to have some env component altering the priority ( pause state ) of the sequences.

If you go with cuonghle’s sequence based approach, you might implement is_relevant() and wait_for_relevant(). That way you don’t have to put pausing code explicitly in the sequence body(). Implement them in a base sequence shared by all QoS sequences.

In reply to chr_sue:

Note, the traffic between sequencer and driver is determined by the driver NOT the sequencer.
The sequencer doe NOT send any transactionn to the driver. The driver is polling a seq_item. It is just easy to implement your behavior in the driver.

I don’t follow how the driver can implement a QoS arbitration scheme. The driver can stop getting the next item, but if there are multiple sequences trying to send items at different QoS level, such a mechanism will block items from all sequences.

-Ryan

In reply to chr_sue:

In reply to cuonghle:
Note, the traffic between sequencer and driver is determined by the driver NOT the sequencer.
The sequencer doe NOT send any transactionn to the driver. The driver is polling a seq_item. It is just easy to implement your behavior in the driver.

What you said is confusing.
The topic owner has 4 sequences, they start same sequencer and there is one driver to drive the transaction to DUT. Now, he wants to pause (stop sending traffic) from a particular sequence, but other sequences are still working.
Why you want to implement this behavior in the driver? And how?
In order to pause, the easy way is pausing the source of the traffic which is in sequence.

In reply to cuonghle:

You can do this by adding a specific ID to the seq_items. In the driver you are checking this item and do not process this simply discardingg it.

In reply to cuonghle:

In reply to warnerrs:

Hi Ryan, Chris:

Thanks for your reply.

I forgot about the case where only the paused sequence is trying to send items. Still, QoS is a form of arbitration, so putting it in the sequencer is a natural fit. If this scenario requires that the paused sequence stay paused, even when there are no other sequences trying to send items, then the UVM_SEQ_ARB_STRICT_* modes won’t work.

Yes, the paused sequence will stay paused as long as DUT (slave-side) is asserting pause to the driver.

What I have implemented is whenever the paused sequence detects the pause signal (I did a signal probe from my sequence, though I know this is not a proper way), it will skip the current packet generation and advance 1ps (to prevent dead loop). This is what my sequence looks like

task body;
int seq_qos; //indicate which qos this sequence represents
...
while (generated_pkt < pkt_to_send)begin
...
  if(dut.pause[seq_qos]==1) begin//pasue is bitmap based pause
    #1ps; 
    contiune
  end
  else begin
    start_item(req);
    finish_item(req);
    generated_pkt++; //only increase when a packet was truly generated
  end
end

However, from what I observed from the waveform, when DUT paused qos0, even though I did see sequence 1-3 is able to generate packets for qos1-3, but it was driving at a much slower speed. (I am expecting sequence 1-3 to generate at full speed, but the actual speed is 10x slower)

In that case, I think I should write my own arbitration_policy for my sequencer. But I wonder why detecting and adding the 1ps delay (my DUT clock cycle is 1ns) in seq0 will significantly slow down the traffic generation for other sequences?

Thanks for all your help,

Hao

But I wonder why detecting and adding the 1ps delay (my DUT clock cycle is 1ns) in seq0 will significantly slow down the traffic generation for other sequences?
Thanks for all your help,
Hao

The idea to add 1ps delay was to avoid the simulation hang due to zero time consumption of the while-loop when pause, and it was not a good idea, it makes the simulator’s scheduling overloaded and slow down your simulation. You can improve it by changing:


task body;
int seq_qos; //indicate which qos this sequence represents
...
while (generated_pkt < pkt_to_send)begin
...
  wait(dut.pause[seq_qos] == 1'b0); // or using === operator if checking X
  start_item(req);
  finish_item(req);
  generated_pkt++;
end

In case of pause, the code is blocked at “wait” statement until unpause (dut.pause[seq_qos] = 0).

In reply to cuonghle:

Hi Chris,

Thanks for your answer, my problem solved with your solution

Thanks

Hao