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?
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.
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”.
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?