Hello !
- Took a basic partial constraint policy example from the dvcon paper and built upon it.
- 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 ?