{"id":16672,"date":"2021-11-17T00:06:45","date_gmt":"2021-11-17T05:06:45","guid":{"rendered":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/?p=16672"},"modified":"2026-03-27T08:47:52","modified_gmt":"2026-03-27T12:47:52","slug":"uvm-factory","status":"publish","type":"post","link":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/2021\/11\/17\/uvm-factory\/","title":{"rendered":"The UVM Factory"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<p>In the previous post in the <a href=\"https:\/\/verificationacademy.com\/news\/the-python-for-verification-series\" target=\"_blank\" rel=\"noopener\">Python for Verification Series,<\/a> we discussed how <strong>pyuvm<\/strong> implemented the configuration database as a singleton class named <code>ConfigDB()<\/code>. In this post, we\u2019ll examine the UVM factory.<\/p>\n\n<p>The <strong>pyuvm<\/strong> implements the UVM factory as it is described in the specification, removing elements that complicated the factory because of SystemVerilog typing.<\/p>\n\n<h2>Instantiating objects using the factory<\/h2>\n\n<p>SystemVerilog UVM developers have a choice of whether they instantiate objects using the <code>new()<\/code> function, or whether they use the long factory incantation that delivers an object that can be overridden. <strong>pyuvm<\/strong> provides the same options.<\/p>\n\n<p>We have the following component that logs a tiny message:<\/p>\n\n<pre><code>class TinyComponent(uvm_component):\n    async def run_phase(self):\n        self.raise_objection()\n        self.logger.info(\"I'm so tiny!\")\n        self.drop_objection()<\/code><\/pre>\n\n<p>Notice that we don\u2019t have a <code>uvm_component_utils()<\/code> macro that registers the class with the factory. In <strong>pyuvm,<\/strong> all classes that extend <code>uvm_void<\/code> are all registered with the factory.<\/p>\n\n<p>You can instantiate this component directly like this:<\/p>\n\n<pre><code>class TinyTest(uvm_test):\n    def build_phase(self):\n        self.tc = TinyComponent(\"tc\", self)<\/code><\/pre>\n\n<p>Or, you can instantiate the component using the <code>create()<\/code> class method:<\/p>\n\n<pre><code>class TinyFactoryTest(uvm_test):\n    def build_phase(self):\n        self.tc = TinyComponent.create(\"tc\", self)\n--\n1000.00ns INFO     testbench.py(15)[uvm_test_top.tc]: I'm so tiny!<\/code><\/pre>\n\n<p>Notice that you do <em>not<\/em> put parenthesis after the class name when you call a class method. This would create an instance of the object and then call the class method using the instance. <\/p>\n\n<p>Thanks to the lack of typing in Python, the <code>create()<\/code> call in Python is much easier to use than the baroque incantation used to call <code>create()<\/code> in SystemVerilog.<\/p>\n\n<p>Now we can override our component.<\/p>\n\n<h2>Overriding classes<\/h2>\n\n<p>We override types in <strong>pyuvm<\/strong> by using the <code>uvm_factory()<\/code> singleton object. The <code>uvm_factory()<\/code> has four overriding methods. Note that what SystemVerilog calls a <em>type<\/em>, we Python programmers call a <em>class<\/em>. Still, the specification uses the word <em>type<\/em> in these methods:<\/p>\n\n<ul>\n\t<li><code>set_type_override_by_type(&lt;original class&gt;, &lt;overriding class&gt;)<\/code><\/li>\n\t<li><code>set_type_override_by_name(&lt;\"original class name\"&gt;,  &lt;\u201coverriding class name\u201d&gt;)<\/code><code>\n\t\t<\/code><\/li>\n\t<li><code>set_inst_override_by_type(&lt;original class&gt;, &lt;overriding class&gt;, &lt;\"UVM hierarchy path\"&gt;)<\/code><\/li>\n\t<li><code>set_inst_override_by_name(&lt;\"original class name\"&gt;,  &lt;\u201coverriding class name\u201d&gt;, &lt;\"UVM hierarchy path)<\/code><\/li>\n<\/ul>\n\n<p>Here is an example of creating a component and using it in an override:<\/p>\n\n<pre><code>class MediumComponent(uvm_component):\n    async def run_phase(self):\n        self.raise_objection()\n        self.logger.info(\"I'm medium size.\")\n        self.drop_objection()<\/code><\/pre>\n\n<p>Now we create a test that overrides <code>TinyComponent<\/code> with <code>MediumComponent<\/code>:<\/p>\n\n<pre><code>class MediumFactoryTest(TinyFactoryTest):\n    def build_phase(self):\n        uvm_factory().set_type_override_by_type(\n            TinyComponent, MediumComponent)\n        super().build_phase()\n--\n2000.00ns INFO     testbench.py(44)[uvm_test_top.tc]: I'm medium size.<\/code><\/pre>\n\n<p>Notice that Python classes are objects just like everything else, so we can pass them to <code>set_type_override_by_type<\/code> using the simple class names. There is no need for the <code>get_type()<\/code> method that we see in SystemVerilog.<\/p>\n\n<p>We can use an environment to demonstrate instance overrides:<\/p>\n\n<pre><code>class TwoCompEnv(uvm_env):\n    def build_phase(self):\n        self.tc1 = TinyComponent.create(\"tc1\", self)\n        self.tc2 = TinyComponent.create(\"tc2\", self)<\/code><\/pre>\n\n<p>Now we have two components, but only want to override <code>tc1<\/code>. Notice that in this example we use <code>set_inst_override_by_name<\/code> so we pass strings containing the names of the classes:<\/p>\n\n<pre><code>class TwoCompTest(uvm_test):\n    def build_phase(self):\n        uvm_factory().set_inst_override_by_name(\n            \"TinyComponent\", \"MediumComponent\", \"uvm_test_top.env.tc1\")\n        self.env = TwoCompEnv(\"env\", self)\n--\n4000.00ns INFO     testbench.py(44)[uvm_test_top.env.tc1]: I'm medium size.\n4000.00ns INFO     testbench.py(15)[uvm_test_top.env.tc2]: I'm so tiny!<\/code><\/pre>\n\n<p>We\u2019ve now overridden only one instance of the <code>TinyComponent<\/code>.<\/p>\n\n<h2>Clearing overrides from the factory<\/h2>\n\n<p>Python and <strong>pyuvm<\/strong> allow you to run many UVM tests in a single Python file. When you do this, the overrides from one test will persist unless you explicitly clear them in the next test. You do this with the <code>uvm_factory().clear_overrides()<\/code> method, as we do below:<\/p>\n\n<pre><code>@cocotb.test()\nasync def two_comp_test(_):\n    uvm_factory().clear_overrides()\n    await uvm_root().run_test(\"TwoCompTest\")<\/code><\/pre>\n\n<h2>Printing the state of the factory<\/h2>\n\n<p>The UVM specification calls for a <code>uvm_factory().print()<\/code> method that prints the state of the factory. The <code>print()<\/code> method takes an argument that controls what gets printed. The argument, named <code>all_types<\/code>, can be set to <code>0<\/code>, <code>1<\/code> or <code>2<\/code> with the following results:<\/p>\n\n<ul>\n\t<li><code>0<\/code>\u2014Prints overrides only<\/li>\n\t<li><code>1<\/code>\u2014 (the default) Prints user-defined types and overrides. User-defined types are types whose names don\u2019t start with the string <code>\"uvm_\"<\/code><\/li>\n\t<li><code>2<\/code>\u2014Prints all types registered with the factory and overrides.<\/li>\n<\/ul>\n\n<p>Here is an example of printing only overrides:<\/p>\n\n<pre><code>@cocotb.test()\nasync def two_comp_test(_):\n    uvm_factory().clear_overrides()\n    await uvm_root().run_test(\"TwoCompTest\") # from above\n    uvm_factory().print(0)\n--\n# --- overrides ---\n# \n# Overrides:\n# TinyComponent            : Type Override: None       || Instance Overrides: uvm_test_top.env.tc1 =&gt; MediumComponent<\/code><\/pre>\n\n<p>The <code>print()<\/code> method uses the Python <code>print()<\/code> function to print out the factory status. But you can incorporate the factory status into logging by creating a string from the factory.<\/p>\n\n<h2>Creating a string from the factory<\/h2>\n\n<p>The <code>uvm_factory().debug_level<\/code> data member can take the same three values as we saw above <code>0<\/code>, <code>1<\/code> or <code>2<\/code> with the same behavior. We create a string from the <code>uvm_factory()<\/code> by passing it to the <code>str()<\/code> class. For example, we might log the state of the factory in the report phase:<\/p>\n\n<pre><code>class MediumNameTest(TinyFactoryTest):\n    def build_phase(self):\n        uvm_factory().set_type_override_by_name(\n            \"TinyComponent\", \"MediumComponent\")\n        super().build_phase()\n\n    def report_phase(self):\n        uvm_factory().debug_level = 0\n        uvm_factory_str = str(uvm_factory())\n        self.logger.info(uvm_factory_str)\n--\n3000.00ns INFO     testbench.py(69)[uvm_test_top]: --- overrides ---\n                   \n                   Overrides:\n                   TinyComponent            : Type Override: MediumComponent || Instance Overrides: \n                     <\/code><\/pre>\n\n<p><strong>cocotb<\/strong> formats the string to fit in the logging system.<\/p>\n\n<h2>Summary<\/h2>\n\n<p>This blog post introduced the UVM factory as implemented in <strong>pyuvm<\/strong>. We saw that the lack of typing make the <strong>pyuvm<\/strong> factory easier to use than the SystemVerilog one. <strong>pyuvm<\/strong> implements the complete UVM factory specification and adds the ability to create a string from the <code>uvm_factory()<\/code> singleton.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post in the Python for Verification Series, we discussed how pyuvm implemented the configuration database as a&#8230;<\/p>\n","protected":false},"author":74314,"featured_media":16675,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spanish_translation":"","french_translation":"","german_translation":"","italian_translation":"","polish_translation":"","japanese_translation":"","chinese_translation":"","footnotes":""},"categories":[984,1,981,10,983],"tags":[971,798],"industry":[],"product":[205],"coauthors":[947],"class_list":["post-16672","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cocotb","category-news","category-pyuvm","category-tips-tricks","category-uvm","tag-pyuvm","tag-uvm-factory","product-questa"],"featured_image_url":"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/11\/factory.png","_links":{"self":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/16672","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/users\/74314"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/comments?post=16672"}],"version-history":[{"count":5,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/16672\/revisions"}],"predecessor-version":[{"id":16699,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/16672\/revisions\/16699"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/media\/16675"}],"wp:attachment":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/media?parent=16672"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/categories?post=16672"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/tags?post=16672"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/industry?post=16672"},{"taxonomy":"product","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/product?post=16672"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/coauthors?post=16672"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}