How to connect virtual interface to virtual interface?

Hello,

We need to test our chip with different flash models, which are coded in verilog.
At the moment the test bench is in verilog and the script is used to select the flash model and put it to a wrapper.
The test bench connects the wrapper to the DUT. We need to recompile everything if the flash model is changed.
We would like to use uvm so that we do not need to recompile if we use different flash models.

Since I am a beginner to uvm, I started with a small uvm test bench with the DUT and 2 flash models.
Our idea is to put the 3 virtual interfaces (dut_flash_vif, flash1_vif, flash2_vif) in the agent. In the connect phase of the agent,
dut_flash_vif, flash1_vif, flash2_vif are connected to the flash interfaces of the DUT, flash1, flash2 verilog modules.
Furthermore, we want to connect dut_flash_vif to flash1_vif or flash2_vif based upon the flash model which is selected in the uvm test case.
In the following code we connect dut_flash_vif to flash1_vif by assigning the dut virtual interface pointer to the flash1 virtual interface pointer
(this.flash1_vif = this.dut_flash_vif). Unfortunately the connection from dut_flash_vif to flash1_vif is not working. Flash1 interface does not receive the signal toggling at the DUT flash inetrface.
Why does flash1_vif not get the signal changing from dut_flash_vif? How do we connect dut_flash_vif to flash1_vif?
Does someone have a better idea to select the flash verilog models in the uvm testbench?

Thanks.
Christine

The followings are some extraction from the codes.

module top
……….
  flash_if  flash1_if();
  flash_if  flash2_if();
  flash_if  dut_flash_if();
………..
  initial
  begin
    uvm_config_db#(virtual flash_if)::set(null, "*", "dut_flash_vif",  dut_flash_if);
    uvm_config_db#(virtual flash_if)::set(null, "*", "flash1_vif",   flash1_if);
    uvm_config_db#(virtual flash_if)::set(null, "*", "flash2_vif",   flash2_if);

     run_test();
  end
endmodel
-----------------------------------------------------------------------
package flash_pkg;
   ……………
   typedef enum {FALSH1, FLASH2} flash_t;
   …………
endpackage: flash_pkg

------------------------------------------
class test_sel_flash extends uvm_test;
  ……..
  flash_t  flash_cfg; 
 ………
function void build_phase(uvm_phase phase);
    flash_cfg = FLASH1;
    uvm_config_db #(flash_t)::set(this, "m_env.m_flash_agent", "flash_cfg", flash_cfg);
  endfunction : build_phase
………..
endclass: test_sel_flash

-----------------------------------------------------
class flash_agent extends uvm_agent; 
 ……….
  virtual flash_if dut_flash_vif;
  virtual flash_if flash1_vif;
  virtual flash_if flash2_vif;
  flash_t  flash_cfg; 
…….
  function void connect_phase(uvm_phase phase);

    // Get the interfaces from the configuration database,
    if ( !uvm_config_db#(virtual flash_if)::get(this, "", "dut_flash_vif", dut_flash_vif))
        `uvm_fatal(get_type_name(), "flash_agent's DUT Flash virtual interface not configured")

    if ( !uvm_config_db#(virtual flash_if)::get(this, "", "flash1_vif", flash1_vif))
        `uvm_fatal(get_type_name(), "flash_agent's  Flash 1 virtual interface not configured")

    if ( !uvm_config_db#(virtual flash_if)::get(this, "", "flash2_vif", flash2_vif))
        `uvm_fatal(get_type_name(), "flash_agent's  Flash2 virtual interface not configured")

// connect dut_falsh_vif to the selected flash vif
  if ( uvm_config_db#(flash_t)::get(this, "", "flash_cfg", flash_cfg)) begin
     case (flash_cfg)
**FLASH1  : this.flash1_vif  = this.dut_flash_vif;
       FLASH2  : this.flash2_vif  = this.dut_flash_vif;
**     endcase
  end
  else
    `uvm_fatal(get_type_name(), "flash type (flash_cfg) not configured")
……….

  endfunction : connect_phase

In reply to Christine Lin:

Hi Christine,

in such cases I’m using macros to specify which interface has to be used. You can pass the appropriate macro to the simulation command and the desired configuration in your testbench will be loaded and simulated.

If you need more details, please let me know.
Christoph

In reply to chr_sue:

Hi Christoph,

I am sorry that I do not understand what you mean by using macros. Could you please describe the solution in details?

In the connect phase of the agent, I have assigned the value to flash1_vif by uvm_config_db#()::get… (flash1_vif is connected to the verilog flash model). It seems that this the reason that the connection from dut_flash_vif to flash1_vif ( this.flash1_vif = this.dut_flash_vif;) does not work. In the vcs simulation, I can see the value of flash1_vif is top.flash1_if. Is this idea to assign dut.flash1_if to flash1_vif by uvm_config_db and then connect dut_flash_vif to flash1_vif feasible?

Some flash interface signals are bidirectional. If we use a driver to drive signals from dut_flash_vif to flash1_vif, we need to the refer to the output enable signal inside the DUT to control who should drive the bidirectional signals. Referring to the directional control signal is not a good idea. Is there any better idea to solve this problem?

Thanks.
Christine

In reply to Christine Lin:

Hi Christine,

no problem. I try to explain some more details.
I understood you have 2 different configurations for your DUT and UVM environment, flash1 and flash2.
But each configuration needs only 1 virtual interface, but they are different for each configuration. With macros you can control this situation. FLASH1 and FLASH2 are macros.

In the toplevel module you can do the following:

module top
……….
  flash_if  flash1_if();
  flash_if  flash2_if();

  `ifdef FLASH1
     flash_design DUT(flash1);
  `endif

  `ifdef FLASH2
     flash_design DUT(flash2);
  `endif
………..
  initial
  begin
    `ifdef FLASH1
      uvm_config_db#(virtual flash_if)::set(null, "*", "flash_vif",   flash1_if);
    `endif
    `ifdef FLASH2
       uvm_config_db#(virtual flash_if)::set(null, "*", "flash_vif",   flash2_if);
    `endif 
     run_test();
  end
endmodule

In the agent you’ll retrieve the interface passed to the config_db. The correct interface was put to the config_db from the toplevel module. We do not have to differentiate.

class flash_agent extends uvm_agent; 
 ………. 
  virtual flash_if vif;
  flash_t  flash_cfg; 
…….
  function void connect_phase(uvm_phase phase);
 
    // Get the interfaces from the configuration database,
    if ( !uvm_config_db#(virtual flash_if)::get(this, "", "flash_vif", vif))
        `uvm_error(get_type_name(), "flash_agent's DUT Flash virtual interface not configured")

From the command line of your simulator you can define which macro has to set. I’m not so familiar with VCS, but there should be a switch to set the specific macro you need. It should look like this

+define+FLASH1

for setting the macro FLASH1

Then the simulator executes your code specified inside ifdef FLASH1 - endif

Hope this makes it now clear to you.
If you have more questions please let me know.
You can also use my email christoph@christoph-suehnel.de

Christoph

In reply to chr_sue:
Hi Christoph,

Thank you for your reply. The Macros are compile-time, not run-time.
With your solution we need to recompile if we select different flashes.
The point is not to recompile. If each test case takes 10 minute for compile,
the compile time is 500 minutes in the regression for 50 test cases.

Unfortunately the flash models from the vendors are in verilog.
Is there a way that we can connect the DUT flash interface to the different flash models
via UVM so that we can have one compile and use uvm testcase to select different flash models?

Although there are UVM flash VIP’s on the market, we still need to check our design with the flash models from the vendor.

Christine

In reply to Christine Lin:

Hi Christine,

this was too fast with my idea.
You are right. Using macros requires a complete recompile of the code.
I’m a little bit astonished to see the long compile times you have.
I have never seen such long compile times for UVM code. In most cases it was between 30 sec and 1 min.
Could it be this comes from your RTL model?

But back to your initial question. What are the differences in your 3 flash interfaces?
Could you please give me a short explanation?

In reply to chr_sue:

Hi Christoph,

When the whole chip is in netlist, it takes many minutes to compile the whole design.
At the moment, we do not have uvm code in the testbench yet. We are doing experiment
to see what uvm can bring to improve our verification.

The 3 flash interfaces are dut_flash_if, flash1_if, flash2_if.
How can we dynamically connect dut_flash_if to flash1_if in test1,
connect dut_flash_if to flash2_if in test2…?

The flash data is bidirectional. Using multiplexer in the testbench needs to refer to
the direction control signals in the DUT or in the flash model and might give timing problem
for netlist simulation. We would like to avoid the multiplexer in the testbench if possible.

At the moment we did the following definition,
In the staic part of the testbench,
The DUT has a flash interface, dut_flash_if
The FLASH1 verilog model has a flash interface, falsh1_if.
The FLASH2 verilog model has a flash interface, flash2_if.

In the dynamic part,
I defined 3 virtual interface in the uvm agent, dut_flash_vif, flash1_vif, flash2_vif.

By using uvm_config_db, we connect dut_flash_vif to dut_flash_if, flash1_vif to falsh1_if, flash2_vif to flash2_if. How can we dynamically connect dut_flash_vif to flash1_vif in test1,
connect dut_flash_vif to flash2_vif in test2…?

Is the explanation of our requirement clear?

Christine

In reply to Christine Lin:

Hi Christine,

many thanks. I believe it becomes now more clear to me.
But as I said the compilation time is strongly influenced by the DUT compilation time.
The UVM compilation runs really fast.

But answering your question. The UVM testbench does not add delay time to the signal paths. It is independet on the level RTL or gates. For your requirement you need a multiplexing function. You can do this as you are proposing using a configuration object or you can simply use a parameter.
Both settings can be made from the test or from the commandline of your simulator. The UVM is providing a generic command line processor.

If you need a well-defined for your signals on the toplevel border you can use a clocking block.
But this adds a few limitations to you.

I hope this is answering your question.

In reply to Christine Lin:

One of the significant benefits of using UVM is that you can run all of your tests with different random seeds without re-compiling. When you run all of the tests, the DUT should be the same so that the coverage metrics can be merged and managed correctly.

I would recommend using separate compilations to different libraries, one for each DUT model. You can then run regressions against each compilation. I would not recommend changing DUT models in the UVM environment since this will cause merging issues when determining coverage.

In reply to cgales:
Hi Christoph,
Thank you for your reply.
All the tests we have now are direct tests. Changing random seeds probably does not influence the coverage.

Back to the UVM question, Is there any way to connect one virtual interface in the agent with 2 interfaces in the top module? Multiplexing io ports is not very nice.

class flash_agent extends uvm_agent;

virtual flash_if flash_vif;

endclass

module top

flash_if flash1_if();
flash_if flash2_if();
flash_if dut_flash_if();

endmodel

Can flash_vif in the agent be connected to dut_flash_if and flash1_if in test1 and
connected to dut_flash_if and flash2_if in test2?

In reply to Christine Lin:

Hi Christine,

if you are changing the structure of your testbench you might run in to tzrouble evaluating and merging your overall coverage numbers. This is independent of running directed or randomized tests. But I do not believe you are changing your UVM architecture.

In my eyes there is no need to pass all your interfaces to the agent.
You can simply pass the appropriate interface to the config_db and retrieve the right one from the config_db in the agent.
Appropriate means flash1 or flash2. This is possible because the config_db stores the interface under a certain name and you can use the same name for the different interfaces. This makes your life in the agent easy.
Christoph

I have a similar requirement in my TB that I need to dynamically connect one physical interface to one of the two physical interfaces in my TB top module.
I can see why assigning virtual interfaces in agent won’t work because VIF can point to any one of the physical interface at any time. Is there a way to solve this problem in run-time without using `ifdefs in TB top?