Setting array of interfaces to UVM config database

Maybe I’m being a jerk about this, but I’m curious enough to find out if what I had tried to do should have been legal and valid.

In my top-level module, I have a parameterized design, and an array of interfaces that depend on one of those parameters. I tried to set the interfaces in the config database as virtual interfaces using the following initial block in the top module:

string if_name; initial begin foreach(my_if[i]) begin $sformat(if_name, "IF[%0d]", i); uvm_config_db#(virtual my_if_type)::set(uvm_root::get(), "*", if_name, my_if[i]); end end

The simulator (I won’t name the vendor) barfed on it with an error about the index on the interface in the set method call. With their help, I was able to rewrite the code and work around the problem.

The simple question is… should the above have been OK, or did I truly do something illegal and invalid?

Hi Manning,

The problem is that an array of instances (module, interface, or program), is not the same as an aggregate data type you know as an array variable. An array variable is a collection of identically typed elements.

With an array variable, you know what arrayvar[1].somthing refers to is identical in definition to arrayvar[2].something, except that is located somewhere else memory. You can simply multiply the variable index value by some constant value to find the offset in memory where it is located.

An array of instances is just a shortcut for declaring a set of numbered instances. Because of Verilog generate and parameter overrides statements, with an array of instances, you don’t necessarily have a regular array. It’s possible what arrayinst[1].something refers to something completely different than what arrayinst[2].something does. So the compiler requires a constant index value to know what that particular something is. You typically use a generate/for_loop to do this.

Hi Manning,

I’m curious to know your work around solution & if its different than a generate statement as suggested by Dave.

Thanks,
-ND

In reply to ndalia:

Sorry for the very late response. Yes, the workaround is basically as described by Dave. I used a generate-for to instantiate initial blocks, each setting the config DB using the genvar as the index to an interface from the “array”.

Thanks, Dave, for that very clear explanation.

In reply to manning999:

Hey Manning,

Can you please paste the code here? I have run in to a similar problem and it will be really useful for me if I have your code snippet as a reference.

Thanks in advance,
– Kartik.

In reply to kartik:

What you need to do is pull the loop outside the initial block

for(genvar i=0;i<N;i++) begin : for_loop
initial begin : config
    string if_name;
    $sformat(if_name, "IF[%0d]", i);
    uvm_config_db#(virtual my_if_type)::set(uvm_root::get(), "*", if_name, my_if[i]);
  end : config
end : for_loop

@dave_59

I’m trying to understand SV race conditions better.

What guarantees that all the initial begin blocks with uvm_config_db::set run before the build_phase where I will be attempting to get those settings?

I had previously thought that it was because statements in the initial block are executed in order, and I had my run_test() after all my uvm_config_db::set. But if I have multiple parallel initial blocks, then how do I know my config initial blocks finish before the initial block with the call to run_test()?

Does something in UVM/Sv guarantee the order? Is it related to when blocking assignments are resolved?

This is an undocumented feature of the UVM. Just make sure your initial processes have no blocking statements before the uvm_config_db::set()

The reason this works is the UVM haphazardly inserts an unspecified number of #0 delays between the running of each phase.

1 Like