How should I manage specific ordering of transactions in the sequencer

Some of the stimulus I provide my DUT with requires some (light) ordering. My basic solution was this:

class tb_sequence extends uvm_sequence#(tb_transaction);
    `uvm_object_utils(tb_sequence)

    function new(string name="");
        super.new(name);
    endfunction : new

    task body();
        tb_transaction tx;
        tb_transaction tmp_tx;

        repeat(1000) begin
            // Generate next transaction
            assert(tx.randomize());

            // Next transaction requires a special mode, set it first before sending the transaction
            if ( tx.cmd == SPECIAL_MODE_CMD ) begin
                // Generate special mode change transaction
                start_item(tmp_tx);
                assert(tmp_tx.randomize() with { cmd == SET_SPECIAL_MODE; });
                finish_item(tmp_tx);
            end

            // Send special mode transaction
            start_item(tx);
            finish_item(tx);
        end
    endtask : body
endclass : tb_sequence

Is this a reasonable approach, or is there something better? I am working on my first full UVM testbench as a lone verification engineer, so I’m not sure about a lot of best practices or common pitfalls to avoid.

In reply to heckey:

Yopu are doing things twice, see you code:

        repeat(1000) begin
            // Generate next transaction
            assert(tx.randomize());  
 
            // Next transaction requires a special mode, set it first before sending the transaction
            if ( tx.cmd == SPECIAL_MODE_CMD ) begin
                // Generate special mode change transaction
                start_item(tmp_tx);
                assert(tmp_tx.randomize() with { cmd == SET_SPECIAL_MODE; });
                finish_item(tmp_tx);
            end
 
            // Send special mode transaction
            start_item(tx);
            finish_item(tx);
        end

Do you really start with a completely unconstrained seq_item and then you want to genearte another one where the data member cmd = SET_SPECIAL_MODE:
Even when you want to do this you can remove the if construct.

In reply to chr_sue:

Thanks for the reply!

The idea is that DUT has no automatic response, it just responds to a sequence of commands. So when a special command is sent, I don’t want the DUT and the TB getting out of sync, and I force that mode automatically.

My “correct” (non-error test) order of commands is:

  1. SET_SPECIAL_MODE
  2. SPECIAL_MODE_CMD

    n. EXIT_SPECIAL_MODE

Since these are both discrete sequence items, I was using the sequence to enforce this order; it this good practice?

Another option is to set the default constraints in the transaction to the distribution {SET_SPECIAL_MODE := 10; SPECIAL_MODE_CMD := 1; EXIT_SPECIAL_MODE := 1}, use the monitor to detect if the mode was entered, and the sequencer can then adjust the distribution to {SET_SPECIAL_MODE := 1; SPECIAL_MODE_CMD := 10; EXIT_SPECIAL_MODE := 10}. This can be communicated using ports, analysis ports, uvm_config, or virtual sequences. I don’t like using the virtual sequences because this interface is wholly independent, so there shouldn’t be any synchronization or timing problems.

I could also use multiple sequences with different transaction distributions and use the sequencer to properly decide which to use based on the mode from the monitor as well.

Is there a guideline or recommendation?

Thanks!

In reply to heckey:

Is this the order of your commands you want to execute?
If yes, then generate the seq_items in the same order, like this:

               start_item(req);
               assert(req.randomize() with { cmd == SET_SPECIAL_MODE; });
               finish_item(req);

               repeat (1000) begin
                 start_item(req);
                 assert(req.randomize() with { cmd == SPECIAL_MODE_CMD; });
                 finish_item(tmp_tx);
               end

               start_item(req);
               assert(req.randomize() with { cmd == EXIT_SPECIAL_MODE; });
               finish_item(req);