Virtual interface resolution cannot find a matching instance of interface

Hi All,

While loading my design I get this error (I’m running Questa 6.3f):

Loading work.mem(fast)

** Fatal: (vsim-8451) env//driver.sv(71): Virtual interface resolution cannot find a matching instance of interface ‘mem_if’.

I’m using the method proposed in the Doulos examples to assign an interface to an virtual interface in a wrapper through set_config_object. I checked it 20 times and can’t see what’s wrong. What does the error exactly mean?

thanks a lot,

Pieter

Hi all,

I found the cause (below, from Supportnet Mentor) and the solution, adding the the same parameters to the virtual interface as to the instance and setting the flag: -permit_unmatched_virtual_intf.

kind regards,

Pieter

When a virtual interface is declared, it references an interface as its type. There must be a matching instance of the actual interface for the type to be fully defined. Prior to 6.3d, Questa would substitute a trivial type for the virtual interface type, if the true matching interface could not be found. After analyzing some user designs, it was found that automatically doing this substitution, while preventing an error, could lead to other fatal problems. Therefore, in 6.3d, this is now an error at elaboration time.

IEEE 1800-2005 Section 24.9 says: “A virtual interface is a variable that represents an interface instance.” This means that Questa must be able to resolve a virtual interface declaration with an instance of a matching actual interface in the design. It is possible to get this error if a virtual interface is declared but never used; such is in the above example if the class method ‘do_something’ was never called. This can occur if a virtual interface is declared in a base class that is re-used among multiple designs, but only some of the designs actually utilize the virtual interface.
For these cases, an option was added to vsim to avoid this error: –permit_unmatched_virtual_intf. It is important to note the LRM restriction: “A virtual interface must be initialized before it can be used; it has the value null before it is initialized. Attempting to use an uninitialized virtual interface shall result in a fatal run-time error.” Therefore, the above example will load successfully if –permit_umatched_virtual_intf is used, however a fatal run-time error would still occur if method ‘do_something’ was ever called.

Hi Pieter,

Thanks for sharing that. I hadn’t come across that particular issue with unconnected virtual interfaces before - the usual run-time error is an illegal dereference when the virtual interface is accessed!

The other question to ask is why do you have an unconnected virtual interface at all? The two most common mistakes I have seen are:

  1. Specifying a wrong path with set_config_object

  2. Forgetting to call `ovm_field_object for the virtual interface wrapper in the driver (so it doesn’t automatically pick up the configuration at the end of the build phase).

Regards,
Dave

Hi,

If I’m not mistaken, I don’t have an unconnected interface. During loading, Questa searches an instantiation of the interface that matches the virtual interface. As I had

mem_if #(data_t, address_t) m_mem_if

and the virtual interface

virtual mem_if m_mem_if

(without parameters) Questa couldn’t find an instance that matched the virtual interface. So I added the parameters to the virtual interface.

While trying to match the virtual interface (with parameters) during loading of the design, Questa couldn’t handle it (it said: can’t match interface none). So I had to turn that check off. Everything runs fine now.

kind regards,

Pieter

Hi Pieter,

Sorry, I hadn’t spotted that you were using parameterised virtual interfaces.

I did write some code using parameterised virtual interfaces that worked OK with Questa 6.2 but got broken in Questa 6.3. The -permit_unmatched_virtual_intf does indeed allow the assignment to the virtual interface (provided the parameters match) but I faced another problem. To be really useful, the classes that contained the virtual interface had to be parameterised too. This required coding along the lines of:

class if_wrapper #(int ADDR_WIDTH=8, int DATA_WIDTH=8) extends ovm_object;

typedef virtual my_if#(ADDR_WIDTH,DATA_WIDTH) my_if_t;

virtual my_if_t v_if;

function new (string name, virtual my_if_t if_);
  super.new(name);
  v_if = if_;
endfunction
...
endclass

This would build OK but give a run-time error when the interface was accessed since the virtual interface specialisation due to the typedef in the class was taken to be a different type from the actual interface specialisation.

I abandoned this approach since it was not supported by other simulators either.

Regards,
Dave

This would build OK but give a run-time error when the interface was accessed since the virtual interface specialisation due to the typedef in the class was taken to be a different type from the actual interface specialisation.

I’m surprised I haven’t hit the above bug (I hope you filed a bug report :)), but I’ve been using parameterized interfaces quite a bit and the working approach I use is to make the class parametric on the interface type:

class if_wrapper #(type my_if_t  = int) extends ovm_object;
   my_if_t v_if;
   [..]
endclass;

Foo_intf #(.BAR(10),.GAR(11)) intf;

if_wrapper #(virtual Foo #(.BAR(10),.GAR(11))) wrap = new("intf",intf);

This seems to be a very good practice in general since there is no OOP properties for interfaces. This lets all the drivers/monitors use any interface that is member name compatible and thus provides something kind of like polymorphism for interfaces.

In one case I have a family of about a dozen name compatible interfaces with slightly different properties (like bit widths/etc) that can be used interchangeably with a generic family of driver/monitors.

I’ve also had a few cases where a generic component might take two interfaces in but, in a specific test one is not used and is just assigned to null. This is where the limitation that was originally quoted becomes annoying, and seemingly unnecessary.

Hi jgg,

Thanks for sharing your approach - it does seem to work OK for my examples too with Questa 6.3f :)

The crucial step seems to be in making the wrapper parameter a virtual interface and then using that “as is” within the wrapper (rather than passing simple parameter types and using them to define a virtual interface within the wrapper). e.g.

class if_wrapper #(type my_chip_if = int) extends ovm_object;
   //parameter my_chip_if must be passed as virtual
 
   my_chip_if if1;  //simple variable declaration not virtual intf

   function new(string name,my_chip_if if_);  //if_ not declared as virtual intf
      super.new(name);
      if1 = if_;      
   endfunction : new
   
endclass : if_wrapper

In top module:

chip_if#(8,8) dut_if();
  chip dut ( .dut_if );

  //parameter must be passed as virtual intf
  if_wrapper #(virtual chip_if#(8,8)) if_wr = new("if_wr",dut_if);

Unfortunately, the SystemVerilog preprocessor (svpp) in IUS (6.20-s005) doesn’t seem to be able to cope with a virtual interface parameter so this approach can only be used at present with Questa :(

Regards,
Dave

The crucial step seems to be in making the wrapper parameter a virtual interface and then using that “as is” within the wrapper (rather than passing simple parameter types and using them to define a virtual interface within the wrapper). e.g.

Yes, without the virtual keyword an interface name is not a type. It is in the same category of not-type, not-variable ‘something else’ that modules, modports, clocking blocks and interfaces fall in.

That is one of my big hates toward SV, there are too many different things. IMHO, modules, interfaces, clocking block/etc/etc all should have been rationalized into an object model, instead of keeping them as a separate ‘magic’ concept. Modern high level language design has been moving in a direction that magic concepts are bad for a long time.

As we’ve seen in several threads lately, trying to mix the structure world of interfaces and modules with the dynamic class world is a huge PITA in anything but the most simple of cases.

Unfortunately, the SystemVerilog preprocessor (svpp) in IUS (6.20-s005) doesn’t seem to be able to cope with a virtual interface parameter so this approach can only be used at present with Questa :(

This reminds me a lot of the early C++ days where compiler writers tried hard to not make a full meta-programming environment in the compiler and it never worked right. It took a long time before C++ compilers were actually expanding and evaluating template code with the full generality of the language. As you observed even things that should work in Questa do not. I’ve found numerous cases where something that should be statically evaluated based the template parameter does not work, ie something like:

bit [$size(ifi.foo)-1:0] bar;

Bails even though it is statically defined.

At least for C++ the preprocessor approach to templates ended up being doomed as it was never able to fully cope with the generality. The pre-processor would have been as complex as the compiler front end.

That is one of my big hates toward SV, there are too many different things. IMHO, modules, interfaces, clocking block/etc/etc all should have been rationalized into an object model, instead of keeping them as a separate ‘magic’ concept. Modern high level language design has been moving in a direction that magic concepts are bad for a long time.

This is one of the major reasons I’ve been on my crusade to get people to stop using virtual interfaces and use abstract classes instead. It’s also the reason we don’t use program and clocking blocks. There are too many features in the SV language that have been brought in from other languages that might have made sense in their native environment, but no longer have enough value to justify the added complexity they introduce.

Dave Rich

Hi Dave,

my crusade to get people to stop using virtual interfaces and use abstract classes instead.

Would you care to give us a few clues about how you would use abstract classes to connect drivers and monitors in an OVM environment to the module ports in the rest of the testbench? All of the examples I recall in AVM and OVM use virtual interfaces.

Thanks.
Regards
Dave

Would you care to give us a few clues about how you would use abstract classes to connect drivers and monitors in an OVM environment to the module ports in the rest of the testbench? All of the examples I recall in AVM and OVM use virtual interfaces.

Indeed, I know of no way to connect class members to ports, which is part of my complaint about ‘magic’. A signal/variable in a class is not the same thing as one in a module :( I’ve seen a technique where you place both the driver class and the UUT in a new module and then reference the driver class with a path name - but that is still challenging as there is alot more typing and boilerplate involved when compared with a virtual interface.

FWIW, I do use clocking blocks with my interfaces, but it is a PITA. Clocking blocks and interfaces don’t work well unless you dedicate the interface to be used only for test benches, and then you need a ‘driving’ and ‘sampling’ test bench interface with a corresponding reversal of clock block direction to avoid multiple driver issues - and of course these interface is not compatible with a synthesis interface (though, I think that is solvable by nesting interfaces, but proper inheritance would have been so much nicer).

It isn’t so much the complexity of the feature that bothers me, but the fact that many of the new features have an incredibly narrow ‘possible use’. Outside that you trip into weird things that make no sense as limitations. That is not a hallmark of a well designed general purpose language.

Program blocks are the same, it is a good idea to have a reactive region, but the concept should have been introduced as a decorator for thread spawning: ‘reactive always […]’ ‘reactive fork […] join’

Would you care to give us a few clues about how you would use abstract classes to connect drivers and monitors in an OVM environment to the module ports in the rest of the testbench? All of the examples I recall in AVM and OVM use virtual interfaces.

OK, here you go. This example demonstrates the following principals

  1. An abstract class is essentially an API defined using pure virtual methods that represents a contract between the user and implementor.
  2. The implementor extends the abstract class into a concrete class by providing the implementations for the methods that directly access the module/interface port/signals.
  3. The concrete class in defined inside a module/interface. Each instance of that module/interface in turn creates a unique class extension.
  4. Each extension is registered with the object factory. The driver either “knows” which factory object it needs, or the instance override can set which driver needs which instance.

[LEFT]I tried using set/get config objects instead of using the factory, but the factory was a little less code.

Dave

[/LEFT]

Hi Dave,

Thanks for that - it’s an interesting approach. I also like the fact that you can give an interface a TLM API without needing import/export functions through a modport.

On the negative side, there does seem to be a danger that functionality that belongs in the class-based environment could “slip” into the interface instead, limiting reuse. The other issue is that since modules and interfaces do not support inheritance, creating a set of SV interfaces with additional “interface methods” (in the Java/C++ sense) could be a lot of work - you would need to create a new abstract class and create each interface from scratch.

Regards,
Dave

Hi Dave,
Thanks for that - it’s an interesting approach. I also like the fact that you can give an interface a TLM API without needing import/export functions through a modport.

Even better, your driver can be designed to work without any SV interfaces at all, making it easier to cross SV/SC/C++ borders.

On the negative side, there does seem to be a danger that functionality that belongs in the class-based environment could “slip” into the interface instead, limiting reuse. The other issue is that since modules and interfaces do not support inheritance, creating a set of SV interfaces with additional “interface methods” (in the Java/C++ sense) could be a lot of work - you would need to create a new abstract class and create each interface from scratch.

There’s no need to define the class inside the interface. It just can’t be in a package where hierarchical references are not allowed. See the paper at the beginning of this thread and the example at the end of that thread.

Dave

but I’ve been using parameterized interfaces quite a bit and the working approach I use is to make the class parametric on the interface type:

[code]
class if_wrapper #(type my_if_t = int) extends ovm_object;
my_if_t v_if;
[…]
endclass;

Foo_intf #(.BAR(10),.GAR(11)) intf;

if_wrapper #(virtual Foo #(.BAR(10),.GAR(11))) wrap = new(“intf”,intf);

Hi I use parameterized interface, and make the class parametric on the interface type as your approach. But the ModelSim Additionally, If the ports and exports are declared by avm_*_port and avm_*_export, and connected them by connect function, of course, the ports and exports have been instanced, in run-time, ModelSim 6.3f said the port to export and the export to fifo export did not connected. I can not figure out why it happens. Thanks a lot! Best Regards! Hellen Gong

… but I’ve been using parameterized interfaces quite a bit and the working approach I use is to make the class parametric on the interface type:

[code]
class if_wrapper #(type my_if_t = int) extends ovm_object;
my_if_t v_if;
[…]
endclass;

Foo_intf #(.BAR(10),.GAR(11)) intf;

if_wrapper #(virtual Foo #(.BAR(10),.GAR(11))) wrap = new(“intf”,intf);

Hi I use parameterized interface, and make the class parametric on the interface type as your approach. But the ModelSim <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />6.3f gives run_time errors: Null instance dereference, the ports and exports are declared by tlm_*_if, and they are connected by assignment. Additionally, If the ports and exports are declared by avm_*_port and avm_*_export, and connected them by connect function, of course, the ports and exports have been instanced, in run-time, ModelSim 6.3f said the port to export and the export to fifo export did not connected. I can not figure out why it happens. Thanks a lot! Best Regards! Hellen Gong

Hi Hellen Gong,

It sounds like you have been using AVM 2.0 style port connections which are not compatible with AVM 3.0 port connections. (By the way, the AVM 3.0 port connections are the only kind of connections that are supported in the OVM)

You did not give enough information about the errors you are getting for me to help you. Try attaching a small code sample we can compile.

Dave Rich

In reply to dave_59:

I will admit to not reading the whole thread- but I got errors out of Questa for unconnected virtual interfaces that exist on agents I am not even instiating in my test. I have a compile scripts which compiles all my files, regardlessof the test. The block tests use a small subset of these agents.

I was then using custom compile scripts which only compiled files that were needed. This was a pain and unmanageable.

I addded the permit_unmatched_virtual_inf option; and now I can use my one comple script for my blocks tests in addition to my system test. Thanks.

Definitely seems like this should be the default-- especially for uninstantiated objects.

In reply to wpiman:

wpiman,

You might want to think about putting the code for your agents in separate packages. See Package/Organization | Verification Academy. You can compile all your packages all the time, but only the packages that get imported will be analyzed for this consistency.

The problem with virtual interfaces is that references via virtual interfaces treat the interface as if it were a class type. The compiler needs the type information in order to generate code around those references, and it doesn’t know without very expensive analysis that the code is unreachable. The switch says “I know what I’m doing” and you are one your own for any weird behaviors that come out of it.

In reply to dave_59:

Hey Dave, I was searching the forum for something else and hit upon this old post which touches on a topic about which I’ve been curious. Over the years I’ve heard mostly vague references to people recommending against using program and clocking blocks. I recently did a web search but could not find a single source article with pros and cons listed. I was hoping there would be a Cliff or Stu paper, but could not find one. Do you know if such a paper exists? or has there been a thread on this topic in one of the verification forums?

Thanks,
ericm