Connecting a verification environment with a DUT is not a straight forward task for someone new to UVM and the purpose of this post is to give a quick tutorial on how to do it fast and correctly.
Let’s assume that we have a verification environment with two APB agents like in the picture below.
I’ll describe two methods:
- a quick way which can be used in most of the cases
- an advanced way suitable for scenarios in which you have two or more interfaces of the same type
The Quick Way
Step #1: declare the interfaces in the testbench
An interface is instantiated just as any other verilog module
1 | //instance of the APB interface used by APB agent agent0 |
Step #2: put the interfaces in the database
UVM comes with a database which you can use to save some information for future use. In our case, we can use it from the testbench to save the virtual interfaces and use them when the two APB agents are created.
1 | initial begin |
There are a few things you need to pay attention to here:
- the parameter of uvm_config_db is a virtual interface (virtual cfs_apb_if), NOT the interface (cfs_apb_if)
- the second argument of the set() function is the full name of the agent which must get the interface.
This full name is build by concatenating the names of components not the names of the “physical” SystemVerilog variables:1
apb_agent_0 = cfs_apb_agent::type_id::create("agent0", this);
In this example “apb_agent0” is the name of the “physical” SystemVerilog variable while “agent0” is the name of the component.
- The third argument of the set() function is like a “key” which the agents will use to get from the database the virtual interface. The same name must be used on Step#3
Step #3: get the interfaces from the database
The hardest part was already done by the set() function. All we have to do in the agent class is to get the virtual interface:
1 | class cfs_apb_agent extends uvm_component; |
The most important thing here is the third argument of the get() function – it must be the same key used by the set() function in Step#2.
That’s it!
The “Be Prepared For Future Changes” Way
The steps above work fine in most of the cases. But what if our design will change from two APB interfaces to four, or ten, or one hundred? Copy-Paste won’t do.
Let’s see how we can change the code to work with a generic number of interfaces.
Step #1: put in the database the number of APB interfaces
Ideally we should change only in one place the number of interfaces used by the DUT. One option is to have a define in the testbench which we can pass to the environment via the database.
1 | //define the number of APB interfaces |
Step #2: use “generate” block to declare interfaces and put them in the database
1 | generate |
You will probably need to do some extra work here for connecting each interface with the DUT, but in most of the cases you will probably get away with some assings based on idx.
Step #3: instantiate the APB agents based on the number of interfaces
1 | class cfs_env extends uvm_component; |
The are some things to pay attention to here:
- The key used to get the number of agents (e.g. “NUM_OF_APB_INTF”) must be the same as used at Step#1
- The name of the agent used in create() function must be the same as used in Step#2
Step #4: get the interfaces from the database
This step is identical with Step#3 from “The Quick Way”:
1 | class cfs_apb_agent extends uvm_component; |
Hope you found this information useful 🙂