How to pass a value from UVM to tb_top - value used to set virtual interfaces

Hi experts,

What I want to achieve:
I want to create variable number of streams in my testcase. In hw_top.sv file maximum number of stream interfaces are always created and connected to DUT.
In UVM classes, only needed number of streams are created. Thus number of uvm_config_StreamIf::set calls are needed.
I want to pass value containing number of created streams from UVM class (uvm_test_top) to tb_top (which controls interface assignements to virtual interface fields in UVM classes).

What I have currently:
My current approach can be summarized with following snippet:

// Inside of uvm_test_top:
rand unsigned int num_streams;

// File tb_top.sv:
initial begin
  int num_streams;  
  // uvm_config_get call was here but it didn't work
  // Currently I fixed this value to maximum and I am stuck with unread factory overrides for not created streams
  num_streams = 64;
  for (int i = 0; i < num_streams; ++i) begin
    set_stream_ctrl_if(i);
  end
end

initial begin
  run_tests();
end

function void set_stream_ctrl_if(int index);
  string name;
  name = $sformatf("*.tb.env_stream[%0d].agent.*", index);
  case (index)
    0  : uvm_config_StreamIf::set(null, name, "vif", hw_top.stream_if_0);
    1  : uvm_config_StreamIf::set(null, name, "vif", hw_top.stream_if_1);
    // The rest of interfaces + default
  endcase
endfunction

// File hw_top:
StreamIf stream_if_0  (.clk(clk), .rstn(rst_n));
StreamIf stream_if_1  (.clk(clk), .rstn(rst_n));
// and the rest of interfaces + DUT

What is the issue with current approach
I have an issue with execution in correct order. When using uvm_config_db#(bit)::get the read was before uvm_test_top written value to database. I tried to use uvm_config_db#(bit)::wait_modified but this makes build process fail - build process advances to creation of drivers and monitors before any interface is set to override virtual interface.
I also searched for ways to access uvm_test_top from tb_top. I only found information that it is not possible.

What I need help with
I would like to know if it is possible to put that in correct order.

  • Write value to database (from uvm_test_top),
  • Read that value in tb_top,
  • Call uvm_config_db#(bit)::set functions,
  • Build all following classes under uvm_test_top.

If there is another (better) approach to this situation, please let me know.

If this description is not clear, please tell me what needs more details - I will try to fix it.
Thank you for your help (in advance)

I recommend that in tb_top, you put all of the interface handles into the uvm_config_db() with unique names targeting uvm_test_top. In your test top, you select the desired interfaces and assign them into the appropriate agent configuration objects.

module tb_top();

initial begin
  uvm_config_db#(StreamIF)::set(null, "uvm_test_top", "StreamIF0", hw_top.stream_if_0);
  uvm_config_db#(StreamIF)::set(null, "uvm_test_top", "StreamIF1", hw_top.stream_if_1);
  run_tests();
end

endmodule
1 Like

@cgales, thank you for your idea. That would actually work. However, I would be left with unused factory overrides and some warnings in check phase (I use check_config_usage())

In the meantime I have came up with an idea that worked.
I would like to ask wheter you see any potential risks with that approach.
I think it is quite a clean way to do this but I am open to feedback

On the figure you can see:
A. Default order of things when I tried to use uvm_config_int::get
B. Tries to add a delay to initial block with interface overrides logic
C. My solution to the problem

You can’t use hierarchical access in a SystemVerilog package, so you would likely have an issue trying to call a testbench function from your UVM code.