How do I disable base class constraints in a transaction extension?

I need to constrain a transaction to hit some corner cases. (it’s a packet length)

So I made a new test for my corner cases, and I also extended my transaction to apply constraints on it’s length.

The sequence creates NUM transaction items, and sends them.

What do you recommend for disabling constraints in a base class? I cannot explicitly disable the constraint in the thread because the transaction doesn’t even exist until the sequence runs. So, my approach was to extend the base, and disable constraints by re declaring it with no contents, and then adding my new constraints. Alternatively, I suppose I could just overwritten it. Anyway, is this to best approach?

  class udp_ArpIp_len_corner_cases extends udp_ArpIp;
    `uvm_object_utils(udp_ArpIp_len_corner_cases)

    constraint c_payload_len {} // disable this constraint in base class
    constraint c_len_corner { // add new constraint
      payload.size() inside {
        MIN_UDP_PAYLD_LEN-1,
        MIN_UDP_PAYLD_LEN,
        MAX_UDP_PAYLD_LEN,
        MAX_UDP_PAYLD_LEN+1,
        [MAX_UDP_PAYLD_LEN+2:2000]
      };
    }

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

  endclass
  class test_UDP_PutPkt_corner_cases extends test_base ;
    `uvm_component_utils(test_UDP_PutPkt_corner_cases);

    const string report_id="test_UDP_PutPkt_corner_cases";

    function new(string name="", uvm_component parent=null);
      super.new(name, parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase); // execute test base
    endfunction

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

      t_init();

      // use extension
      udp_transaction::type_id::set_type_override(udp_ArpIp_len_corner_cases::get_type());
      
      begin
        seq_PutPkt_udp seq;
        seq = seq_PutPkt_udp::type_id::create("seq",,);
        seq.csel=DUT_CS;
        if(!seq.randomize() with {num==NUM;}) `uvm_error("RANDERR","Randomization error")
        seq.start(sqr_pack.plb_sqr);
      end

      #100us;

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

  endclass

In reply to bmorris:
You actually now have 4 different choices for doing this.

  1. Override with an empty constraint, and add new constraint. This runs the risk of having a typo and winding up with both constraints active.
  2. Override with a replacement constraint. This shows your intent with the most clarity.
  3. Disable the base constraint using constraint_mode in the extended constructor. This allows you to turn it back on later if needed in the sequence, or an extended sequence.
  4. Use a soft constraint. This allows you to add new constraints, and only removes the existing soft constraint if it conflicts. I find this either works great for some situations, and doesn’t work for other situations.

In reply to dave_59:

thanks for the suggestions. Option 4 was not working correctly given some of the constraints I had. I think 2) and 3) have the most clarity: thanks

  class udp_ArpIp_len_corner_cases extends udp_ArpIp;
    `uvm_object_utils(udp_ArpIp_len_corner_cases)

    constraint c_payload_length {
      payload.size() inside {
        UDP_HDR_LEN,
        MIN_UDP_PAYLD_LEN-1,
        MIN_UDP_PAYLD_LEN,
        MAX_UDP_PAYLD_LEN,
        MAX_UDP_PAYLD_LEN+1,
        MAX_UDP_PAYLD_LEN+500
      };
    }

    function new( string name="" );
      super.new(name);
      c_payload_32b_align.constraint_mode(0);
    endfunction

  endclass

Hit all the corner cases just fine:
COVERPOINT uvm_test_top.env.plb_PutPkt_cov_h.PutPkt_udp_cg::cp_len 57.143% 100.000% Uncovered
bin too_small 20 1 Covered
bin min_len 10 1 Covered
bin small_pkt 0 1 Zero
bin med_pkt 0 1 Zero
bin large_pkt 0 1 Zero
bin max_len 8 1 Covered
bin too_big 12 1 Covered