Search code examples
system-veriloguvm

Calling a Task Hierarchically without Defines


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:

  1. I can't change or replace the vendor-supplied BFM. I'd prefer to not even wrap it (i.e., instantiate it in my wrapper).
  2. For reasons that I don't want to go into here, the BFM needs to be instantiated inside the DUT. Changing that would require more effort than I can invest right now.

Solution

  • 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.