Search code examples
classinterfacevirtualsystem-verilog

What causes 'interface resolution' compilation error when working with classes and virtual interfaces


I have declared in a design file following interfaces:

interface t_clocks;
   ckrs_t ClkRs125MHz_ix;
   ckrs_t ClkRs160MHz_ix;
   ckrs_t [3:0] ClkRsLink_ixb;
   ckrs_t ClkRsLinkx2_ixb;
   logic tdclk_sampling;

   modport producer(output ClkRs125MHz_ix,
            output ClkRs160MHz_ix,
            output ClkRsLink_ixb,
            output tdclk_sampling);

   modport consumer(input ClkRs125MHz_ix,
            input ClkRs160MHz_ix,
            input ClkRsLink_ixb,
            input tdclk_sampling);
endinterface // clocks

interface t_bst(input ckrs_t ClkRs_ix);
   tb_t mark;

   modport consumer(input ClkRs_ix, input mark);
   modport producer(output ClkRs_ix, output mark);
endinterface // t_bst

and in a package classes working with those interfaces:

package clspkg;
   import DefinitionsPkg::*;

class bst_generator;
   virtual t_bst.producer bst_master;
   ....
endclass // bst_generator

class clock_generator;
   virtual t_clocks.producer clk_tree;
   ....
endclass // clock_generator
endpackage // clspkg

I have glued all together in the testbench, using only clock_generator class from the package:

module tb_turn_emulator;
   import clspkg::*;

   t_clocks clk_tree();
   clock_generator cgen;

   // ???????????????
   //t_bst blast_radius(clk_tree.ClkRs160MHz_ix);

   default clocking cb @(posedge clk_tree.ClkRs160MHz_ix.clk); endclocking

   `TEST_SUITE begin

      `TEST_SUITE_SETUP begin
         cgen = new;
         cgen.clk_tree = clk_tree;
         cgen.run();
         ##10;
      end

....

endmodule

Now, when I try to compile such example, it FAILS with Virtual interface resolution cannot find a matching instance for 'virtual t_bst.producer'

It took me quite some time to find out, that if I instantiate as well the t_bst interface in the testbench module (uncommenting the t_bst line in the code above), everything goes smoothly, no compilation error and the testbench passes as usual.

I don't understand why the t_bst interface has to be instantiated as it is not at all used in code. It is true that I am importing the entire clspkg package, but nothing changes when I cherry pick by importing only the clock_generator by import clspkg::clock_generator.

What is wrong? I'm using Mentor Modelsim


Solution

  • First about using packages:

    Once you import one identifier or every identifier from a package in a design, the entire package exists in your design. That means all the static variables get allocated and initialized, as well as all the code for tasks and functions get generated. If static variable initializations call functions like class constructors, that implies executing procedural code without ever referencing it directly. (For those of you familiar with the factory design pattern and UVM, this is exactly how factory registration works.)

    Next about using interfaces:

    Like a module, an interface is a design element containing definitions of lots of different things. They can define variables, routines, import other packages, and have port connections. But nothing inside an interface exists or generates any code in a design until other design unit instantiates it, or in the case of a module, gets established as a top-level instance.

    Now about using virtual interfaces:

    Virtual interface are the primary method used to bridge the two kingdoms of the dynamic class based testbench world with the static instance based design world. Virtual interfaces behave much like a class type, except that there is no rule to have seen a definition of the interface before using it in your code. Hierarchical reference also have this capability of referencing something that does not exist at the point of compilation, but must be resolved later in the elaboration phase of compilation.

    To summarize, the compiler generates code for a virtual interface once it sees a reference to it whether you actually think you are using it or not. I would try to align packages with specific interfaces they are associated with.