Constraint solver error using the config object of subsequence in the nested sequence and subsequence that inherited the base sequence

Hello, experts.

I tried to create a base sequence that included control knobs and constraints and inherited the base sequence to create various sequences, but there was a problem.

I got a constraint solver error and the error message is as follows during simulation running.

Error-[CNST-ICE] Constraint infeasible constraints error

As the solver has encountered a failure due to an infeasible set of 
constraints, the values printed during this solve cycle are invalid.
The solver will preserve original values.
...
Error-[CNST-NPE] Constraint null pointer error
~~~error path~~~
Accessing null pointer cfg.sim_line in constraints.
Please make sure variable cfg.sim_line is allocated.



However, the configuration of the subsequence seems to be normal.
Maybe it's related to when the construction solver works.
I wonder if there is a solution.

The example code is provided below.


``` verilog

class my_config extends uvm_object;
    `uvm_object_util(my_config)

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

    int sim_line;

endclass : my_config

class base_seq extends uvm_sequence #(my_item);
    `uvm_object_utils(base_seq)
 
    // control knobs
    rand bit [11:0] line_addr;

    // configuration handle
    my_config cfg;

    // constraints
    constraint line_addr_c {line_addr >=0; line_addr < cfg.sim_line;}
 
    function new(string name = "base_seq")
        super.new(name);
    endfunction : new

    virtual task pre_start();
        if(!uvm_config_db #(my_config)::get(get_sequenceser(), get_sequence_path(), "cfg", cfg))
            `uvm_fatal(get_type_name(), "Failed to get configuration")
    endtask
endclass : base_seq
 
class nested_seq extends base_seq;
    `uvm_object_utils(nested_seq)
 
    sub_seq1 sub_seq1;
 
    virtual task body();
        `uvm_do_with(sub_seq1, {sub_seq1.line_addr == local::line_addr;}) // --> error occurs!
    endtask : body
endclass : nested_seq
 
class sub_seq1 extends base_seq;
    `uvm_object_utils(sub_seq1)
 
    virtual task body();
        // do something...
    endtask : body
endclass : sub_seq1

class my_test extends uvm_test;
    `uvm_component_utils(my_test)

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

    my_env env;
    my_config cfg;

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = my_env::type_id::create("env", this);
        cfg = my_config::type_id::create("cfg"); // I forgot to write this line, sorry...
        cfg.sim_line = 16; // I forgot to write this line, sorry...
        uvm_config_db #(my_config)::set(this, "env.agt*", "cfg", cfg);
    endfunction : build_phase

    virtual task run_phase(uvm_phase phase);
        nested_seq seq = nested_seq::type_id::create("seq");
        phase.raise_objection(this);
        seq.start(env.agt.sqr);
        phase.drop_objection(this);
    endtask : run_phase
endclass : my_test

```

In reply to YMNKY:

the problem is the my_config object is not created before it is being used in the constraint in the base class.
It is not a good practice to create object in the constructor. Please use some recommend place to create object for my_cfg class before it is being used in the base class.

I just captured the minimum required code to replicate the issue and fix it.
If you remove the my_cfg object create method in the base_seq constructor, you will get the error you faced and uncomment to get it fixed.

Here is the code below.
import uvm_pkg::*;
`include “uvm_macros.svh”
typedef class my_config;
class my_item extends uvm_sequence_item;
rand bit [31:0] dummy;
endclass : my_item

class base_seq extends uvm_sequence#(my_item);
// control knobs
rand bit [11:0] line_addr;

// configuration handle
my_config cfg;

`uvm_object_utils(base_seq)
// constraints
constraint line_addr_c {line_addr >=0; line_addr < cfg.sim_line;}

function new(string name = "base_seq");
    super.new(name);
    <font size=20>**_cfg = my_config::type_id::create("cfg", null);_**</font>
endfunction : new

virtual task pre_start();
    if(!uvm_config_db #(my_config)::get(get_sequencer(), get_sequence_path(), "cfg", cfg))
        `uvm_fatal(get_type_name(), "Failed to get configuration")
endtask

endclass : base_seq
class my_config extends uvm_object;
int sim_line = 16;
`uvm_object_utils(my_config)

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

endclass : my_config

module tb();
import uvm_pkg::*;
`include “uvm_macros.svh”

base_seq m_base;
my_config cfg;

initial begin
    uvm_config_db #(my_config)::set(null, "*", "cfg", cfg);
    m_base = base_seq::type_id::create("m_base", null);
    void'(m_base.randomize());
end

endmodule : tb

In reply to nhp:

Hi, nhp

Thank you for trying to solve the problem.

But I’m sorry, but there were some missing parts in the example code I posted.

The modified example code is below.

class my_config extends uvm_object;
    `uvm_object_util(my_config)
 
    function new(string name = "my_config")
        super.new(name);
    endfunction : new
 
    int sim_line; // modified
 
endclass : my_config

class my_test extends uvm_test;
    ...
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = my_env::type_id::create("env", this);
        cfg = my_config::type_id::create("cfg"); // I forgot to write this line, sorry...
        cfg.sim_line = 16; // I forgot to write this line, sorry...
        uvm_config_db #(my_config)::set(this, "env.agt*", "cfg", cfg);
    endfunction : build_phase
    ...
endclass : my_test

However, inspired by what you explained, I did some tests, and it seems that my constraint solver problem is related to when the config object was created.

Maybe your approach to the problem will be helpful.

So, I tried to add the line below.

function new(string name = “base_seq”);
super.new(name);
cfg = my_config::type_id::create(“cfg”, null);
endfunction : new

And I got an error below.

======================
Solver failed when solving following set of constraints
integer cfg.sim_line = 0;
rand bit[11:0] line_addr; // rand_mode = ON
constraint line_addr_c // (from this) (constraint_mode = ON) (~path~)
{
(line_addr < cfg.sim_line);
}
======================

I think for this error, sim_line = 16 setting was not passed to subsequence.

Thanks.

In reply to YMNKY:

Note: Some non-recommended way of writing code however, the purpose is to display the results. Please don’t take this as reference code. concept here is, the my_cfg should be set and get before the constraint solver.

As I suspected earlier, you need to get the my_cfg instance before constraint solver starts.

function new(string name = "base_seq");
    super.new(name);
    //cfg = my_config::type_id::create("cfg", null);

if(!uvm_config_db #(my_config)::get(get_sequencer(), get_sequence_path(), “cfg”, cfg))
`uvm_fatal(get_type_name(), “Failed to get configuration”)

endfunction : new

I put these lines into constructor from the pre_start in base_seq and it works for me.

In the build_phase of the test, I changed the sim_line = 20 different value from the default declared in my_config and I can get that value in base_seq.

virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    cfg = my_config::type_id::create("cfg", null);
    cfg.sim_line = 20;
    uvm_config_db#(my_config)::set(null, "*", "cfg", cfg);
endfunction : build_phase

Complete code:

import uvm_pkg::*;
`include “uvm_macros.svh”
typedef class my_config;
class my_item extends uvm_sequence_item;
rand bit [31:0] dummy;
endclass : my_item

class base_seq extends uvm_sequence#(my_item);
// control knobs
rand bit [11:0] line_addr;

// configuration handle
my_config cfg;


`uvm_object_utils_begin(base_seq)
    `uvm_field_int(line_addr, UVM_DEFAULT)
    `uvm_field_object(cfg, UVM_DEFAULT)
`uvm_object_utils_end
// constraints
constraint line_addr_c {line_addr >=0; line_addr < cfg.sim_line;}

function new(string name = "base_seq");
    super.new(name);
    //cfg = my_config::type_id::create("cfg", null);
    if(!uvm_config_db #(my_config)::get(get_sequencer(), get_sequence_path(), "cfg", cfg))
        `uvm_fatal(get_type_name(), "Failed to get configuration")
endfunction : new

virtual task pre_body();
    super.pre_body();
    `uvm_info(get_type_name(), $sformatf("Executing pre_body"), UVM_MEDIUM)
endtask : pre_body

endclass : base_seq
class my_config extends uvm_object;
int sim_line = 16;
uvm_object_utils_begin(my_config) uvm_field_int(sim_line, UVM_DEFAULT)
`uvm_object_utils_end

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

endclass : my_config

class my_test extends uvm_test;
base_seq m_base;
my_config cfg;
`uvm_component_utils(my_test)

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

virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    cfg = my_config::type_id::create("cfg", null);
    cfg.sim_line = 20;
    uvm_config_db#(my_config)::set(null, "*", "cfg", cfg);
endfunction : build_phase

task run_phase(uvm_phase phase);
    m_base = base_seq::type_id::create("m_base", null);
    for (int i = 0 ; i < 10 ; i++) begin
        void'(m_base.randomize());
        `uvm_info(get_type_name(), $sformatf("m_base transactions: %0s",m_base.sprint()), UVM_MEDIUM)
    end
endtask : run_phase

endclass : my_test
module tb();
import uvm_pkg::*;
`include “uvm_macros.svh”

initial begin
    //uvm_config_db #(my_config)::set(null, "*", "cfg", cfg);
    run_test("my_test");
end

endmodule : tb

In reply to nhp:

Thanks for your effort.

As your code, I modified below, and it worked properly.


class base_seq extends uvm_sequence #(my_item);
    ...
    function new(string name = "base_seq");
        super.new(name);
        //cfg = my_config::type_id::create("cfg", null);
        if(!uvm_config_db #(my_config)::get(get_sequencer(), get_sequence_path(), "cfg", cfg))
            `uvm_fatal(get_type_name(), "Failed to get configuration")
    endfunction : new
    ...
endclass : base_seq

class my_test extends uvm_test;
    ...
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = my_env::type_id::create("env", this);
        cfg = my_config::type_id::create("cfg");
        cfg.sim_line = 16;
        //uvm_config_db #(my_config)::set(this, "env.agt*", "cfg", cfg); --> error occurs!
        uvm_config_db #(my_config)::set(null, "*", "cfg", cfg); // this works OK!
    endfunction : build_phase
    ...
endclass : my_test