Bind a module, with parameters not from the target location

I would like to bind a module, and pass a parameter from the module I declared the bind in, rather than them all coming from the module I am binding to.

module dut(input logic A, output logic B);
  assign B = A;
endmodule

module dut_verif_bind#(
  string IF_PATH = "a_string"
) (
  inout A,
  input B
);
  import uvm_pkg::*;

  AB_intf vif();
  assign vif.A = A;
  assign vif.B = B;
  initial begin
    uvm_config_db#(virtual AB_intf)::set(null, IF_PATH, "vif", vif);
  end
endmodule

The bind module would be bound from some higher level (a testbench, or another bind module) to dut. The fact that this can be another bind module is why I want to be able to bind the parameters like this.

module tb#(string IF_PATH = "uvm_test_top*") ();
  dut my_dut();
  bind my_dut dut_verif_bind#(.IF_PATH($sformatf("%s.dut*", IF_PATH))) dut_if_binds (.*);
endmodule

The above however, gives errors, because in the parameter binding of the bind module (#(.IF_PATH($sformatf("%s.dut*", IF_PATH)))) it is searching for the IF_PATH parameter in the module being bound to, not in the scope of the bind declaration. This is somewhat intuitive, though I hadn’t considered that issue, but it also seems like there should be a way around it.

For those wondering, this structure is something I am exploring because it should wind up making mid-level testbenches and tests nearly trivial to run if you have a unit and system test anyways. Just need a couple extra sequences and a couple more agent instantiations, but you don’t have to start over with declaring interfaces and tossing them in the database, and shouldn’t have to move them around the database at all.

I have become aware that this is not directly possible (Passing parameters to a bind entity - #3 by leela). I am hoping that someone has a workaround for a non-constant/derived parameter value in a bind module, whose value is determined in the context of where the bind statement itself exists. This doesn’t seem like it ought to be logically impossible. DefParam looked so promising (though $sprintf is not considered constant when it’s arguments are, so use concatenation) but it only works on scopes below the scope it is used in, not in scopes to the side.

I was trying to build an example to demonstrate this at (1) - EDA Playground before I ran into this (I had done a proof of concept, but missed doing nested binds and so missed this parameterization issue).

Limit the use of parameters to places that require constant expressions. In this case, there is no need to make IF_PATH a parameter; it can be a string variable.

module dut_verif_bind (
  inout A,
  input B
);
  string IF_PATH;
  import uvm_pkg::*;

  AB_intf vif();
  assign vif.A = A;
  assign vif.B = B;
  initial begin
    wait(IF_PATH !="")
    uvm_config_db#(virtual AB_intf)::set(null, IF_PATH, "vif", vif);
  end
endmodule
module tb#(string IF_PATH = "uvm_test_top*") ();
  dut my_dut();
  bind my_dut dut_verif_bind dut_if_binds (.*);
 initial
    my_dut.dut_verif_bind.IF_PATH = $sformatf("%s.dut*", IF_PATH);
endmodule

Do you have any recommendations for managing timing? As in, ensuring that IF_PATH is set before the uvm_config_db calls occur in all the various modules?

The wait statement used in my example does that.

oh, yeah, sorry about that.
I have this integrated to my demo package, and am quite happy with the result. Thank you for the help!