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