You are on page 1of 42




w w w.m e n t o r.c o m


Testbench Guide for OVM
learn the basics and details of OVM testbench architecture

UVM/OVM Documentation - Copyright (c) 2011 Mentor Graphics Corporation - PDF generated at: Fri, 08 Jul 2011 17:30:57 PST

Table of Contents
Ovm/Testbench/Overview Ovm/Testbench/Build Ovm/Testbench/Blocklevel Ovm/Testbench/IntegrationLevel Ovm/Agent OVM Phases OVM Factory 1 6 13 21 28 33 36

- This document is a snapshot of dynamic content from the Online Methodology Cookbook - Created from on Fri, 08 Jul 2011 10:30:58 PDT



You are reading the OVM version of this article. You can find the new UVM version at [[]]

How an OVM testbench differs from a traditional module based testbench
In Verilog or VHDL, a testbench consists of a hierarchy of modules containing testbench code that are connected to the design under test (DUT). The modules contain stimulus and response checking code which is loaded into simulator memory along with the DUT at the beginning of the simulation and is present for the duration of the simulation. Therefore, the classic Verilog testbench wrapped around a DUT consists of what are known as static objects. SystemVerilog builds on top of Verilog by adding abstract language constructs targetted at helping the verification process. One of the key additions to the language was the class. SystemVerilog classes allow Object Orientated Programming (OOP) techniques to be applied to testbenches. The OVM itself is a library of base classes which facilitate the creation of structured testbenches using code which is open source and can be run on any SystemVerilog IEEE 1800 simulator. Like classes in any other OOP language such as C++ and Java, SystemVerilog class definitions are templates for an object that is constructed in memory. Once created, that object persists in memory until it is de-referenced and garbage collected by an automatic background process. The class template defines the members of the class which can either be data variables or methods. In SystemVerilog, the methods can either be functions which are non-time consuming, or tasks which can consume time. Since a class object has to be constructed before it exists in memory the creation of a class hierarchy in a SystemVerilog testbench has to be initiated from a module since a module is a static object that is present at the beginning of the simulation. For the same reason, a class cannot contain a module. Classes are referred to as dynamic objects because they can come and go during the life time of a simulation.
// // Example to show how a class is constructed from within a static object (a module) // // // Example class that contains a message and some convenience methods // class example; string message; function void set_message(string ip_string); message = ip_string; endfunction: set_message function void print(); $display("%s", message); endfunction: print endclass: example // // Module that uses the class - class is constructed, used and dereferenced // in the initial block, after the simulation starts // module tb; example C; // Null handle after elaboration initial begin C = new(); // Handle points to C object in memory C.set_message("This ojbect has been created");

UVM/OVM Documentation - Copyright (c) 2011 Mentor Graphics Corporation -

Ovm/Testbench/Overview #10.testbench connections. There are two main collective component types used to enable reuse . initiating the construction process by building the next level down in the hierarchy and by initiating the stimulus by starting the main sequence.Copyright (c) 2011 Mentor Graphics Corporation . C = null. The top level module will also contain an initial block which will contain a call to the OVM run_test() method. The OVM testbench architecture is modular to facilitate the reuse of groups of verification components either in different projects (horizontal reuse) or at a higher level of integration in the same project (vertical reuse). OVM testbench Hierarchy OVM testbenches are built from classes derived from the ovm_component base class.mentor. The top level class in an OVM testbench is usually known as the test class and this class is responsible for configuring the testbench. and each test case is implemented by extending a test base class. stimulus is generated and then reports on the results of the simulation. UVM/OVM Documentation .com . This method starts the execution of the OVM phases. which controls the order in which the testbench is built. ovm_components which are used to construct a class based hierarchical testbench structure. C.print(). For a given verification environment. The process of connecting a DUT to an OVM class based testbench is described in the article on DUT.the env (short for environment) and the agent. the testbench hierararchy below the test class is reasonably consistent. object can be garbage collected end endmodule: tb 2 The OVM Package The OVM package contains a class library that comprises three main types of classes. ovm_objects which are used as data structures for configuration of the testbench and ovm_transactions which are used in stimulus generation and analysis. // C has been deferenced. The testbench hierarchy is determined by a series of 'has-a' class relationships. in other words which components contain which other components. An OVM testbench will always have a top level module which contains the DUT and the testbench connections to it.http://uvm.

UVM/OVM Documentation . used to pass information to the agent which affects what it does and how it is built and connected. It may also contain other fields which control whether other sub-component classes such as functional coverage monitors or scoreboards get built or not. • A Sequencer . often implementing an API layer for the driver. each of which have their own protocol. the driver and sequencer are not required. error injection.Copyright (c) 2011 Mentor Graphics Corporation . A SystemVerilog package  is used to gather all the classes associated with an agent together in one namespace. a slave version of the driver rather than a master version). Each agent should have a configuration . • A Monitor . Other classes that might be included in an agent package: • Functional coverage monitor . The configuration object will also contain other data members which will control which of the agents sub-components are collect protocol specific functional coverage information • Scoreboard . or active.e. The OVM agent collects together a group of ovm_components focused around a specific pin-level interface.The monitor observes pin level activity and converts its observations into sequence_items which are sent to components such as scoreboards which use them to analyse what is happening in the testbench.http://uvm. or support for a protocol variant) The agent configuration object contains an active bit which can be used to select whether the agent is passive . this will contain a reference to the virtual interface which the driver and the monitor use to access pin level signals.The driver is responsible for converting the data inside a series of sequence_items into pin level transactions.e. and it may also contain information that affects the behaviour of the agents components (e. • Configuration object .A container object.A driver that responds to bus events rather than creating them (i.Ovm/Testbench/Overview The Agent Most DUTs have a number of different signal interfaces.mentor.gif • A Driver .g.The role of the sequencer is to route sequence_items from a sequence where they are generated to/from a driver.usually of limited use • A responder . The contents of an agent package will usually include: • A Sequence_item -The agent will have one or more sequence items which are used to either define what pin level activity will be generated by the agent or to report on what pin level activity has been observed by the agent. 3 Active agent.i. The purpose of the agent is to provide a verification component which allows users to generate and monitor pin level transactions.Utility sequences likely to be of general use. • (API) Sequences .

A scoreboard will usually compare transactions from at least two agents. or env. it is generally used in conjunction with other components such as the .A predictor is a component that computes the response expected from the stimulus. A functional coverage monitor is usually specific to a DUT. the different classes associated with the env are organised into a SystemVerilog package. which will import the agent packages.The env will have a configuration object that enables the test writer to control which of the environments sub-components are built.A functional coverage monitor analysis component contains one or more covergroups which are used to gather functional coverage information relating to what has happened in a <span style="background-color: navy. Block Level env In a block level OVM testbench.Copyright (c) 2011 Mentor Graphics Corporation .A scoreboard is an analysis component that checks that the DUT is behaving correctly. color: white. These are then assigned to the envs agents using set_config_object.http://uvm. • Predictors . 4 UVM/OVM Documentation . • Scoreboards . • Functional Coverage Monitors . or around a collection of blocks at higher levels of integration. In addition to the agents the env will also contain some or all of the following types of components: • Configuration object . which is why it is usually present in the env. • Virtual Sequencers .mentor. Like the agent." />testbench during a test case. The diagram shows a block level testbench which consists of a series of tests which build an env which contains several analysis components and two agents. The env configuration object should also contain a handle for the configuration object for each of the agents that it contains. OVM scoreboards use analysis transactions from the monitors implemented inside agents. or env.A virtual sequencer is used in the stimulus generation process to allow a single sequence to control activity via several agents. the environment. is used to collect together the agents needed for the DUTs interfaces together. is a container component for grouping together sub-components orientated around a block.Ovm/Testbench/Overview The env The environment.

mentor. UVM/OVM Documentation .Copyright (c) 2011 Mentor Graphics Corporation . The block level envs provide all of the structures required to test each block. 5 The OVM testbench Build And Connection Process Before an OVM testbench can start to apply stimulus its component hierarchy has to be built and the connections between the verification components has to be made. and the configuration object for each sub-env is nested inside the configuration object for the env at the next level of hiearchy. but as a result of the integration process. not all the block level interfaces are exposed at the boundary and so some of the functionality of the block level envs will be . The integration level env then needs to be configured to make agents connected to internal interfaces passive. the diagram shows a first level of integration where two block level environments have been merged together to Integration level ovm hierarchy. block level and integration level OVM testbenches is described in the article on building OVM testbenches. vertical reuse can be achieved by reusing the envs used in each of the block level testbenches merged together into a higher level env. The process for configuring and building agents.gif test the peripheral file.http://uvm. The 'greyed out' components in the envs are components that are no longer used in the integration level envrionment. As an illustration. Further levels of integration can be accomodated by layering multiple integration level envs inside eachother. This configuration is done in the test.Ovm/Testbench/Overview Integration Level env When blocks are integrated to create a sub-system. or possibly even not to include an agent at all. The configuration object for the integration level contains the rest of the configuration objects nested inside it.

The build phase works top-down and so the process is repeated for the each successive level of the testbench hiearchy until the bottom of the hierarchical tree is reached. Finally the next level of hierarchy is built. This conditional construction affects the topology or hierarchical structure of the testbench. The connect phase works from the bottom to the top of the testbench hierarchy. the connect phase is used to ensure that all intra-component connections are made.Copyright (c) 2011 Mentor Graphics Corporation . After the build phase has completed. The OVM testbench is is activated when the run_test() method is called in an initial block in the top level test module. before the configuration object is used to guide the configuration and conditional construction of the next level of hierarchy.mentor. and it takes a string argument or a string passed in from the +OVM_TESTNAME plusarg that defines the test to be run and constructs it via the factory. The +OVM_TESTNAME takes precedence over a string argument passed into run_test().com . UVM/OVM Documentation . This approach to construction is referred to as deferred construction.  Then the OVM infrastructure starts the build phase by calling the test classes build method During the execution of the tests build phase.Ovm/Testbench/Build 6 Ovm/Testbench/Build You are reading the OVM version of this article. At the next level of hierarchy the configuration object prepared by the test is "got" and further configuration may take place. The next step is for the configuration objects to be put into the tests configuration table.http://uvm. Following the connect phase. the testbench component configuration objects are prepared and assignments to the testbench module interfaces are made to the virtual interface handles in the configuration objects. You can find the new UVM version at [[]] The first phase of an OVM testbench is the build phase. During this phase the ovm_component classes that make up the testbench hierarchy are constructed into objects. the rest of the OVM phases run to completion before control is passed back to the testbench module. The construction process works top-down with each level of the hierarchy being constructed before the next level is configured and constructed. This method is an OVM static method.

A detailed account of the build and connect processes for this example can be found in the Block Level Testbench Example article. one for its APB bus interface and one for its SPI interface. This example is an environment for an SPI master interface DUT and it contains two agents. This facility can be useful for changing or updating component behaviour or for extending a configuration object. Factory Overrides The OVM factory allows an OVM class to be substituted with another derived class at the point of construction.Copyright (c) 2011 Mentor Graphics Corporation . since this can be overloaded in test cases extending from the base test class.http://uvm. so it is recommended that a test base class is created which can be easily extended for each of the test cases. a block level verification environment will be referred to.mentor.Ovm/Testbench/Build 7 The Test Is The Starting Point For The Build Process The build process for an OVM testbench starts from the test class and works top-down. The factory override must be specified before the target object is constructed. so it is convenient to do it at the start of the build process. If the configuration of the sub-component is either complex or is likely to change then it is worth adding a function call to take care of the configuration. These configuration objects should be created in the test build method and configured according to the requirements of the test case. To help explain how the test build process works. usually the top-level env For a given design verification environment most of the work done in the build method will be the same for all the . The function of the tests build method is to: • • • • • Set up any factory overrides so that configuration objects or component objects are created as derived types Create and configure the configuration objects required by the various sub-components Assign any virtual interface handles put into configuration space by the testbench module Build up a nested env configuration object which is then set into configuration space Build the next level down in the testbench hierarchy. Sub-Component Configuration Objects Each collective component such as an agent or an env should have a configuration object which defines their structure and behaviour. `ifndef SPI_TEST_BASE `define SPI_TEST_BASE // // Class Description: // // class spi_test_base extends ovm_test. UVM/OVM Documentation . The test class build method is the first to be called during the build phase and what the test method sets up determines what gets built in an OVM testbench.

void configure_apb_agent(apb_agent_config cfg). ovm_component parent = null). void configure_env(spi_env_config cfg). //-----------------------------------------// Methods //-----------------------------------------// Standard OVM extern function extern function extern funciton extern funciton Methods: new(string name = "spi_test_base". // Create apb agent configuration object m_apb_cfg = apb_agent_config::type_id::create("m_apb_cfg").com .has_spi_scoreboard = = OVM_ACTIVE. // Call function to configure the env configure_env(m_env_cfg). void build(). create the env configuration // including any sub configurations and assigning virtural interfaces function void spi_test_base::build(). // Configuration objects spi_env_config m_env_cfg. // More to follow endfunction: build // // Convenience function to configure the env // // This can be overloaded by extensions to this base class function void spi_test_base::configure_env(spi_env_config cfg).has_scoreboard = endfunction // Build the env. 8 endclass: spi_test_base function spi_test_base::new(string name = "spi_test_base". cfg. cfg. // Create env configuration object m_env_cfg = spi_env_config::type_id::create("m_env_cfg"). cfg.http://uvm.Ovm/Testbench/Build // OVM Factory Registration Macro // `ovm_component_utils(spi_test_base) //-----------------------------------------// Data Members //-----------------------------------------//-----------------------------------------// Component Members //-----------------------------------------// The environment class spi_env m_env. apb_agent_config m_apb_cfg. cfg. endfunction: configure_apb_agent `endif // SPI_TEST_BASE UVM/OVM Documentation .has_functional_coverage = 1. parent). ovm_component parent = null). // Call function to configure the apb_agent configure_apb_agent(m_apb_cfg).has_reg_scoreboard = 0. spi_agent_config m_spi_cfg. cfg. endfunction: configure_apb_agent // // Convenience function to configure the apb agent // // This can be overloaded by extensions to this base class function void spi_test_base::configure_apb_agent(apb_agent_config cfg).Copyright (c) 2011 Mentor Graphics Corporation .mentor.has_functional_coverage = 0. cfg. super.

See the article on virtual interfaces for more information on this topic. Therefore. They can be passed individually. create the env configuration // including any sub configurations and assigning virtural interfaces function void spi_test_base::build(). only from their configuration object. Following the SPI block level envrionment example. each of the agents will have a separate configuration object. "APB_vif").mentor.Copyright (c) 2011 Mentor Graphics Corporation . the links to the signals on the top level I/O boundary of the DUT should have been made by connecting them to SystemVerilog interfaces and then a handle to each interface should have been assigned to a virtual interface handle which was wrapped inside a virtual interface container object. // Adding the apb virtual interface: m_apb_cfg.http://uvm. // Create apb agent configuration object m_apb_cfg = apb_agent_config::type_id::create("m_apb_cfg"). Then the env configuration object would be set into the configuration space. the configuration object for that level is unpacked and then its sub-configuration objects are re-configured (if necessary) and then passed to the relevant components using set_config_object(). these virtual interface references need to be assigned to the virtual interface handles inside the relevant component configuration objects. In the test build method. all of the configuration objects will be constructed and configured from the test case viewpoint. In order to keep components modular and reusable drivers and monitors should not get their virtual interface pointers directly from configuration space. UVM/OVM Documentation . an effective way to approach the passing of configuration objects through a testbench hierarchy is to nest the configuration objects inside each other in a way that reflects the hierarchy itself. In the test. Then. using the path argument in the set_config_object() method to control which components can access the objects. // More to follow endfunction: build Nesting Sub-Component Configuration Objects Configuration objects are passed to sub-components via the OVM component configuration space from the test. The following code shows how the the SPI testbench example uses the ovm_container to make virtual interface assignments to the virtual interface handle in the apb_agents configuration object: // The build method from before. The envs configuration object will have a handle for each of the agents configuration object. // Call function to configure the apb_agent configure_apb_agent(m_apb_cfg).com . The test class is the correct place to ensure that the virtual interfaces are assigned to the right verification components via their configuration objects. adding the apb agent virtual interface assignment // Build the env.APB = ovm_container #(virtual apb_if)::get_value_from_config(this. however a common requirement is that intermediate components also need to do some local configuration. individual components access the virtual interface handle inside their configuration object in order to drive or monitor DUT signals. then the agent configuration object handles inside the env configuration object will be assigned to the actual agent configuration objects. At each intermediate level in the testbench.Ovm/Testbench/Build 9 Assigning Virtual Interfaces From The Configuration Space Before the OVM run_test() method is called. // Create env configuration object m_env_cfg = spi_env_config::type_id::create("m_env_cfg"). // Call function to configure the env configure_env(m_env_cfg). to be retrieved when the env is built.

// Create env configuration object m_env_cfg = spi_env_config::type_id::create("m_env_cfg"). super. additional levels of nesting will be 10 For more complex environments. endfunction `endif // SPI_ENV_CONFIG // // Inside the spi_test_base class. UVM/OVM Documentation .mentor. // OVM Factory Registration Macro // `ovm_object_utils(spi_env_config) //-----------------------------------------// Data Members //-----------------------------------------// Whether env analysis components are used: bit has_functional_coverage = 1. //-----------------------------------------// Methods //-----------------------------------------// Standard OVM Methods: extern function new(string name = "spi_env_config").com . // // Configuration object for the spi_env: // `ifndef SPI_ENV_CONFIG `define SPI_ENV_CONFIG // // Class Description: // // class spi_env_config extends ovm_object. adding the apb agent virtual interface assignment // Build the env. the agent config handles are assigned: // // The build method from before. endclass: spi_env_config function spi_env_config::new(string name = "spi_env_config"). bit has_reg_scoreboard = 0. spi_agent_config m_spi_agent_cfg. create the env configuration // including any sub configurations and assigning virtural interfaces function void spi_test_base::build(). // Configurations for the sub_components apb_config m_apb_agent_cfg.Copyright (c) 2011 Mentor Graphics Corporation .http://uvm. bit has_spi_scoreboard = 1.

this). In the previous code snippet. // Repeated for the spi configuration object m_spi_cfg = spi_agent_config::type_id::create("m_spicfg"). The values of these arguments are used to create an entry in a linked list which the OVM uses to locate ovm_components in a pusedo hierarchy. This usually means building the top level env.SPI = ovm_container #(virtual spi_if)::get_value_from_config(this. endfunction: build 11 Building The Next Level Of Hierarchy The final stage of the test build process is to build the next level of testbench hierarchy using the OVM factory. configure_spi_agent(m_spi_cfg).m_spi_agent_cfg = m_spi_cfg. // Assign the apb_angent config handle inside the env_config: m_env_cfg. m_env_cfg.APB = ovm_container #(virtual apb_if)::get_value_from_config(this. // Adding the apb virtual interface: m_apb_cfg. // Create apb agent configuration object m_apb_cfg = apb_agent_config::type_id::create("m_apb_cfg").Name Argument For Factory Create Method Should Match Local Handle The create method takes two arguments. m_spi_cfg. UVM/OVM Documentation . // Call function to configure the apb_agent configure_apb_agent(m_apb_cfg). this list is used in the messaging and configuration mechanisms. the spi_env is created in the test using its declaration handle . but there could be more than one env or there could be a conditional build with a choice being made between several envs. m_env_cfg. one is a name string and the other is pointer to the parent ovm_component class object. the OVM path to the spi_env would be "spi_test. 0).mentor. "APB_vif").http://uvm. Using the same name as the handle makes it easier to cross reference paths and handles. after the end of the build process. "spi_env_config".Ovm/Testbench/Build // Call function to configure the env configure_env(m_env_cfg). This means that. the name argument string should be the same as the declaration handle of the component and the parent argument should be "this" so that it refers to the ovm_component in which the component is being created. // Now we are ready to build the spi_env: m_env = spi_env::type_id::create("m_env".Copyright (c) 2011 Mentor Graphics Corporation . By convention. // Now env config is complete set it into config space: set_config_object("*". Coding Convention .m_apb_agent_cfg = m_apb_cfg. "SPIvif").m_env".

mentor. Once the test class has been constructed. and then the build method of its child(ren) is called. its build method is called. the build methods of each of the child nodes through the testbench tree are called until the whole hierarchy has been constructed. and works from the bottom of the hierarchy tree to the top and its purpose is to make connections between TLM classes.http://uvm. inside an agent. the virtual interface assignment to a driver and the TLM connection between a driver and its sequencer can only be made if the agent is active.Ovm/Testbench/Build 12 Hierarchical Build Process The build phase in the OVM works top down.Copyright (c) 2011 Mentor Graphics Corporation . Configuration objects are used during the connection process since they make contain references to virtual interfaces or they may contain information that guides the connection process. For instance. the OVM testbench component hierarchy is in place and the individual components have been constructed and linked into the component hierarchy linked list. assign virtual interface pointers to their handles and to make any other assignments to resources such as virtual sequencer sub-sequencers. if an agent is configured to be passive. In turn. The Hierarchical Connection Process Once the build phase has completed. the build process for the agent omits the creation of the agents sequencer and driver since these are only required if the agent is . This deferred approach to construction means that each build method can affect what happens in the build process of components at lower levels in the testbench hierarchy. Examples The build process is best illustrated by looking at some examples to illustrate how different types of component hierarchy are built up: A block level testbench containing an agent An integration level testbench UVM/OVM Documentation . For instance. The connect phase follows the build phase.

PENABLE).Copyright (c) 2011 Mentor Graphics Corporation .mentor. . // SPI Interface intr_if INTR(). The structure of the overall OVM verification environment is as illustrated in the block diagram. In this case.PSEL[0]). import spi_test_lib_pkg::*.PRDATA). SPI and INTR (interrupt) virtual interfaces are put into the OVM top configuration space using the set_value_in_global_config() method in the ovm_container. Block level ovm hierarchy. . In the initial block of the test bench. . Then the run_test() method is called . .PADDR[4:0]). You can find the new UVM version at [[]] As an example of a block level test bench.PRESETN(PRESETn).v" import ovm_pkg::*.PWDATA(APB. we are going to consider a test bench built to verify a SPI Master DUT.Ovm/Testbench/Blocklevel 13 Ovm/Testbench/Blocklevel You are reading the OVM version of this article. // PCLK and PRESETn // logic PCLK. logic PRESETn. handles for the APB agent to handle bus transfers on its APB slave port.PADDR(APB. . // // Instantiate the interfaces: // apb_if APB(PCLK.PCLK(PCLK).gif The Test Bench Module The top level test bench module is used to encapsulate the SPI Master DUT and connect it to the apb_if and spi_if SystemVerilog interfaces. // APB interface spi_if SPI(). UVM/OVM Documentation .http://uvm. the OVM environment has two agents . and a SPI agent to handle SPI protocol transfers on its SPI port.this causes the specified test to be constructed and the processing of the OVM phases to start. We shall go through each layer of the test bench and describe how it is put together from the top down. There is also an initial block which generates a clock and a reset signal for the APB interface.PSEL(APB. .PRDATA(APB.PENABLE(APB. // Interrupt // DUT spi_top DUT( // APB Interface: .PWDATA). module top_tb. PRESETn). import ovm_container_pkg::*.com . `include "timescale.

miso) ). they are constructed.mosi). end PRESETn = 1.mentor. run_test().ss_pad_o(SPI. The following code is for the spi_test_base class: `ifndef SPI_TEST_BASE `define SPI_TEST_BASE // // Class Description: UVM/OVM Documentation .cs). . repeat(8) begin #10ns PCLK = ~PCLK. having first created and prepared all of the configuration objects that are going to be used by the environment. SPI). In SPI example.PREADY(APB.IRQ(INTR. // OVM initial block: // Virtual interface wrapping & run_test() initial begin ovm_container #(virtual apb_if)::set_value_in_global_config("APB_vif" . The build method in the spi_env is then responsible for passing on these sub-configurations. Before the configuration objects for the agents are assigned to their handles in the env configuration block. ovm_container #(virtual spi_if)::set_value_in_global_config("SPI_vif" .IRQ).Copyright (c) 2011 Mentor Graphics Corporation . . APB). $finish. PRESETn = 0. using the ovm_container get_value_from_config() method.miso_pad_i(SPI. INTR). and then they are configured. The configuration and build process is likely to be common to most test cases.mosi_pad_o(SPI.http://uvm. ovm_container #(virtual intr_if)::set_value_in_global_config("INTR_vif".Ovm/Testbench/Blocklevel . this allows the env configuration object to be used to pass all of the configuration objects to the .PWRITE(APB. . The APB agent may well be configured differently between test cases and so its configuration process has been split out into a separate virtual method in the base class.PWRITE).PREADY). end // // Clock and reset initial block: // initial begin PCLK = 0. forever begin #10ns PCLK = ~PCLK. // Interrupt output . the configuration object for the spi_env contains handles for the SPI and APB configuration objects. so it is usually good practice to create a test base class that can be extended to create specific tests. end end endmodule: top_tb 14 The Test The next phase in the OVM construction process is the build phase. have their virtual interfaces assigned. . For the SPI block level example this means building the spi_env component.PSLVERR(). // SPI signals .clk). This "Russian Doll" approach to nesting configurations is used since it is scalable for many levels of hierarchy. . this allows inheriting test classes to overload this method and configure the APB agent differently.sclk_pad_o(SPI.

m_env_cfg. null). //-----------------------------------------// Methods //-----------------------------------------extern virtual function void configure_apb_agent(apb_agent_config cfg). // OVM Factory Registration Macro // `ovm_component_utils(spi_test_base) //-----------------------------------------// Data Members //-----------------------------------------//-----------------------------------------// Component Members //-----------------------------------------// The environment class spi_env m_env. . m_env_cfg. cfg. // SPI is on select line 0 for address range 0-18h cfg.has_functional_coverage = 0. "INTR_vif").Keep reg_map a generic name for vertical reuse reasons spi_rm = new("reg_map". endfunction // Build the env. "SPI_vif").m_apb_agent_cfg = m_apb_cfg. cfg.http://uvm. cfg. set_config_object("*". m_apb_cfg = apb_agent_config::type_id::create("m_apb_cfg"). 0). // The SPI is not configured as such m_spi_cfg = spi_agent_config::type_id::create("m_spi_cfg"). // Register map spi_register_map spi_rm. configure_apb_agent(m_apb_cfg).has_functional_coverage = 0. endfunction: build 15 // // Convenience function to configure the apb agent // // This can be overloaded by extensions to this base class function void spi_test_base::configure_apb_agent(apb_agent_config cfg).m_spi_agent_cfg = m_spi_cfg.spi_rm = spi_rm. parent).APB = ovm_container #(virtual apb_if)::get_value_from_config(this. endclass: spi_test_base function spi_test_base::new(string name = "spi_test_base".Ovm/Testbench/Blocklevel // // class spi_test_base extends ovm_test. "APB_vif").has_scoreboard = 0.adapter"). "spi_env_config". // Override for register adapter: register_adapter_base::type_id::set_inst_override(apb_register_adapter::get_type(). spi_agent_config m_spi_cfg. ovm_component parent = null). this). = OVM_ACTIVE. m_spi_cfg.SPI = ovm_container #(virtual spi_if)::get_value_from_config(this.Copyright (c) 2011 Mentor Graphics Corporation . cfg.no_select_lines = 1.start_address[0] = 32'h0. // Configuration objects spi_env_config m_env_cfg.INTR = ovm_container #(virtual intr_if)::get_value_from_config(this. super.mentor. ovm_component parent = null). m_env = spi_env::type_id::create("m_env". m_apb_cfg. m_env_cfg. extern function void build(). create the env configuration // including any sub configurations and assigning virtural interfaces function void spi_test_base::build(). // Register map . apb_agent_config UVM/OVM Documentation . // Insert the interrupt virtual interface into the env_config: m_env_cfg. // Standard OVM Methods: extern function new(string name = "spi_test_base". m_env_cfg = spi_env_config::type_id::create("m_env_cfg"). "spi_bus.

parent). send_spi_char_seq spi_char_seq = send_spi_char_seq::type_id::create("spi_char_seq"). endtask: run `endif // SPI_TEST UVM/OVM Documentation .http://uvm. check_reset_seq reset_test_seq = check_reset_seq::type_id::create("rest_test_seq"). endfunction: build task spi_test::run.Ovm/Testbench/Blocklevel cfg. endfunction: configure_apb_agent `endif // SPI_TEST_BASE 16 To create a specific test case the spi_test_base class is extended.start(m_env.apb). All of the configuration process is carried out by the super. In the following (simplistic and to be updated) example. endfunction // Build the env. // OVM Factory Registration Macro // `ovm_component_utils(spi_test) //-----------------------------------------// Methods //-----------------------------------------// Standard OVM Methods: extern function new(string name = "spi_test". reset_test_seq.apb). and this allows the test writer to take advantage of the configuration and build process defined in the parent class and means that he only needs to add a run method call in the build method. ovm_component parent = null).Copyright (c) 2011 Mentor Graphics Corporation .build(). global_stop_request(). extern function void build(). super. the run method instantiates a virtual sequence and starts it on the virtual sequencer in the env. spi_char_seq. super. ovm_component parent = null).mentor. `ifndef SPI_TEST `define SPI_TEST // // Class Description: // // class spi_test extends spi_test_base.m_v_sqr. extern task run(). create the env configuration // including any sub configurations and assigning virtural interfaces function void spi_test::build().start(m_env.range[0] = 32'h18. endclass: spi_test function spi_test::new(string name = "spi_test".new(name. .m_v_sqr.

This will be used by sequences running on the virtual sequencer. // Standard OVM Methods: extern function new(string name = "spi_env_config"). a functional coverage monitor and a virtual sequencer. This class contains a number of . // Whether the various agents are used: bit has_apb_agent = 1. endfunction // // Function: get_config // // This method gets the my_config associated with component c. bit has_spi_scoreboard = 1. bit has_reg_scoreboard = 0. namely the SPI and APB agents. The contents of the spi_env_config class are as follows: `ifndef SPI_ENV_CONFIG `define SPI_ENV_CONFIG // // Class Description: // // class spi_env_config extends ovm_object.Ovm/Testbench/Blocklevel 17 The env The next level in the SPI OVM environment is the spi_env. In this case. // OVM Factory Registration Macro // `ovm_object_utils(spi_env_config) // Interrupt Virtual Interface .Copyright (c) 2011 Mentor Graphics Corporation . the spi_env configuration object also contains a virtual interface and a method for detecting an interrupt. bit has_spi_functional_coverage = 1. Which of these sub-components gets built is determined by variables in the spi_env configuration object. localparam string s_my_config_id = "spi_env_config". //-----------------------------------------// Methods //-----------------------------------------extern static function spi_env_config get_config( ovm_component c).mentor. bit has_spi_agent = 1. //-----------------------------------------// Data Members //-----------------------------------------// Whether env analysis components are used: bit has_functional_coverage = 0. localparam string s_my_config_type_error_id = "config type error". extern task wait_for_interrupt. // Whether the virtual sequencer is used: bit has_virtual_sequencer = 1. a scoreboard. localparam string s_no_config_id = "no config".new(name). // Configurations for the sub_components apb_agent_config m_apb_agent_cfg.used in the wait for interrupt task // virtual intr_if INTR. super. spi_agent_config m_spi_agent_cfg. // SPI Register model ovm_register_map spi_rm. extern function bit is_interrupt_cleared. endclass: spi_env_config function spi_env_config::new(string name = "spi_env_config"). We check for // the two kinds of error which may occur with this kind of UVM/OVM Documentation .http://uvm.

mentor. // OVM Factory Registration Macro // `ovm_component_utils(spi_env) //-----------------------------------------// Data Members //-----------------------------------------apb_agent m_apb_agent. end return t. `ovm_file .IRQ). OVM_NONE . UVM/OVM Documentation . if( !c. OVM_NONE .ovm_report_error( s_my_config_type_error_id . $psprintf("config %s associated with config %s is not of type my_config" . s_my_config_id ) . endfunction // This task is a convenience method for sequences waiting for the interrupt // signal task spi_env_config::wait_for_interrupt. `ovm_file . a pointer to the spi_env_config is retrieved from the tests configuration table using get_config(). endfunction: is_interrupt_cleared `endif // SPI_ENV_CONFIG 18 In this example. end if( !$cast( t . // function spi_env_config spi_env_config::get_config( ovm_component c ). else return 0. o . spi_env_config t. This gives the env the ultimate flexibility for reuse. s_my_config_id ) . there are build configuration field bits for each . ovm_object o.Ovm/Testbench/Blocklevel // operation. `ovm_line ). Then the build process tests the various has_<sub_component> fields in the configuration object to determine whether to build a sub-component. if(INTR. $psprintf("no config associated with %s" . there is an additional step which is to unpack the configuration objects for each of the agents from the envs configuration object and then to set the agent configuration objects in the envs configuration table after any local modification. the spi_env configuration object is again used to determine which TLM connections to make and which pointers to assign to the sequencer handles in the virtual sequencer. o ) ) begin c.get_config_object( s_my_config_id . endtask: wait_for_interrupt // Check that interrupt has cleared: function bit spi_env_config::is_interrupt_cleared.http://uvm. In the connect phase. `ovm_line ).IRQ == 0) return 1. During the spi_envs build phase. @(posedge INTR. o.ovm_report_error( s_no_config_id . `ifndef SPI_ENV `define SPI_ENV // // Class Description: // // class spi_env extends ovm_env.sprint() . return null. In the case of the APB and SPI agents. 0 ) ) begin c.Copyright (c) 2011 Mentor Graphics Corporation .

end if(m_cfg. ovm_component parent = null).has_virtual_sequencer) begin if(m_cfg.analysis_export). spi_virtual_sequencer m_v_sqr.http://uvm. end if(m_cfg. spi_scoreboard m_scoreboard.spi = m_spi_agent. //-----------------------------------------// Constraints //-----------------------------------------//-----------------------------------------// Methods //-----------------------------------------// Standard OVM extern function extern function extern function endclass:spi_env function spi_env::new(string name = "spi_env". end if(m_cfg.apb = m_apb_agent.m_apb_agent_cfg. endfunction function void spi_env::build().spi.connect(m_reg_cov_monitor.ap.spi_rm = m_cfg.connect(m_scoreboard.Copyright (c) 2011 Mentor Graphics Corporation . spi_env_config m_cfg.has_spi_scoreboard) begin m_apb_agent. parent). 19 UVM/OVM Documentation . void connect(). if(m_cfg. m_cfg = spi_env_config::get_config(this).connect(m_func_cov_monitor.has_functional_coverage) begin m_apb_agent.Ovm/Testbench/Blocklevel spi_agent m_spi_agent. void build().has_spi_functional_coverage) begin m_func_cov_monitor = spi_reg_functional_coverage::type_id::create("m_func_cov_monitor".ap. end if(m_cfg.has_spi_scoreboard) begin m_scoreboard = spi_scoreboard::type_id::create("m_scoreboard".analysis_export).analysis_export).ap. end if(m_cfg. end endfunction:build function void spi_env::connect(). this).new(name. end if(m_cfg. end endfunction: connect `endif // SPI_ENV Methods: new(string name = "spi_env". m_spi_agent.m_sequencer.has_functional_coverage) begin m_reg_cov_monitor = spi_register_coverage::type_id::create("m_reg_cov_monitor". end if(m_cfg. super. end if(m_cfg. this).has_apb_agent) begin set_config_object("m_apb_agent*". m_spi_agent = spi_agent::type_id::create("m_spi_agent".m_spi_agent_cfg. spi_register_coverage m_reg_cov_monitor. end end if(m_cfg.has_spi_agent) begin set_config_object("m_spi_agent*".apb.connect(m_scoreboard. this). if(m_cfg.analysis_export). ovm_component parent = null). "spi_agent_config".mentor.has_spi_agent) begin m_v_sqr. m_scoreboard. this).ap. m_apb_agent = apb_agent::type_id::create("m_apb_agent". m_cfg.has_apb_agent) begin .spi_rm. 0). m_cfg. spi_reg_functional_coverage m_func_cov_monitor. "apb_agent_config".has_virtual_sequencer) begin m_v_sqr = spi_virtual_sequencer::type_id::create("m_v_sqr". this). 0).m_sequencer.has_spi_functional_coverage) begin m_apb_agent. this).

Ovm/Testbench/Blocklevel 20 The Agents Since the OVM build process is top down.http://uvm. the SPI agent follows the same process. UVM/OVM Documentation .mentor. ( for source code example download visit us online at ).com . The components within the agents are at the bottom of the test bench hierarchy.mentor. so the build process terminates there.Copyright (c) 2011 Mentor Graphics Corporation . The article on the agent build process describes how the APB agent is configured and built. the SPI and APB agents are constructed next.

import pss_test_lib_pkg::*. The example takes the SPI block level example and integrates it with another block level verification environment for a GPIO DUT. We shall now go through the test bench and the build process from the top down. the top level test bench module is used to encapsulate the .Copyright (c) 2011 Mentor Graphics Corporation . which also includes an AHB agent to drive the exposed AHB bus interface. import ovm_pkg::*. The principles that are illustrated in the example are applicable to repeated rounds of vertical resue. starting with the top level test bench module. The stimulus needs to drive the AHB interface and register layering enables reuse of block level stimulus at the integration level. The main differences between this code and the block level test bench code are that there are more interfaces and that there is a need to bind to some internal signals to monitor the APB bus. // PCLK and PRESETn UVM/OVM Documentation . In this configuration. The environments from the block level are encapsulated by the pss_env. Top Level Test Bench Module As with the block level test bench example. import ovm_container_pkg::*.Ovm/Testbench/IntegrationLevel 21 Ovm/Testbench/IntegrationLevel You are reading the OVM version of this article. and so the APB agents are put into passive mode to monitor the APB traffic. the block level APB bus interfaces are no longer exposed. You can find the new UVM version at [[]] This test bench example is one that takes two block level verification environments and shows how they can be reused at a higher level of integration. The hardware for the two blocks has been integrated into a Peripheral Sub-System (PSS) which uses an AHB to APB bus bridge to interface with the APB interfaces on the SPI and GPIO blocks.http://uvm.mentor. connect interfaces to the DUT signal pins and then set the virtual interface containers up in configuration space before calling run_test(). The DUT is wrapped by a module which connects its I/O signals to the interfaces used in the OVM test bench. The internal signals are bound to the APB interface using the binder module: module top_tb.

logic HRESETn.uart_tx(UART_TX).http://uvm. end HRESETn = 1. // OVM initial block: // Virtual interface wrapping & run_test() initial begin ovm_container #(virtual apb_if)::set_value_in_global_config("APB_vif" . APB). ovm_container #(virtual serial_if)::set_value_in_global_config("UART_RX_vif" .ahb(AHB). .spi(SPI). GPI). ovm_container #(virtual serial_if)::set_value_in_global_config("UART_TX_vif" . .clk = HCLK. // Binder binder probe(). // // Instantiate the interfaces: // apb_if APB(HCLK. ovm_container #(virtual gpio_if)::set_value_in_global_config("GPI_vif" . INTR).com . gpio_if GPI(). AHB). ovm_container #(virtual icpit_if)::set_value_in_global_config("ICPIT_vif" .PCLK = HCLK. ICPIT). ovm_container #(virtual intr_if)::set_value_in_global_config("INTR_vif". icpit_if ICPIT().modem(MODEM)). // DUT Wrapper: pss_wrapper wrapper(.shared between passive agents ahb_if AHB(HCLK. MODEM).Ovm/Testbench/IntegrationLevel // logic HCLK. . // AHB interface spi_if SPI(). GPO). forever begin #10ns HCLK = ~HCLK. end end // Clock assignments: assign GPO. serial_if UART_RX(). end // // Clock and reset initial block: // initial begin HCLK = 0. ovm_container #(virtual ahb_if)::set_value_in_global_config("AHB_vif" . // SPI Interface intr_if INTR(). repeat(8) begin #10ns HCLK = ~HCLK.uart_rx(UART_RX). . HRESETn). UART_TX). HRESETn = 0. UART_RX). . . assign GPI. SPI).clk = HCLK. assign ICPIT.mentor. ovm_container #(virtual gpio_if)::set_value_in_global_config("GPOE_vif" .gpoe(GPOE). ovm_container #(virtual modem_if)::set_value_in_global_config("MODEM_vif" . . serial_if UART_TX(). // APB interface .icpit(ICPIT).gpi(GPI). // Interrupt gpio_if GPO(). GPOE). endmodule: top_tb 22 UVM/OVM Documentation .Copyright (c) 2011 Mentor Graphics Corporation .gpo(GPO). ovm_container #(virtual gpio_if)::set_value_in_global_config("GPO_vif" . assign GPOE. . gpio_if GPOE(). ovm_container #(virtual spi_if)::set_value_in_global_config("SPI_vif" . HRESETn). run_test(). modem_if MODEM().clk = HCLK.

gpio_env_config m_gpio_env_cfg. As can be seen from the example. extern virtual function void configure_apb_agent(apb_agent_config cfg.mentor. The pss_env is responsible for unnesting the spi_env and gpio_env configuration objects and setting them in its configuration table. apb_agent_config m_gpio_apb_agent_cfg. the sub-env configuration objects contain handles for their agent sub-component configuration objects. logic[31:0] range).http://uvm. logic[31:0] start_address. int index. gpio_agent_config m_GPO_agent_cfg. In turn. //uart_env_config m_uart_env_cfg. extern function void build().new( . spi_agent_config m_spi_agent_cfg. ovm_component parent = null). the integration level test should have the common build and configuration process captured in a base class that subsequent test cases can inherit from. // Register map pss_register_map pss_rm. //-----------------------------------------// Methods //-----------------------------------------//extern function void configure_apb_agent(apb_agent_config cfg). gpio_agent_config m_GPI_agent_cfg.Copyright (c) 2011 Mentor Graphics Corporation .Ovm/Testbench/IntegrationLevel 23 The Test Like the block level test. gpio_agent_config m_GPOE_agent_cfg. // OVM Factory Registration Macro // `ovm_component_utils(pss_test_base) //-----------------------------------------// Data Members //-----------------------------------------//-----------------------------------------// Component Members //-----------------------------------------// The environment class pss_env m_env. // Standard OVM Methods: extern function new(string name = "spi_test_base". ovm_component parent = null). // Configuration objects pss_env_config m_env_cfg. The pss test base class is as follows: `ifndef PSS_TEST_BASE `define PSS_TEST_BASE // // Class Description: // // class pss_test_base extends ovm_test. The configuration object for the pss_env contains handles for the configuration objects for the spi_env and the gpio_env. ahb_agent_config m_ahb_agent_cfg. extern task run(). parent). endclass: pss_test_base function pss_test_base::new(string name = "spi_test_base". there is more configuration to do and so the need becomes more compelling. spi_env_config m_spi_env_cfg. In turn the spi_env and the gpio_env put their agent configurations into their configuration table. apb_agent_config m_spi_apb_agent_cfg. super. making any local changes necessary. endfunction UVM/OVM Documentation .

// Only monitors m_gpio_env_cfg. m_gpio_env_cfg.m_spi_agent_cfg = m_spi_agent_cfg.GPIO = ovm_container #(virtual gpio_if)::get_value_from_config(this.has_apb_agent = 1.Ovm/Testbench/IntegrationLevel 24 // Build the env. configure_apb_agent(m_gpio_apb_agent_cfg.mentor.m_apb_agent_cfg = m_spi_apb_agent_cfg. m_gpio_apb_agent_cfg. m_gpio_env_cfg. configure_apb_agent(m_spi_apb_agent_cfg. // Register map . // GPI agent . this). "SPI_vif"). m_gpio_env_cfg. m_gpio_env_cfg. m_spi_apb_agent_cfg = apb_agent_config::type_id::create("m_spi_apb_agent_cfg"). 32'h124).Keep reg_map a generic name for vertical reuse reasons pss_rm = new("reg_map". "AHB_vif"). m_GPOE_agent_cfg.has_virtual_sequencer = 0. null). UVM/OVM Documentation .GPIO = ovm_container #(virtual gpio_if)::get_value_from_config(this. 0. m_gpio_env_cfg. 0). create the env configuration // including any sub configurations and assigning virtural interfaces function void pss_test_base::build(). // Add in interrupt line m_env_cfg.m_gpio_env_cfg = m_gpio_env_cfg. // Override for register adapters: register_adapter_base::type_id::set_inst_override(ahb_register_adapter::get_type().gpio_rm = pss_rm.has_AUX_agent = 0. "gpio_env_config". m_GPO_agent_cfg.has_in_scoreboard = 1. 1.pss_rm = . "APB_vif"). // GPIO Aux agent not present m_gpio_env_cfg.http://uvm. m_gpio_env_cfg.has_apb_agent = 1.adapter").ICPIT = ovm_container #(virtual icpit_if)::get_value_from_config(this. m_env_cfg. m_GPOE_agent_cfg. "GPOE_vif").active (default) m_GPI_agent_cfg = gpio_agent_config::type_id::create("m_GPI_agent_cfg").GPIO = ovm_container #(virtual gpio_if)::get_value_from_config(this. // GPIO env configuration: m_gpio_env_cfg = gpio_env_config::type_id::create("m_gpio_env_cfg"). m_gpio_env_cfg. logic[31:0] range).active = OVM_PASSIVE. "spi_bus.APB = ovm_container #(virtual apb_if)::get_value_from_config(this. set_config_object("*".spi_rm = pss_rm. cfg. "GPI_vif").has_reg_scoreboard = 0.m_ahb_agent_cfg = m_ahb_agent_cfg. "APB_vif"). 0). m_ahb_agent_cfg.APB = ovm_container #(virtual apb_if)::get_value_from_config(this. m_GPO_agent_cfg. m_spi_env_cfg. // SPI Sub-env configuration: m_spi_env_cfg = spi_env_config::type_id::create("m_spi_env_cfg"). m_env_cfg. m_gpio_env_cfg. // Only monitors m_gpio_env_cfg.has_out_scoreboard = 1. // Register coverage no longer valid // GPO agent m_GPO_agent_cfg = gpio_agent_config::type_id::create("m_GPO_agent_cfg"). m_spi_apb_agent_cfg. // SPI agent: m_spi_agent_cfg = spi_agent_config::type_id::create("m_spi_agent_cfg"). 32'h100. m_env = pss_env::type_id::create("m_env". set_config_object("*". m_spi_env_cfg.has_functional_coverage = 1. m_env_cfg.m_GPOE_agent_cfg = m_GPOE_agent_cfg.has_functional_coverage = 1.m_apb_agent_cfg = m_gpio_apb_agent_cfg. m_gpio_env_cfg. // AHB Agent m_ahb_agent_cfg = ahb_agent_config::type_id::create("m_ahb_agent_cfg"). "gpio_bus.AHB = ovm_container #(virtual ahb_if)::get_value_from_config(this. m_spi_env_cfg. m_GPI_agent_cfg.SPI = ovm_container #(virtual spi_if)::get_value_from_config(this. m_gpio_env_cfg.Copyright (c) 2011 Mentor Graphics Corporation . // GPOE agent m_GPOE_agent_cfg = gpio_agent_config::type_id::create("m_GPOE_agent_cfg").adapter"). // apb agent in the SPI env: m_spi_env_cfg. m_spi_env_cfg. 32'h0. m_gpio_env_cfg. m_spi_agent_cfg. m_env_cfg = pss_env_config::type_id::create("m_env_cfg"). 32'h18). 0).active = OVM_PASSIVE. "pss_env_config".m_GPO_agent_cfg = m_GPO_agent_cfg. "spi_env_config". logic[31:0] start_address. register_adapter_base::type_id::set_inst_override(ahb_register_adapter::get_type(). endfunction: build // // Convenience function to configure the apb agent // // This can be overloaded by extensions to this base class function void pss_test_base::configure_apb_agent(apb_agent_config cfg. "ICPIT_vif"). "GPO_vif"). set_config_object("*".active = OVM_PASSIVE.m_spi_env_cfg = m_spi_env_cfg. m_env_cfg. int index. // APB agent used m_gpio_apb_agent_cfg = apb_agent_config::type_id::create("m_gpio_apb_agent_cfg"). m_env_cfg.m_GPI_agent_cfg = m_GPI_agent_cfg.

start_address[0] = start_address.no_select_lines = 1. `ifndef PSS_TEST `define PSS_TEST // // Class Description: // // class pss_test extends pss_test_base. super. bridge_basic_rw_vseq t_seq = bridge_basic_rw_vseq::type_id::create("t_seq"). parent). super.apb_index = index.has_functional_coverage = 0. cfg.start(m_env.mentor. If there was non-default configuration to be . // OVM Factory Registration Macro // `ovm_component_utils(pss_test) //-----------------------------------------// Methods //-----------------------------------------// Standard OVM Methods: extern function new(string name = "pss_test".has_scoreboard = 0. endtask: run `endif // PSS_TEST UVM/OVM Documentation . a test case that extends this base class would populate its run method to define a virtual sequence that would be run on the virtual sequencer in the env. repeat(10) begin t_seq. cfg.range[0] = range. cfg.ahb).Ovm/Testbench/IntegrationLevel cfg. endfunction // Build the env. extern task run(). cfg. cfg. end global_stop_request().build().Copyright (c) 2011 Mentor Graphics Corporation . then this could be done by populating or overloading the build method or any of the configuration methods.. endclass: pss_test function pss_test::new(string name = "pss_test".m_vsqr. endtask: run `endif // SPI_TEST_BASE Again. extern function void build().http://uvm. ovm_component parent = null). endfunction: build task endfunction: configure_apb_agent 25 task pss_test_base::run. $display("Starting PSS test"). ovm_component parent = null). create the env configuration // including any sub configurations and assigning virtural interfaces function void pss_test::build().

http://uvm. this). ovm_component parent = null). gpio_env m_gpio_env. pss_virtual_sequencer m_vsqr.Ovm/Testbench/IntegrationLevel 26 The PSS env The PSS env build process retrieves the configuration object and constructs the various sub-envs. 0). this). The connect method assigns pointers for the sub-sequencer handles in the pss_env virtual sequencer. m_cfg. if(m_cfg. m_gpio_env = gpio_env::type_id::create("m_gpio_env". m_ahb_agent = ahb_agent::type_id::create("m_ahb_agent". end endfunction: build // Only required if you have sub-components which are connected function void pss_env::connect(). endclass: pss_env function pss_env::new(string name = "pss_env". m_spi_env = spi_env::type_id::create("m_spi_env" // Only required if you have sub-components which are connected extern function void connect(). after testing the various has_<sub-component> fields in order to determine whether the env is required by the test case. end if(m_cfg. m_cfg.has_virtual_sequencer) begin m_vsqr = pss_virtual_sequencer::type_id::create("m_vsqr". m_cfg. // Only required if you have sub-components extern function void build().has_spi_env) begin set_config_object("m_spi_env*". end if(m_cfg.Copyright (c) 2011 Mentor Graphics Corporation . m_cfg = pss_env_config::get_config(this). end if(m_cfg. this). // OVM Factory Registration Macro // `ovm_component_utils(pss_env) //-----------------------------------------// Data Members //-----------------------------------------pss_env_config m_cfg. "gpio_env_config". UVM/OVM Documentation .m_gpio_env_cfg. ovm_component parent = null).has_gpio_env) begin set_config_object("m_gpio_env*". endfunction // Only required if you have sub-components function void pss_env::build(). the sub-envs configuration object is set in the PSS envs configuration table. ahb_agent . super. 0).has_ahb_agent) begin set_config_object("m_ahb_agent*". parent).mentor. If the sub-env is to be present. "ahb_agent_config". //-----------------------------------------// Sub Components //-----------------------------------------spi_env m_spi_env. 0). `ifndef PSS_ENV `define PSS_ENV // // Class Description: // // class pss_env extends ovm_env. //-----------------------------------------// Methods //-----------------------------------------// Standard OVM Methods: extern function new(string name = "pss_env". "spi_env_config".m_spi_env_cfg. this).

has_spi_env) begin m_vsqr.gpi = ).m_sequencer.Ovm/Testbench/IntegrationLevel if(m_cfg.has_ahb_agent) begin m_vsqr. but further down the hierarchy.has_gpio_env) begin m_vsqr.ahb = m_ahb_agent. the configuration and build process has already been implemented in the previous generation of vertical layering. Further levels of integration Vertical reuse for further levels of integration can be achieved by extending the process described for the PSS example.has_virtual_sequencer) begin if( . so for instance a level 2 integration environment would contain two or more level 1 envs and the level 2 env configuration object would contain nested handles for the level 1 env configuration objects.m_sequencer.m_sequencer.http://uvm. Each level of integration adds another layer.spi = m_spi_env. Obviously. ( for source code example download visit us online at http://uvm. end if(m_cfg. at the test level of the hierarchy the amount of code increases for each round of vertical reuse.mentor. end if(m_cfg.m_GPI_agent.Copyright (c) 2011 Mentor Graphics Corporation .m_spi_agent. UVM/OVM Documentation .mentor. end end endfunction: connect `endif // PSS_ENV 27 The rest of the test bench hierarchy The build process continues top-down with the sub-envs being conditionally constructed as illustrated in the block level test bench example and the agents contained within the sub-envs being built as described in the agent example.

mentor. The agent is developed as package that includes a SystemVerilog interface for connecting to the signal pins of a DUT.gif components to the agent without having to know how the agent has been . In order to illustrate the design and implementation of an agent we shall take an APB bus agent and show how it is packaged.svh" // Utility Sequences `include "apb_seq.svh" "apb_sequencer.svh" endpackage: apb_agent_pkg UVM/OVM Documentation . making it possible for a user to connect external analysis Active agent ovm. configured. Any component. The APB agent uses an interface which is called apb_if and will be stored in a file called apb_if.svh" `include `include `include `include `include `include `include "apb_seq_item.svh" "apb_driver. and a SystemVerilog package that includes the classes that make up the overall agent component. plus any other verification components such as functional coverage monitors or scoreboards. import ovm_pkg::*.svh" "apb_monitor. such as an env.Copyright (c) 2011 Mentor Graphics Corporation .Ovm/Agent 28 Ovm/Agent You are reading the OVM version of this article. The various class template files for the agent are collected together in a SystemVerilog package which is saved in a file called package apb_agent_pkg.svh" " The agent also has an analysis port which is connected to the analysis port on the monitor.svh" "apb_agent_config. The agent is the lowest level hierarchical block in a testbench and its exact structure is dependent on its configuration which can be varied from one test to another via the agent configuration object. The agent class itself is a top level container class for a driver. a sequencer and a monitor. that uses files from this package will import this package.svh" "apb_agent. built and connected. `include "ovm_macros. You can find the new UVM version at [[]] An OVM agent can be thought of as a verification component kit for a specific logical interface.

// Include the APB RAM based scoreboard bit has_scoreboard = 0. localparam string s_my_config_id = "apb_agent_config". For instance. // Include the APB functional coverage monitor bit has_functional_coverage = 0. // OVM Factory Registration Macro // `ovm_object_utils(apb_agent_config) // Virtual Interface virtual apb_if APB. Whether other sub-components are built or not is controlled by other variables which should have descriptive names. localparam string s_my_config_type_error_id = "config type error". OVM agents have a variable of type OVM_ACTIVE_PASSIVE_e which defines whether the agent is active (OVM_ACTIVE) with the sequencer and the driver constructed. For instance if there is a functional coverage monitor. The configuration object is constructed and configured in the test and it is in test that the virtual interface handle is assigned to the virtual interface passed in from the testbench module.Ovm/Agent 29 The Agent Configuration Object The agent has a configuration object which is used to define: • Which of the agent sub-components get constructed (Topology) • The handle for the virtual interface used by the driver and the monitor • The behaviour of the agent By convention. `ifndef APB_AGENT_CONFIG `define APB_AGENT_CONFIG // // Class Description: // // class apb_agent_config extends ovm_object. This configuration class has a get_config() method implemented to provide a more convenient API for ovm_components to access this configuration. logic[31:0] range[15:0]. The configuration object may also contain other variables which affect the way in which the agent behaves or is configured.http://uvm. // // Address decode for the select lines: int no_select_lines = 1. //------------------------------------------ UVM/OVM Documentation . logic[31:0] start_address[15:0].Copyright (c) 2011 Mentor Graphics Corporation . there are variables which set up the memory map and determine which apb PSEL lines is activated for which addresses. or passive (OVM_PASSIVE) with niether the driver or the sequencer constructed. then the bit that controls whether the functional coverage monitor gets built or not might be called has_functional_coverage. //-----------------------------------------// Data Members //-----------------------------------------// Is the agent active or passive ovm_active_passive_enum active = OVM_ACTIVE.mentor. This parameter is called active and by default it is set to OVM_ACTIVE. The configuration object will contain a handle for the virtual interface that is used by the driver and the monitor. in the configuration object for the apb agent. localparam string s_no_config_id = "no config". The configuration class should have all its variables set to common default . The following code example shows the configuration object for the apb agent.

`ovm_file . `ovm_line ). s_my_config_id ) .new(name). return null. `ovm_file . o. if( !c. s_my_config_id ) . endclass: apb_agent_config function apb_agent_config::new(string name = "apb_agent_config"). OVM_NONE . super.http://uvm. endfunction // // Function: get_config // // This method gets the my_config associated with component c.mentor.Ovm/Agent // Methods //-----------------------------------------extern static function apb_agent_config get_config( ovm_component c ). // Standard OVM Methods: extern function new(string name = "apb_agent_config"). ovm_object o. end if( !$cast( t .com . o ) ) begin c. OVM_NONE .get_config_object( s_my_config_id .ovm_report_error( s_no_config_id . endfunction `endif // APB_AGENT_CONFIG 30 UVM/OVM Documentation .ovm_report_error( s_my_config_type_error_id . o . $sformatf("config %s associated with config %s is not of type my_config" . 0 ) ) begin c.sprint() . `ovm_line ). $sformatf("no config associated with %s" . We check for // the two kinds of error which may occur with this kind of // operation.Copyright (c) 2011 Mentor Graphics Corporation . end return t. // function apb_agent_config apb_agent_config::get_config( ovm_component c ). apb_agent_config t.

The exceptions to this rule is the monitor which is always built. Assigning the driver and monitor virtual interfaces in the agent removes the need for these sub-components to have the overhead of a configuration table lookup. • Any agent analysis sub-components analysis exports to the monitor analysis Passive agent ovm.Copyright (c) 2011 Mentor Graphics Corporation .gif port • Assignment of the virtual interfaces in the driver and the monitor to the virtual interface in the configuration object 2 Notes: 1. Then. then they need to be connected. //-----------------------------------------// Component Members //-----------------------------------------ovm_analysis_port #(apb_seq_item) ap. this saves having to construct a separate analysis port object in the agent. The following code for the apb agent illustrates how the configuration object determines what happens during the build and connect phases: `ifndef APB_AGENT `define APB_AGENT // // Class Description: // // class apb_agent extends ovm_component.Ovm/Agent 31 The Agent Build Phase The actions that take place during the agent build phase are determined by the contents of its configuration object. The Agent Connect Phase Once the agent sub-components have been constructed. the appropriate configuration field is tested to determine whether they should be constructed or not. at the points where sub-components are to be constructed. The first action during the method is to get a reference to the configuration object. since it is used whether the agent is active or passive. UVM/OVM Documentation .http://uvm. 2. The usual connections required are: • Monitor analysis port to the agent analysis port 1 • The sequencer seq_item_pull_export to the driver seq_item_pull_port (If the agent is active).com .mentor. The agent analysis port handle can be assigned a pointer from the monitor analysis port. // OVM Factory Registration Macro // `ovm_component_utils(apb_agent) //-----------------------------------------// Data Members //-----------------------------------------apb_agent_config m_cfg.

32 endclass: apb_agent function apb_agent::new(string name = "apb_agent".active == OVM_ACTIVE) begin m_driver = apb_driver::type_id::create("m_driver". m_monitor. end endfunction: connect `endif // APB_AGENT The build process for the APB agent can be followed in the block level testbench example: ( for source code example download visit us online at http://uvm.APB = m_cfg. this).new(name.connect( . apb_coverage_monitor m_fcov_monitor. this).Copyright (c) 2011 Mentor Graphics Corporation .com ). m_cfg = apb_agent_config::get_config(this).Ovm/Agent apb_monitor m_monitor.analysis_export).mentor. m_sequencer = apb_sequencer::type_id::create("m_sequencer".APB.has_functional_coverage) begin m_monitor. ap = m_monitor. // Only connect the driver and the sequencer if active if(m_cfg.ap. // Only build the driver and sequencer if active if(m_cfg.has_functional_coverage) begin m_fcov_monitor = apb_coverage_monitor::type_id::create("m_fcov_monitor". ovm_component parent = null). parent).http://uvm.ap. end if(m_cfg.seq_item_export).connect(m_sequencer. apb_sequencer m_sequencer. ovm_component parent = null). UVM/OVM Documentation . end endfunction: build function void apb_agent::connect().seq_item_port. // Monitor is always present m_monitor = apb_monitor::type_id::create("m_monitor". end if(m_cfg. m_driver.APB = m_cfg. //-----------------------------------------// Methods //-----------------------------------------// Standard OVM extern function extern function extern function Methods: new(string name = "apb_agent". this). endfunction function void apb_agent::build().APB. void connect(). apb_driver m_driver. super. this).active == OVM_ACTIVE) begin m_driver. void build().mentor.

For instance . By convention.gif called OVM_TESTNAME and uses that plusarg string as a lookup for an ovm_component if there is one present.OVM Phases 33 OVM Phases You are reading the OVM version of this article.Copyright (c) 2011 Mentor Graphics Corporation . It is usually called from within an initial block in the top level module of the . The different OVM phases are illustrated in order in the flow diagram. However. The method can be passed a string argument containing the default type name of an ovm_component which will be constructed as the root node of the OVM testbench.http://uvm. since it is clear what happens in each phase. You can find the new UVM version at [[]] In order to have a consistent execution flow. run_test() -> new To start an OVM testbench the run_test() method has to be called from the static part of the testbench.mentor. but it can be derived from any ovm_component. overriding the default type name. Calling run_test() initiates the OVM phasing by constructing the root component of the OVM class structure. the OVM uses phases which are ordered to allow the testbench component objects to stay in step as the testbench is built and configured and connected.In order to signify the test component 'my_big_test' as the root class the Questa command line would look like this: vsim tb_top +OVM_TESTNAME=my_big_test UVM/OVM Documentation . The ovm_component base class contains virtual methods for each of the phases which are populated by the testbench creator according to the requirements of the component. run_test() checks a command line plusarg Ovm phases. The defined phases allow OVM verification components developed by different teams to be mixed freely. Once the testbench hierarchy is available the simulation run phase is executed. the root node will be derived from an ovm_test component. after which the report phases occur.

Unlike the other OVM phases.Copyright (c) 2011 Mentor Graphics Corporation . After that. data collected during the previous extract phase is checked and the overall result of the testbench is calculated. the rest of the testbench hierarchy is built top-down during the build phase. When the report phase has completed. this is either via messages to the simulator transcript or by writing to files. The connect phase works from the bottom up and is used to make TLM connections between components or to make references to testbench .OVM Phases build In an OVM testbench only the test or root node component is constructed directly using the new method. by default. All components that are actively participating in the testbench will have a populated run method and all of these run methods are run in parallel. extract The extract phase is intended to be used to extract test results and statistics together with functional coverage information from different components in the testbench such as scoreboards and functional coverage monitors. This shuts down all the executing threads and terminates the run phase. run .Terminated by global_stop_request The run method is where the stimulus generation and checking activities of the testbench are defined. connect Once the testbench component hierarchy has been put in place during the build method.http://uvm. The call to global_stop_request() can either be made explicitly by the user. the connect phase begins. report The report phase is the final phase and is used to report the results of the test case. Construction is deferred so that the structure and configuration of each level of the component hierarchy can be controlled by the level above. During the build method components are indirectly constructed through a factory based creation process. the run method is a task which means that it consumes time. It may be a convenient point in the OVM phases to print banner information or testbench configuration status information. makes a $finish system call. the OVM testbench terminates and. check During the check phase. start_of_simulation The start_of_simulation phase occurs just before the run phase. The run phase is terminated by a call to the global_stop_request() method. or if the OVM objection mechanism is being used it will be called automatically when all objections have been lowered. 34 UVM/OVM Documentation . end_of_elaboration This phase can be used to make any final enhancements to the environment after it has been built and its inter-component connections made.mentor.

mentor. but may disapear in future versions and will not be supported in the UVM. . UVM/OVM Documentation . and they should consider porting any verification components using them to align with the supported set of OVM phases. These phases are still supported in the current version of the OVM . Users should avoid using the deprecated phases. usually the test Component hierarchy deferred construction and configuration phase Used to make TLM and other connections once components in place Make final enhancements before simulation starts Print out start of simulation messages Time consuming phase where the work of the test case is done Used for data extraction from analysis components Used to make checks to ensure that the simulation has completed with no errors Used to report the results of the simulation and any statistics collected end_of_elaboration Bottom-Up function start_of_simulation Bottom-Up function run extract check report Bottom-Up task Bottom-Up function Bottom-Up function Bottom-Up function Deprecated Phases There are a number of phases which are a legacy from the AVM. scoreboard and the normal stimulus generation infrastructure will be inactive during the user defined phase. For instance. it is rarely used in practice since it introduces potential incompatability problems between OVM components.used to construct the top level component. Whilst this may appear to be an useful thing to do.Copyright (c) 2011 Mentor Graphics Corporation . URM and earlier versions of the OVM. The deprecated phases and their recommended replacement phases are shown in the following table: Deprecated Phase  post_new export_connections import_connections pre_run configure Replacement Phase    build connect connect start_of_simulation end_of_elaboration Adding Other Phases The OVM provides a means to allow users to insert other task or function based phases between the standard set of phases. adding phases is not recommended.OVM Phases 35 OVM Phases .Summary Phase run_test() -> new build connect Order Phase Type function Top-Down function Bottom-Up function Description Psuedo phase . adding a task phase means that any other components will not be active during that phase so the monitor.http://uvm.

typedefed to type_id • A static function to get the type_id • A function to get the type name For example: class my_component extends ovm_component. You can find the new UVM version at [[]] The OVM Factory The purpose of the OVM factory is to allow an object of one type to be substituted with an object of a derived type without having to change the structure of the testbench or edit the testbench code. typedef my_param_component #(ADD_WIDTH.  This includes having all the same TLM interfaces handles exist and TLM objects be created by the new replacement component. // Wrapper class around the component class that is used within the factory typedef ovm_component_registry #(my_component. return type_id::get(). Factory Coding Convention 1: Registration A component or object must contain factory registration code which comprises of the following elements: • An ovm_component_registry wrapper. endfunction . Additionally.Copyright (c) 2011 Mentor Graphics Corporation .  Any components which are to be swapped must be polymorphically compatible.OVM Factory 36 OVM Factory You are reading the OVM version of this article. endclass: my_component The registration code has a regular pattern and can be safely generated with one of a set of four factory registration macros: // For a component class my_component extends ovm_component.mentor. return "my_component".com . endfunction // Used to get the type_name as a string function string get_type_name(). int DATA_WIDTH=23) extends ovm_component.. The mechanism used is refered to as an override and the override can be by instance or type. DATA_WIDTH) this_t. // Component factory registration macro `ovm_component_utils(my_component) // For a parameterised component class my_param_component #(int ADD_WIDTH=20.. // Parameterised component factory registration macro UVM/OVM Documentation .  This functionality is useful for changing sequence functionality or for changing one version of a component for another. // Used to get the type_id wrapper static function type_id get_type().http://uvm. in order to take advantage of the factory certain coding conventions need to be followed. "my_component") type_id.

UVM/OVM Documentation . . super. my_param_seq #(. super. the factory constructor should contain defaults for the constructor arguments.Copyright (c) 2011 Mentor Graphics Corporation . This allows a factory registered class to be built inside the factory using the defaults and then the class properties are re-assigned to the arguments passed via the create method of the ovm_component_registry wrapper class. // Constructor & registration macro left out // Component and Parameterised Component create examples function void build(). ovm_transaction.ADDR_WIDTH(32). again the create method is used.mentor. then assigns the pointer to the class to its declaration handle in the testbench after having the name and parent arguments correctly.ADDR_WIDTH(32). m_my_p_component = my_param_component #(32. In order to support deferred construction during the build phase. `ovm_oject_utils(my_item) // For a parameterised object class class my_item #(int ADD_WIDTH=20. The defaults are different for components and objects: // For a component: class my_component extends this). ovm_sequence etc) class my_item extends ovm_sequence_item. my_param_component #(.OVM Factory `ovm_component_param_utils(this_t) // For a class derived from an object (ovm_object. This first constructs the class. function new(string name = "my_component". endfunction Factory Coding Convention 3: Component and Object creation Testbench components are created during the build phase using the create method of the ovm_component_registry. int DATA_WIDHT=20) extends ovm_sequence_item. this). the build process is top-down. endfunction // For an object class my_item extends which allows higher level components and configurations to control what actually gets built. my_seq test_seq. parent). ovm_sequence_item. . m_my_component = my_component::type_id::create("m_my_component".DATA_WIDTH(32)) . endfunction: build task run. DATA_WIDTH) this_t `ovm_object_param_utils(this_t) 37 Factory Coding Convention 2: Constructor Defaults The ovm_component and ovm_object constructors are virtual methods which means that users have to follow their prototype template. ovm_component parent = null). Object classes are created as required. 32)::type_id::create("m_my_p_component". my_component m_my_component. typedef my_item #(ADD_WIDTH.http://uvm.DATA_WIDTH(32)) p_test_seq. For components. function new(string name = "my_item"). The following code snippet illustrates how this is done: class env extends ovm_env.

32)::type_id::create("p_test_seq").OVM Factory // Object and parameterised ojbect create examples test_seq = my_seq::type_id::create("test_seq").. p_test_seq = my_param_seq #(32.Copyright (c) 2011 Mentor Graphics Corporation .com . // .http://uvm. endtask: run 38 UVM/OVM Documentation ...mentor.

call us or visit: w w w. all rights reserved. the recipient agrees to make every reasonable effort to prevent unauthorized use of this information. All trademarks mentioned are this document are trademarks of their respective owners.c o m © 2010 Mentor Graphics Corporation. MGC 06-10 TECH9050-w . In accepting this document. provided that this entire notice appears in all copies.m e n t o r.Mentor Graphics UVM/OVM Documentation / Methodology Cookbook For the latest product information. This document contains information that is proprietary to Mentor Graphics Corporation and may be duplicated in whole or in part by the original recipient for internal business purposes only.