To avoid a somewhat ugly use of e.g. uvm_hdl_force that is currently in the codebase, I tried being “clever” and using a hierarchical upwards reference from a bound interface.
In the application, the design contains interfaces of some module, M. Let’s suppose it looks like this:
module M (input clk_i);
logic my_state;
endmodule
I can define an interface like the following to be bound into the module. The idea is that M.my_state walks up the hierarchy to the first instance of M.
interface my_if (input clk_i);
function flip();
M.my_state = ~M.my_state;
endfunction
endinterface
I can then bind in the interface with something like this:
bind M my_if u_my_if(.*);
And everything seems to work: I get an instance of the interface in each of the instances of the module and can interact with each happily! Yippee!
In the actual application, M is the name of some primitive block that is used in some, but not all, of the duts in my testbenches. When I tried the trick above with a dut/testbench that doesn’t happen to use M, the elaboration stage fails. With Xcelium, I get errors about the broken hierarchical up-reference. My suspicion is that this is caused by trying to make sense of an implicit instance of my_if at the top of the hierarchy (where the up-reference obviously won’t work).
It occurred to me to try a hack with parameters:
interface my_if #(bit bound = 0) (input clk_i);
if (bound) begin
function flip();
M.my_state = ~M.my_state;
endfunction
end
endinterface
and then binding with
bind M my_if #(.bound(1)) u_my_if(.*);
My idea was that the conditional generate construct that wasn’t enabled wouldn’t be elaborated.
Unfortunately, I still get the same elaboration error (*E,CUVUNF): apparently, I’m not “turning elaboration off” as much as I’d hoped.
This leaves me with two questions:
- How could I implement something like this nicely, where an interface gets bound into every occurrence (zero or more) of some module and then interacts with that module’s internals?
- Why didn’t my hacks above work?
