Wednesday, 15 February 2017

Type overriding using UVM factory

Type overriding means that every time a component class type is created in the Testbench hierarchy, a substitute type i.e. derived class of the original component class, is created in its place, which applies to all the instances of that component type. In UVM, below are the methods by which we can override the class:
  • set_type_override_by_type
  • set_type_override_by_name

There's no difference in the final result either we override by type or name.

In below example, our purpose is to override driver class without making change in existing environment, so we created extended class which is extended from the original driver class.

Factory Code:


// When ~replace~ is 1, a previous override on ~original_type_name~ is replaced, otherwise a previous override, if any, remains intact. Yet to check.

Driver Code:


Extended driver Code:


In test, we can override the driver class by using "set_type_override_by_type" function.

Overriding in Test:


Output:

In test, we can override the driver class by using "set_type_override_by_name" function.

Overriding in Test:


Output:

Instance overriding using UVM factory

In instance overriding, as name indicates it substitutes only a particular instance of the component. In UVM, below are the methods by which we can override the instance of particular class:
  • set_inst_override_by_type
  • set_inst_override_by_name

There's no difference in the final result either we override by type or name.

In below example, our purpose is to override driver instance without making change in existing environment, so we created extended class which is extended from the original driver class.

Factory Code:


Driver Code:


Extended driver Code:


In test, we can override the driver class by using "set_inst_override_by_type" function.

Overriding in Test:


Output:


In test, we can override the driver class by using "set_inst_override_by_name" function.

Overriding in Test:


Output:




Tuesday, 14 February 2017

uvm_analysis_imp_decl macro

NEED for uvm_analysis_imp_decl macro

Sometimes in the same component we need to have two analysis "Imp" export. For example, In Scoreboard we want to compare the data coming from tx_monitor of Agent1 with the data coming from rx_monitor of Agent2. 

So to get the transactions from two different component we have to have two analysis "Imp" export in the same component. One which will be connected with tx_monitor and other which will be connected with rx_monitor. Here, for two analysis "Imp" export we can not define the same write() method for both. So UVM provides the solution by defining the macro `uvm_analysis_imp_decl macro. This macro allows to declare a specialized "imp"-style analysis export, by which its function write can be renamed as write_SUFFIX. 

Code:


Analysis Port, Export and "Imp" Export


Analysis port is a part of TLM. Just like other ports (uvm_put_port, uvm_get_port etc), analysis port is also extended from uvm_port_base class. 

-------------------------------------------------------------------------------------------------------------------------
Outline of TLM
TLM stands for Transaction Level Modelling, which means communication happens between different components by transferring transaction from one component to other [i.e. Sequencer to Driver, Monitor to Scoreboard etc].
In UVM, transaction is a class object, uvm_transaction extended from uvm_object. In simple words, you can also think of a packet class with fields like address, rd_wr, rd_en, wr_en, data etc.. 

Usually two components are connected, component which transmits the transaction has TLM port and component which receives the transaction has TLM export. And connection of this two components happen on any top level component. Each TLM connection has its defined method, which is called by Port and implemented by "Imp" Export.
-------------------------------------------------------------------------------------------------------------------------

Advantage of analysis port over other port is, analysis port can have any number of exports. Single analysis port can have 0, 1 or more than 1 number of exports at the time.

Analysis port requires an implementation of void function write() inside the analysis "Imp" export. Here we can see that, this is non-blocking as write() is a function. All the "Imp" exports connected with particular port has to implement write() method. So whenever port calls the write() function, all the write functions of the connected "Imp" exports will be executed.

If one analysis port is connected with 3 analysis exports then all 3 "Imp" exports should have write() method implemented. It is also okay if out of 3 any or all "Imp" exports have not implemented write() function, as it has been already implemented inside the analysis export class.

// If port has no export connected and still we call write method then which write() method would be called?

Difference between Analysis Export and Analysis "Imp" Export

Analysis "Imp" export is just like other analysis export which has implemented write() method inside it.

So analysis export is used for hierarchical connection, where the last component in the hierarchy (or the child component) has analysis "Imp" export with implemented write() function.

 

Analysis FIFO

Whenever write() function is getting called by port, it will be out of it in 0 time. So if we want to perform any time consuming operation on this received transaction we need some kind of buffer to store this received transaction, Analysis FIFO is that buffer.

Below is the snippet of analysis_fifo code inside UVM:


Last component in the hierarchy can be analysis export which can be connected with analysis fifo as fifo has already instance analysis "Imp" export. So when the export is connected with fifo then whenever port calls the write() method, analysis fifo will directly push the data the queue [as shown in above code].