Constraint Randomization Policy [With interface class] output not as excepted

Hello !

  1. Took a basic partial constraint policy example from the dvcon paper and built upon it.
  2. But upon execution looks like the outputs aren’t as expected.

addr_types.svh

typedef bit [31:0] addr_t;

class addr_range extends uvm_object;
  addr_t min;
  addr_t max;
  
  function new(addr_t min, addr_t max);
    this.min = min;
    this.max = max;
  endfunction
endclass

typedef class addr_txn;
typedef class addr_p_txn;

policy_base.svh

interface class policy;
    pure virtual function string name();
    pure virtual function string type_name();
    pure virtual function string description();
    pure virtual function bit item_is_compatible(uvm_object item);
    pure virtual function void set_item(uvm_object item);
    // pure virtual function policy copy();
endclass: policy 

typedef policy policy_queue[$];

virtual class policy_imp #(type ITEM=uvm_object) implements policy;
    protected rand ITEM m_item;

    pure virtual function string name();
    pure virtual function string description();
    // pure virtual function policy copy();

    virtual function string type_name();
        return (ITEM::type_name);
    endfunction: type_name

    virtual function bit item_is_compatible(uvm_object item);
        ITEM local_item;

        return ((item != null) && ($cast(local_item, item)));
    endfunction: item_is_compatible

    virtual function void set_item(uvm_object item);
        if (item == null)
            `uvm_error("policy::set_item()", "NULL item passed")

        else if ((this.item_is_compatible(item)) && $cast(this.m_item, item)) begin
            `uvm_info(
                "policy::set_item()",
                $sformatf(
                    "policy <%s> applied to item <%s>: %s",
                    this.name(), item.get_name(), this.description()
                ),
                UVM_FULL
            )
            this.m_item.rand_mode( 1 );

        end else begin
            `uvm_warning(
                "policy::set_item()",
                $sformatf(
                    "Cannot apply policy '%0s' of type '%0s' to target object '%0s' of incompatible type '%0s'",
                    this.name(), this.type_name(), item.get_name(), item.get_type_name()
                )
            )
            this.m_item = null;
            this.m_item.rand_mode( 0 );
        end
    endfunction: set_item
endclass: policy_imp

interface class policy_container;
    // Queries
    pure virtual function bit has_policies();

    // Assignments
    pure virtual function void set_policies(policy_queue policies);
    pure virtual function void add_policies(policy_queue policies);
    pure virtual function void clear_policies();

    // Access
    pure virtual function policy_queue get_policies();

    // Copy
    // pure virtual function policy_queue copy_policies();
endclass: policy_container

class policy_object #(type BASE=uvm_object) extends BASE implements policy_container;
    protected rand policy_queue m_policies;
  
    // Queries
    virtual function bit has_policies();
        return (this.m_policies.size() > 0);
    endfunction: has_policies

    // Assignments
    virtual function void set_policies(policy_queue policies);
        if(this.has_policies())
            `uvm_warning( "policy", "set_policies() replacing existing policies" )

        this.m_policies = {};
        foreach(policies[i]) try_add_policy(policies[i]);
    endfunction: set_policies

    virtual function void add_policies(policy_queue policies);
        foreach(policies[i]) try_add_policy(policies[i]);
    endfunction: add_policies

    virtual function void clear_policies();
        if (this.has_policies())
            `uvm_info("policy", $sformatf("clearing [%0d] policies from %s", this.m_policies.size(), this.get_name()), UVM_FULL)

        this.m_policies = {};
    endfunction: clear_policies

    // Access
    virtual function policy_queue get_policies();
        return (this.m_policies);
    endfunction: get_policies

    // Copy
    // virtual function policy_queue copy_policies();
    //     copy_policies = {};
    //     foreach(this.m_policies[i])
    //         copy_policies.push_back(this.m_policies[i].copy());
    // endfunction: copy_policies

    protected function void try_add_policy(policy new_policy);
        if (new_policy.item_is_compatible(this)) begin
            `uvm_info("policy", $sformatf("adding policy %s to %s", new_policy.name, this.get_name()), UVM_FULL)

            new_policy.set_item(this);
            this.m_policies.push_back(new_policy);
        end else
            `uvm_warning("policy", $sformatf("policy %s not compatible with target %s", new_policy.name, this.get_name()))
    endfunction: try_add_policy

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

endclass: policy_object

addr_txn.svh

// class addr_txn extends uvm_object;
class addr_txn extends policy_object#(uvm_object);
    rand addr_t addr;
    rand int    size;
    rand policy_queue policies;

    constraint c_size {size inside {1, 2, 4};}

    //dm function void pre_randomize;
    //dm   foreach(policies[i]) policies[i].set_item(this);
    //dm endfunction

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

   `uvm_object_utils_begin(addr_txn)
   `uvm_object_utils_end

    class POLICIES;
        // class addr_policy extends policy_object#(addr_txn);
        class addr_policy extends policy_imp#(addr_txn);
           addr_range ranges[$];

           virtual function string name();
               // return (ITEM::name);
               return name;
           endfunction: name 
           
           virtual function string description();
               return ("addr_policy base");
           endfunction: description 

           function void add(addr_t min, addr_t max);
               addr_range rng = new(min, max);
               ranges.push_back(rng);
              `uvm_info("addr_policy", $sformatf("rng: %p", rng), UVM_FULL)
           endfunction 
        endclass

        class addr_permit_policy extends addr_policy;
            rand int selection;

            constraint c_addr_permit {
              selection inside {[0:ranges.size()-1]};

              foreach(ranges[i]) {
                if(selection == i) {
                  m_item.addr inside {[ranges[i].min:ranges[i].max - m_item.size]};
                }
              }
            }
        endclass

        class addr_prohibit_policy extends addr_policy;
            constraint c_addr_prohibit {
              foreach(ranges[i]) {
                !(m_item.addr inside {[ranges[i].min:ranges[i].max - m_item.size + 1]});
              }
            }
        endclass
    endclass: POLICIES
endclass

class addr_p_txn extends addr_txn;
    rand bit parity;
    // protected rand bit parity_err;
    rand bit parity_err;

    constraint c_parity_err {
      soft (parity_err == 0);
      (parity_err) ^ ($countones({addr, parity}) == 1);
    }


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

   `uvm_object_utils_begin(addr_p_txn)
   `uvm_object_utils_end


    class POLICIES extends addr_txn::POLICIES;
        // class addr_parity_err_policy extends policy_object#(addr_p_txn);
        class addr_parity_err_policy extends policy_imp#(addr_p_txn);
            protected bit parity_err;
           
            virtual function string name();
                // return (ITEM::name);
                return name;
            endfunction: name 
            
            virtual function string description();
                return ("addr_policy base");
            endfunction: description 

            constraint c_fixed_value {m_item != null -> m_item.parity_err == parity_err;}

            // function new(bit parity_err);
            //    this.parity_err = parity_err;
            // endfunction
        endclass

        // static function addr_parity_err_policy PARITY_ERR(bit value);
        //     PARITY_ERR = new(value);
        // endfunction 
    endclass: POLICIES
endclass

class addr_constrained_txn extends addr_p_txn;
    function new(string name = "addr_constrained_txn");

        addr_constrained_txn::POLICIES::addr_permit_policy      permit_p   = new();
        addr_constrained_txn::POLICIES::addr_prohibit_policy    prohibit_p = new();
        addr_constrained_txn::POLICIES::addr_parity_err_policy  addr_parity_err_p = new();
        super.new(name);

        // only a single policy queue is necessary now
        permit_p.add('h00000000, 'h0000FFFF);
        permit_p.add('h10000000, 'h1FFFFFFF);
       `uvm_info("addr_constrained_txn", $sformatf("permit_p: %p", permit_p), UVM_FULL)
        try_add_policy(permit_p);
        // add_policies(permit_p);

        prohibit_p.add('h13000000, 'h130FFFFF);
       `uvm_info("addr_constrained_txn", $sformatf("prohibit_p: %p", prohibit_p), UVM_FULL)
        try_add_policy(prohibit_p);
        // add_policies(prohibit_p);

        // policy constraint value setup unchanged from previous example
        // this.policies.push_back(
        //     addr_constrained_txn::POLICIES::PARITY_ERR(1'b1)
        // );
        // addr_constrained_txn::POLICIES::addr_parity_err_policy  addr_parity_err_p = new();
        try_add_policy(addr_parity_err_p);
       `uvm_info("addr_constrained_txn", $sformatf("addr_parity_err_p: %p", addr_parity_err_p), UVM_FULL)

        // add_policies(this.policies);
    endfunction

   `uvm_object_utils_begin(addr_constrained_txn)
   `uvm_object_utils_end
endclass

testbench.sv

import uvm_pkg::*;

`include "uvm_macros.svh"
`include "addr_types.svh"
`include "policy_base.svh"
`include "addr_txn.svh"

      
module tb;
  initial begin
    addr_constrained_txn txn = new();
    txn.randomize();
    $display("addr=%0h", txn.addr);
    $display("parity=%0h", txn.parity);
    $display("parity_err=%0h", txn.parity_err);
  end
endmodule

Output:

UVM_INFO addr_txn.svh(37) @ 0: reporter [addr_policy] rng: '{super:'{super:'{}, use_uvm_seeding:'h1, m_leaf_name:"", m_inst_id:2556, m_inst_count:450, __m_uvm_status_container:uvm_pkg::uvm_status_container@395_1}, min:'h0, max:'hffff}
UVM_INFO addr_txn.svh(37) @ 0: reporter [addr_policy] rng: '{super:'{super:'{}, use_uvm_seeding:'h1, m_leaf_name:"", m_inst_id:2564, m_inst_count:451, __m_uvm_status_container:uvm_pkg::uvm_status_container@395_1}, min:'h10000000, max:'h1fffffff}
UVM_INFO addr_txn.svh(122) @ 0: reporter [addr_constrained_txn] permit_p: '{super:'{super:'{m_item:null}, ranges:'{$unit_0x4ccdf83b::addr_range@2556_1, $unit_0x4ccdf83b::addr_range@2564_2}}, selection:0}
UVM_INFO addr_txn.svh(37) @ 0: reporter [addr_policy] rng: '{super:'{super:'{}, use_uvm_seeding:'h1, m_leaf_name:"", m_inst_id:2568, m_inst_count:452, __m_uvm_status_container:uvm_pkg::uvm_status_container@395_1}, min:'h13000000, max:'h130fffff}
UVM_INFO addr_txn.svh(127) @ 0: reporter [addr_constrained_txn] prohibit_p: '{super:'{super:'{m_item:null}, ranges:'{$unit_0x4ccdf83b::addr_range@2568_2}}}
UVM_INFO addr_txn.svh(137) @ 0: reporter [addr_constrained_txn] addr_parity_err_p: '{super:'{m_item:null}, parity_err:'h0}
UVM_INFO policy_base.svh(116) @ 0: reporter [policy] adding policy  to addr_constrained_txn
UVM_INFO policy_base.svh(41) @ 0: reporter [policy::set_item()] policy <> applied to item <addr_constrained_txn>: addr_policy base
UVM_INFO policy_base.svh(116) @ 0: reporter [policy] adding policy  to addr_constrained_txn
UVM_INFO policy_base.svh(41) @ 0: reporter [policy::set_item()] policy <> applied to item <addr_constrained_txn>: addr_policy base
UVM_INFO policy_base.svh(116) @ 0: reporter [policy] adding policy  to addr_constrained_txn
UVM_INFO policy_base.svh(41) @ 0: reporter [policy::set_item()] policy <> applied to item <addr_constrained_txn>: addr_policy base
addr=0
parity=1
parity_err=0

Query: Looks like the constraint policy isnt getting applied while getting randomized. Am I missing something ?

Hello @dave_59 Any comments from your side. Have listed out the working code above.

  1. Is there any way to print the contents of the policies/handles contents of it as well ?

Please let me know. Thanks.

This is a lot of code for anyone to go over. It might help to explain what it results you’re expecting and how they differ from what you got.
You need to build a deep print method to print out the policy classes.

Hello @dave_59 Thanks for taking time and responding back. Let me break down into smaller piece.

  1. I have a the base class addr_txn which has lets say one of the variable addr to be randomized.
  2. And I have created three policy classes:
    • addr_policy [i.e. base policy] extended from policy_imp parameterized with addr_txn.
    • addr_permit_policy extended from addr_policy and added two constraint address range ('h00000000, 'h0000FFFF) and ('h10000000, 'h1FFFFFFF).
    • addr_prohibit_policy extended from addr_policy and added constraint to prohibit the addr to fall b/w ('h13000000, 'h130FFFFF) range.
  3. Using constraint policy class, created two policy class to add constraint to the main class addr_txn.
  4. But when I randomize I don’t see the constraint from the policy class addr_permit_policy and addr_prohibit_policy getting applied.

Expected Output: addr=16c5 [within the permitable range] based on randomization/seed etc.
Actual Output: addr=0

Basic Debug:

  1. Have set a default value of 1555 to the address in pre-randomize and that gets reflected in all the handles of the addr_txn. Also you can see the policy handles printeed in the pre_randomize prints.
  2. And once the randomization is done and if you see the prints in the post_randomize the addr values becomes 0’s.
  3. Somehow the policies aren’t getting applied when everything gets randomized.

Hello ! Think its mainly because of some odd parity constraint causing the issue. Though the tool didn’t through up any errors. Think figured the issues with help from friends.