Do Hierarchical References Follow the Declaration Scope or the Instance Scope

The following code is adapted from the UVM Cookbook’s BusFunctionalModels example. However, I’m 99% certain that it’s a SystemVerilog question.

The original example was along the lines of this (I’ve left out a few things):


module wb_bus_wrapper #(int WB_ID = 0);
  ...
  wishbone_bus_syscon_bfm wb_bfm(); // BFM instance
  ...
  interface wishbone_bus_bfm_if
    (input bit clk);
    ...
    task wb_write_cycle(wb_txn req_txn, bit [2:0] m_id);
      wb_bfm.wb_write_cycle(req_txn, m_id);
    endtask
    ...
  endinterface
  ...
  wishbone_bus_bfm_if wb_bus_bfm_if(.clk(wb_bfm.clk)); // Interface instance
  ...
endmodule

Unfortunately, the example doesn’t work out of the box. Questa (10.3d) complains that a “global interface [was] expected”.

To try to fix it, I pulled the interface declaration out of the module, even though I was sure that it would fail on the reference to wb_bfm.wb_write_cycle(). To my surprise, it didn’t. I tested it with two different sequences to two instances of wb_bus_wrapper, and each one got the correct sequence.

Should this work? This would mean that it’s evaluating the task within the scope of the interface instance, i.e., at runtime. That’s not what I expected.

If this is how it’s supposed to work, can you point me to the relevant part(s) of the SystemVerilog standard?

Thanks.
[Update: Link to original code]
https://verificationacademy.com/cookbook/download?file=/w/images/2/20/Uvm_Wb_mac_bfm_vif.tgz

In reply to jabreen:
All hierarchical references get resolved before run-time. Hierarchical names a searched first in the declaration scope defined in section 23.7, and then upward references use the instance scope defined in section 23.8 in the 1800-2012 LRM.

The original example should have found wb_bfm by looking in the enclosing declaration scope as defined in 23.7. That worked for me.
Your “fix” works because 23.8 has it looking in the instantiating parents scope.

A problem that I’ve seen with nested interface declarations is when you try to make a virtual interface out of it. The interface name is only visible to the enclosing scope. If you try to create a class n a package, the interface name is not visible.

In reply to dave_59:

In reply to jabreen:
A problem that I’ve seen with nested interface declarations is when you try to make a virtual interface out of it.

That may be the issue here (which I didn’t include in the snippets above). The error came from
a virtual interface reference when loading. Here is the full error from the original code:

# ** Fatal: (vsim-8451) ./wishbone/wb_bus_bfm_monitor.svh(56): Virtual interface resolution cannot find a matching instance for 'virtual wishbone_bus_bfm_if'.
# Global interface 'wishbone_bus_bfm_if' expected.
#  Non-matching nested interface from 'wb_bus_wrapper' has instances:
#       ./wishbone/wb_bus_wrapper.sv(157): wishbone_bus_bfm_if #() wb_bus_bfm_if()

(note that the original interface is also parameterized; that caused errors when I moved it, so I took it out (the parameter wasn’t used in the interface, so I’m not sure why it was there)).
So you’re saying that 23.8 allows tasks to be called with no compile-time indication of how the task is defined? That’s hard for me to get my head around, but I’m a relative newbie to Verilog and SV.

Also, I meant to give a link to the (original) code in my original post: https://verificationacademy.com/cookbook/download?file=/w/images/2/20/Uvm_Wb_mac_bfm_vif.tgz

In reply to jabreen:
Correct. Verilog treats function and task calls as hierarchical references and resolves them at elaboration (as the design is loaded into vsim).