Verification access to hierarchical signals without using hierarchical instance names

I’ll be teaching a Verification course this spring; while I’ve done a fair amount of verification over the years, I’m certainly not a Systemverilog expert. So, a how-to question. (Note that this is in pure Systemverilog; not UVM).

My example is a 2D-mesh routing fabric. The fabric is made of mesh stops; each mesh stop is made of FIFOs (among other things). The verification environment should have a tracker that looks through the entire design hierarchy, finds packets (let say just in the FIFOs) and prints them. Can I do this in any way that doesn’t require hard-coding the entire design hierarchy into the verification code?

I thought of using “bind my-fifo-module-name interf-type ports” to insert an interface object into every FIFO instance. The simulator would then find every FIFO instance for me, without my needing to know where they all are. But I can’t quite figure out how to make this work:

  • bind() doesn’t return a list of all the instances it created, so my Tracker cannot query all the interface instances to find packets.
  • the FIFOs are made of user code that doesn’t even know it has had an interface object inserted, so they won’t be able to go and register the interface objects with the Tracker.
  • if the Interface object had,e.g., an always_comb block inside, it could react to any change in the FIFO internal memory and notify the Tracker. But while an Interface can contain functions and tasks, it cannot contain an “always_comb” block.

So I’m kind of stuck. Any ideas?
Thanks,
/Joel

In reply to JoelG:
You use the “%m” format specifier to get the name of the instance you are bound into. You can build a list of instances your are bound into using an associative array. And interfaces have no such restrictions about always blocks.

module node;
  logic x;
endmodule

interface node_tracker;
  initial top.list[$sformatf("%m")]=node.nt;
  always @(node.x) $display("%m x has been set %d",node.x);
  function void setx();
    node.x = $urandom_range(1);
  endfunction
endinterface

module top;
  
  node n[5][5]();
  
  bind node node_tracker nt();
  
  virtual node_tracker list[string];
  
  initial begin
    #10
    foreach(list[s]) list[s].setx;
  end
endmodule

Here is a similar abstract/concrete class based approach taken from my DVCon 2012 paper

package tracker;
virtual class abstract;
  static abstract list[string];
  function new(string name);
    list[name] = this;
  endfunction
  pure virtual function void setx;
endclass
endpackage    

module node;
  logic x;
endmodule

module node_tracker;
  always @(node.x) $display("%m x has been set %d",node.x);
  class concrete extends tracker::abstract;
    function new(string name);
      super.new(name);
    endfunction
    function void setx();
      node.x = $urandom_range(1);
    endfunction
  endclass
  concrete c = new($sformatf("%m"));
endmodule

module top;
  import tracker::*;
  node n[5][5]();
  
  bind node node_tracker nt();
  
  initial begin
    foreach(abstract::list[s]) abstract::list[s].setx;
  end
  
endmodule

In reply to dave_59:

Thanks! I’ll try it out & update this forum item.
/Joel

Very nice! I’ve been playing with both solutions. They work fine :-), and it all makes sense now. I had not realized that an interface could have an “always” block inside of it. And the solution with a module that has a class object to report back to the verification environment is quite clever.

Thanks,
/Joel