How to configure extended transaction

I have a sequence item class, and it’s extension:

class txn extends uvm_sequence_item;
  `uvm_object_utils(txn)

  rand int A;

  //...

endclass

// extension
class txn_ext extends txn;
  `uvm_object_utils(txn_ext)

  int B;
  constraint c_A { A<B; }

  //...

endclass

I have the following sequence, which runs a single object of txn.

class seq_A extends uvm_sequence #(txn);
  `uvm_object_utils(seq_A)

  virtual task body();
    txn t;
    t = txn::type_id::create("t");
    start_item(t);
    if(!t.randomize()) `uvm_error("RANDERR","Randomization error")
    finish_item(t);
  endtask

  // ...

endclass

In my test, I want to run the sequence, do a factory override of the transaction, then repeat the sequence.

class test_A extends test_base ;
  `uvm_component_utils(test_A)

  virtual task run_phase( uvm_phase phase );
    phase.raise_objection(this, "Objection raised by test_base");

    begin
      seq_A seq;
      seq = seq_A::type_id::create("seq");
      seq.start(sqr); // send unconstrained transaction

      txn::type_id::set_type_override(txn_ext::get_type());
      // ??? <------- configure B here? How?
      seq.start(sqr); // send constrained transaction

    end

    phase.drop_objection(this, "Objection raised by test_base");
  endtask

  //...

endclass

Where/How do I configure integer ‘B’ of the extension?

In reply to bmorris:

You can do it like this:

  begin
      seq_A seq;
      seq = seq_A::type_id::create("seq");
      seq.start(sqr); // send unconstrained transaction
 
      txn::type_id::set_type_override(txn_ext::get_type());
      seq.randomize with {B == any_value or range};
      seq.start(sqr); // send constrained transaction
 
    end

In reply to chr_sue:
That will not work as B is not a member of seq_A

You might consider using the config DB for this.

In reply to dave_59:

txn_ext do a dB pull to acquire B? Then I’ve got the performance issue of my transaction extensions all using the dB to configure.

Putting B in the base class would at least allow the sequence to configure it, but that’s not a realistic option because it’s not OO or scalable.

Apparently I’m also supposed to avoid inline constraints for configuring sequences too. So that knocks out the sequence configuring it.

I’m also supposed to avoid m_sequencer/p_sequencer.

Making B static seems like the most straight-forward way to configure it directly from the test.

Is this example not the bread and butter of the language? Why isn’t there a trivial way to implement it?

In reply to bmorris:

The trivial thing to do for your example is making B a parameter.

class txn_ext #(int B) extends txn;
  `uvm_object_utils(txn_ext)
  constraint c_A { A<B; }
  //...
endclass

Then you can set B as part of the factory override

      txn::type_id::set_type_override(txn_ext#(.B(10))::get_type());

But more generally, I think your problem is you created an extension requiring external configuration. You could just create more extensions with the configuration self-contained.

class txn_ext10 extends txn_ext;
  `uvm_object_utils(txn_ext10)
 function new(
   super.new()
   B = 10; 
endfunction 
endclass

And still another approach is to construct the transaction before starting the sequence and not constructing inside the sequence. Use clone() to create more copies if you need them rather than create().

In reply to dave_59:

The correct value for B only becomes known well into the simulation. The parameter idea could work. thanks