Figure : UVM Class Hierarchy
The main OO building blocks of a UVM test bench are:
1) Transaction (also called a sequence item) - a high-level data set with standard methods
The main OO building blocks of a UVM test bench are:
1) Transaction (also called a sequence item) - a high-level data set with standard methods
2) Sequence – a constraint random stimulus generator that creates transaction
3) Sequencer – routes transactions to a driver using built-in arbitration algorithms
3) Sequencer – routes transactions to a driver using built-in arbitration algorithms
4) Driver – receives transactions from the sequencer and drives them to the DUT through methods in a virtual interface
5) Monitor- a passive entity that samples DUT signals through interface methods
6) Agent – encapsulates and configures a sequencer, driver, monitor and coverage collector
7) Environment – encapsulates and configures one or more agents and components such as scoreboard and coverage collector
Important Points :
1) VSIM run 0 command to execute all the construction phases and halt at the start of run_phase() (can be used in interactively debugging)
2) Each phase is a virtual method (a void function or a task) inherited from the uvm_component base class.
3) The build_phase() methods are executed sequentially in a top-down order and the connect_phase() methods are executed sequentially in a bottom-up order.
4) The UVM Factory –
· Creates objects in the UVM test bench
· Registers UVM component with the Factory
· Allow tests to ‘override’ the original object with one that has new functionality (The overriding class must be derived from the original class)
5) Viewing UVM test bench topology –
· Procedurally, call uvm_top.print_topology() to see the structure during end_of_elaboration_phase() after all components have been built.
· From Questa GUI- VSIM 1> run 0, VSIM 2> uvm pt
6) uvm_top is the instance name of uvm_root, uvm_test_top is the instance name of your test.
7) create() – creates a new object and returns a handle of the base uvm_object type.
Note: The create() method used by the clone() method is not the same create() method that is part of the factory and it returns a handle to uvm_object , which is the reason we need to call $cast() after each and every clone() method call.
8) The driver base class has a built-in port with the name ‘seq_item_port’, the UVM sequencer base class has a built-in export with the name ‘seq_item_export’.
9) TLM connections come in many flavors such as blocking v/s non-blocking. They can also have FIFOs to buffer transactions.
10) UVM driver has a virtual interface that is a pointer to the physical interface instance because a class (dynamic) can’t have a physical interface (static).
11) The sequencer sends handles to transactions, not the objects directly.
12) Why driver/sequencer should not send the values to scoreboard/coverage collector since they have the transaction item?
· A passive agent would not have driver/sequencer
· The actual inputs to the DUT might not be the same values visible in driver
· The interface methods between the test bench and DUT might contain timing that skews the input stimulus
· The interface methods between the test bench and DUT might contain functionality that modifies the values coming from the DUT
13) In the TLM analysis flow, the monitor still calls write(), just the one in a TLM analysis port class. The port then calls write() in the TLM analysis ( implementation) imp export, which finally calls the write() in the scoreboard. Note that the uvm_analysis_port actually has a queue of connections so you can connect 0 or more listeners.
14) The scoreboard/coverage collector should extend uvm_subscriber which includes the export.
15) TLM ports are constructed using new() and not through the factory. TLM ports are generic connectors that don’t have any design specific behavior, so their classes are never extended.
16) TLM exports implement the methods called by TLM port.
17) If we do not feed the export chain into a TLM FIFO, we would have to create write() method that put the data in storage such as System Verilog storage. When we connect the TLM FIFO to the export, it automatically takes the incoming data (transaction handle) and puts them into the FIFO. Now the evaluation just has to call fifo.get() to read the oldest data.
18) A system Verilog associative array can be used when expected results and DUT outputs can occurs in different orders.
19) There can’t be two write() methods for two analysis port write() calls. UVM provides “uvm_analysis_imp_decl(_xx)” macro to make unique names for multiple imp exports and write() methods. However, the UVM TLM FIFO has pre-defined storage and write() methods and it does not have this issue.
20) Disadvantages of using hierarchical name for configuration database in UVM factory-
· What if randomization changes number of components?
· What if you add a new configuration value?
· Store the configuration at top level which can be accessed when necessary by lower layer components.
21) get() , set() methods for factory configuration registration. Arguments – Context, Instance, field name value. Context and Instance completes the scope. ‘Null’ context is ‘uvm_top’
22) Most situation can be handles with two simple guidelines.
· When get() or set() are called from from within a class, set the context handle to ‘this’, and do not use the instance name. An exception is for class extended from uvm_sequence or uvm_sequence_item.
· When get() or set() are called from an module (typically the top DUT module ), set the context handle to ‘NULL’ and specify the instance name ‘uvm_test_top’.
23) Read controls from the object (class object) rather than calling get() multiple times. Reading and writing the UVM configuration database can be slow as it is a string based lookup at run time. Instead, read the values once and cache the values in a configuration object.
24) A common utility method added to the agent base is a get_sqr() method, returning the handle for the sequencer in the agent. The method can be added to the base class, even if the sequencer is not defined until later.
25) Two important problems with using a hierarchy path to the agent’s sequencer are:
· The writer of the test must know about the internal names in the testbench environment. This is counter to the goal of separating the stimulus from the test bench
· The hierarchy path is not “vertically scalable”. If this environment is later encapsulated in a higher-level environment, the hierarchy path will change.
26) get_sequencer() does not work always in virtual sequences as it requires that the start() method, used to start the sequence, be passed a handle to a sequencer. Since virtual sequences do not directly generates sequence_items, sometimes start() is called with the sequencer handle set to null. In this case, there is no sequencer. If your virtual sequence needs to access the configuration data base, use get_sequencer() to access the uvm_config_db.
27) set_drain_time () to delay the end of run phase.
28) A virtual sequence does not connect to a sequencer (in its body() method it connects the real sequence to sequencer). It starts sequences on their corresponding sequencer (AHB, SPI etc)
29) Virtual sequence is a sequence that creates and starts other sequences.
30) If the driver calls get() to fetch transaction N, the sequence is free to start transaction N+1 This allows the driver to start multiple transactions in parallel, also known as overlapping or pipelined transactions, get_next_item() does not allow this.
31) Front and back door register access-
· Front door sends transaction from/through the register model via the sequencer, driver and interface. The full protocol for the transfer is followed and it takes time, based on the requirements of the protocol.
· Back door ignores the rest of the environment and directly sets the values in the DUT with no time delay. A Verilog hierarchical path to the registers must be included as part of the model. A back-door access goes through the DPI (System Verilog Direct Procedural Interface) and is instantaneous.
32) UVM Register Model hierarchy –
· A UVM register model instantiates a register block
Ø A register block contains once or more register blocks, registers memories
- A register contains one or more fields
• A field contains one or more bits with access control
· Every register block contains a map
Ø The map contains the translation between addresses and register names
Ø Contains handle for an adapter, and a sequencer and also a method to assign values to these handles
Ø The handle for the map needs to be known, but if not set explicitly, it will be default_map
· A register model is not a class, it is an instance of a register block
· The register model has a copy of the registers, but not memories
33) To set up front door access for register model requires two extra classes to integrate with environment –
· Translator from internal Register model types to bus transaction and back
· Predictor to update the register model based on bus activity
34) The adapter is a user defined class derived from uvm_reg_adapter and implements pure virtual reg2bus() and bus2reg() translation methods.
35) Each UVM register field holds two copies of the actual DUT data
· Mirrored value- The value expected to be in DUT registers
Ø Updated whenever a read or write operation is performed
Ø Can be out of sync with the DUT if the DUT register is modified without going through the register model or via the address mapped interface
Ø Can use the register model mirror() method to resynchronize
· Desired value- The value to be written to the DUT by the register update() command
36) Predictor- The DUT registers may be modified by VIP or RTL that does not go through the UVM register model. To keep register model updated with the correct values, we need to create a predictor that watches the bus and sends commands to the register model. The predictor calls the register model methods to update values at the end of a bus transaction.
37) Before the register model is created and build method is called, any coverage needs to be turned on so that the register model is built with the appropriate coverage.
Please comment if any of the mentioned point on UVM is unclear.
----------------------------------------------Happy Learning--------------------------------------------
5) Monitor- a passive entity that samples DUT signals through interface methods
6) Agent – encapsulates and configures a sequencer, driver, monitor and coverage collector
7) Environment – encapsulates and configures one or more agents and components such as scoreboard and coverage collector
Important Points :
1) VSIM run 0 command to execute all the construction phases and halt at the start of run_phase() (can be used in interactively debugging)
2) Each phase is a virtual method (a void function or a task) inherited from the uvm_component base class.
3) The build_phase() methods are executed sequentially in a top-down order and the connect_phase() methods are executed sequentially in a bottom-up order.
4) The UVM Factory –
· Creates objects in the UVM test bench
· Registers UVM component with the Factory
· Allow tests to ‘override’ the original object with one that has new functionality (The overriding class must be derived from the original class)
5) Viewing UVM test bench topology –
· Procedurally, call uvm_top.print_topology() to see the structure during end_of_elaboration_phase() after all components have been built.
· From Questa GUI- VSIM 1> run 0, VSIM 2> uvm pt
6) uvm_top is the instance name of uvm_root, uvm_test_top is the instance name of your test.
7) create() – creates a new object and returns a handle of the base uvm_object type.
Note: The create() method used by the clone() method is not the same create() method that is part of the factory and it returns a handle to uvm_object , which is the reason we need to call $cast() after each and every clone() method call.
8) The driver base class has a built-in port with the name ‘seq_item_port’, the UVM sequencer base class has a built-in export with the name ‘seq_item_export’.
9) TLM connections come in many flavors such as blocking v/s non-blocking. They can also have FIFOs to buffer transactions.
10) UVM driver has a virtual interface that is a pointer to the physical interface instance because a class (dynamic) can’t have a physical interface (static).
11) The sequencer sends handles to transactions, not the objects directly.
12) Why driver/sequencer should not send the values to scoreboard/coverage collector since they have the transaction item?
· A passive agent would not have driver/sequencer
· The actual inputs to the DUT might not be the same values visible in driver
· The interface methods between the test bench and DUT might contain timing that skews the input stimulus
· The interface methods between the test bench and DUT might contain functionality that modifies the values coming from the DUT
13) In the TLM analysis flow, the monitor still calls write(), just the one in a TLM analysis port class. The port then calls write() in the TLM analysis ( implementation) imp export, which finally calls the write() in the scoreboard. Note that the uvm_analysis_port actually has a queue of connections so you can connect 0 or more listeners.
14) The scoreboard/coverage collector should extend uvm_subscriber which includes the export.
15) TLM ports are constructed using new() and not through the factory. TLM ports are generic connectors that don’t have any design specific behavior, so their classes are never extended.
16) TLM exports implement the methods called by TLM port.
17) If we do not feed the export chain into a TLM FIFO, we would have to create write() method that put the data in storage such as System Verilog storage. When we connect the TLM FIFO to the export, it automatically takes the incoming data (transaction handle) and puts them into the FIFO. Now the evaluation just has to call fifo.get() to read the oldest data.
18) A system Verilog associative array can be used when expected results and DUT outputs can occurs in different orders.
19) There can’t be two write() methods for two analysis port write() calls. UVM provides “uvm_analysis_imp_decl(_xx)” macro to make unique names for multiple imp exports and write() methods. However, the UVM TLM FIFO has pre-defined storage and write() methods and it does not have this issue.
20) Disadvantages of using hierarchical name for configuration database in UVM factory-
· What if randomization changes number of components?
· What if you add a new configuration value?
· Store the configuration at top level which can be accessed when necessary by lower layer components.
21) get() , set() methods for factory configuration registration. Arguments – Context, Instance, field name value. Context and Instance completes the scope. ‘Null’ context is ‘uvm_top’
22) Most situation can be handles with two simple guidelines.
· When get() or set() are called from from within a class, set the context handle to ‘this’, and do not use the instance name. An exception is for class extended from uvm_sequence or uvm_sequence_item.
· When get() or set() are called from an module (typically the top DUT module ), set the context handle to ‘NULL’ and specify the instance name ‘uvm_test_top’.
23) Read controls from the object (class object) rather than calling get() multiple times. Reading and writing the UVM configuration database can be slow as it is a string based lookup at run time. Instead, read the values once and cache the values in a configuration object.
24) A common utility method added to the agent base is a get_sqr() method, returning the handle for the sequencer in the agent. The method can be added to the base class, even if the sequencer is not defined until later.
25) Two important problems with using a hierarchy path to the agent’s sequencer are:
· The writer of the test must know about the internal names in the testbench environment. This is counter to the goal of separating the stimulus from the test bench
· The hierarchy path is not “vertically scalable”. If this environment is later encapsulated in a higher-level environment, the hierarchy path will change.
26) get_sequencer() does not work always in virtual sequences as it requires that the start() method, used to start the sequence, be passed a handle to a sequencer. Since virtual sequences do not directly generates sequence_items, sometimes start() is called with the sequencer handle set to null. In this case, there is no sequencer. If your virtual sequence needs to access the configuration data base, use get_sequencer() to access the uvm_config_db.
27) set_drain_time () to delay the end of run phase.
28) A virtual sequence does not connect to a sequencer (in its body() method it connects the real sequence to sequencer). It starts sequences on their corresponding sequencer (AHB, SPI etc)
29) Virtual sequence is a sequence that creates and starts other sequences.
30) If the driver calls get() to fetch transaction N, the sequence is free to start transaction N+1 This allows the driver to start multiple transactions in parallel, also known as overlapping or pipelined transactions, get_next_item() does not allow this.
31) Front and back door register access-
· Front door sends transaction from/through the register model via the sequencer, driver and interface. The full protocol for the transfer is followed and it takes time, based on the requirements of the protocol.
· Back door ignores the rest of the environment and directly sets the values in the DUT with no time delay. A Verilog hierarchical path to the registers must be included as part of the model. A back-door access goes through the DPI (System Verilog Direct Procedural Interface) and is instantaneous.
32) UVM Register Model hierarchy –
· A UVM register model instantiates a register block
Ø A register block contains once or more register blocks, registers memories
- A register contains one or more fields
• A field contains one or more bits with access control
· Every register block contains a map
Ø The map contains the translation between addresses and register names
Ø Contains handle for an adapter, and a sequencer and also a method to assign values to these handles
Ø The handle for the map needs to be known, but if not set explicitly, it will be default_map
· A register model is not a class, it is an instance of a register block
· The register model has a copy of the registers, but not memories
33) To set up front door access for register model requires two extra classes to integrate with environment –
· Translator from internal Register model types to bus transaction and back
· Predictor to update the register model based on bus activity
34) The adapter is a user defined class derived from uvm_reg_adapter and implements pure virtual reg2bus() and bus2reg() translation methods.
35) Each UVM register field holds two copies of the actual DUT data
· Mirrored value- The value expected to be in DUT registers
Ø Updated whenever a read or write operation is performed
Ø Can be out of sync with the DUT if the DUT register is modified without going through the register model or via the address mapped interface
Ø Can use the register model mirror() method to resynchronize
· Desired value- The value to be written to the DUT by the register update() command
36) Predictor- The DUT registers may be modified by VIP or RTL that does not go through the UVM register model. To keep register model updated with the correct values, we need to create a predictor that watches the bus and sends commands to the register model. The predictor calls the register model methods to update values at the end of a bus transaction.
37) Before the register model is created and build method is called, any coverage needs to be turned on so that the register model is built with the appropriate coverage.
Please comment if any of the mentioned point on UVM is unclear.
----------------------------------------------Happy Learning--------------------------------------------
0 Comments:
Post a Comment