I have a vendor-supplied BFM module instantiated deep in my hierarchy; let's call the path top.dut.u1.u2.bfm1
. The BFM's API is a little archaic and messy for our needs. I would like to write an "object" (class? interface? something else?) that will provide tasks with a simpler calling interface, and can call the tasks of the specific BFM that it has been "linked" with. It's this "linking" that I can't figure out.
I have a simple version defined as a module, that uses a `define to specify the path to the BFM, something along the lines of:
`define BFM top.dut.u1.u2.bfm1
module bfm_wrapper;
...
task read_burst(...);
...
`BFM.read_burst(...);
endtask;
...
endmodule
Obviously this isn't very reusable. How do I replace `BFM with something more portable or abstracted to the next higher level?
I'm a relative newbie with SystemVerilog, and I'm not even using UVM yet, but I'll take the plunge if there's something there that will help. Any help is appreciated.
[Update] A couple of restrictions that I didn't mention:
The final answer (first suggested by @toolic and @Greg, later by @dave_59) is to use bind
to dynamically put the wrapper where the vendor BFM can be found with "upwards name referencing" (specifically, by putting the wrapper inside of the vendor BFM). So my code above would look something like:
`define BFM top.dut.u1.u2.bfm1
module top;
...
// Instantiate my wrapper code inside of the vendor's BFM
bind `BFM bfm_wrapper my_bfm();
// BFM commands go here
initial begin
wait (`BFM.reset === 0) @(posedge `BFM.clk);
`BFM.my_bfm.my_read_burst(...);
...
end
endmodule
module bfm_wrapper;
...
task my_read_burst(...);
...
read_burst(...);
endtask;
...
endmodule
My apologies if there are any typos. My code didn't wind up looking exactly like this.
Note that I didn't completely get rid of the define
. That would probably require the more elegant techniques in @dave_59's papers. But I did at least move it out of the reusable part of the code, which is good enough for now.