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