{"id":16260,"date":"2021-06-21T09:48:03","date_gmt":"2021-06-21T13:48:03","guid":{"rendered":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/?p=16260"},"modified":"2026-03-27T08:49:57","modified_gmt":"2026-03-27T12:49:57","slug":"verification-class-categories","status":"publish","type":"post","link":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/2021\/06\/21\/verification-class-categories\/","title":{"rendered":"Verification Class Categories"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>What can you describe with Object-Oriented Programming? When I learned OOP, we had cute classes like animals, cars, and houses. That would be fine if I was taking a C++ or Java course, but this is SystemVerilog, and I am verifying hardware designs. What should my classes represent? This post shows two major categories. It also covers concepts that confused me when I first learned UVM, like sequence vs. sequencer.<\/p>\n\n\n\n<p>This is the second post in a series. Here is the first <a href=\"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/2021\/06\/14\/systemverilog-class-variables-and-objects\/\">post<\/a> on Class Variables and Objects.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The UVM Way<\/h2>\n\n\n\n<p>UVM testbenches have two major groups of classes: transactions and components, plus minor utilities. All UVM classes are derived from uvm_object. In my last post, I recommended that you give every SystemVerilog object either a unique ID or name. uvm_object has both as seen in its constructor.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class uvm_object;\n  function new(string name);\n    m_inst_id = m_inst_count++;\n    m_leaf_name = name;\n  endfunction\nendclass<\/pre>\n\n\n\n<p>This code follows the convention that member variables start with the prefix of \u201cm_\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">UVM Topology<\/h2>\n\n\n\n<p>In the following diagram, all the boxes are components: test, environment, agent, monitor, driver, sequencer, and scoreboard. The gold dots are transactions that are generated in the gold sequence and flow to the driver, or are sampled in the monitor and sent to the scoreboard.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"783\" height=\"497\" src=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_1_uvm_topo.png\" alt=\"UVM Topology with components and transactions\" class=\"wp-image-16262\" srcset=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_1_uvm_topo.png 783w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_1_uvm_topo-600x381.png 600w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_1_uvm_topo-768x487.png 768w\" sizes=\"auto, (max-width: 783px) 100vw, 783px\" \/><figcaption>UVM Topology with components and transactions<\/figcaption><\/figure>\n\n\n\n<p>The OOP term \u201chierarchy\u201d refers to the tree of base classes and their extensions, an <em>is-a<\/em> relationship. The UVM term \u201chierarchy\u201d is a <em>has-a<\/em> relationship, like an agent has-a driver. To avoid confusion, I call this relationship the UVM \u201ctopology\u201d.<\/p>\n\n\n\n<p>UVM components have a fixed topology. A driver is always inside an agent, so UVM says that the driver\u2019s parent is the agent. The agent\u2019s parent is an environment, whose parent is the test.<\/p>\n\n\n\n<p>You can see this in the constructor for the base component class which passes the name up to uvm_object and saves a copy of the parent handle. Neither the name or parent need a default.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class uvm_component extends uvm_object;\n  function new(string name, uvm_component parent);\n    super.new(name);\n    m_parent = parent;\n  endfunction\nendclass<\/pre>\n\n\n\n<p>Transactions have no fixed location, flowing from one component to the next. You can&#8217;t verify a design with a single transaction, so UVM groups one or more of them into a sequence. This is why transactions in UVM are derived from uvm_sequence_item. This class is derived from uvm_object, and its constructor does not have a parent argument. However the name must have a default value.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class uvm_sequence_item extends uvm_object;\n  function new(string name=\u201duvm_sequence_item\u201d);\n    super.new(name);\n  endfunction\nendclass<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Life in the Tree of Components<\/h2>\n\n\n\n<p>Another dimension of your testbench is time. When are these objects constructed and then garbage collected? When you start simulation, UVM builds the components from the top down, from the test down to the driver and monitor. These objects exist for the entire simulation \u2013 you wouldn\u2019t want the driver to get garbage collected halfway through the test! I call component objects \u201cpermanent\u201d.<\/p>\n\n\n\n<p>After the components are built and connected, UVM runs your test. Hundreds or thousands of transactions are created in sequences, flow through the testbench into the design, or captured by the monitor and sent to the scoreboard. When no longer needed, the objects are garbage collected. Transactions are very dynamic.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Who\u2019s Jiving Who?<\/h2>\n\n\n\n<p>The final big difference between these two types is their focus. Transactions are passive containers of properties such as address and data. The have functions to print, copy, and compare the properties. This pseudo-UVM Packet class gives you the flavor. The calcCsm function calculates the checksum (csm) based on the src, dst, and data properties.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"934\" height=\"764\" src=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_2_packet_class-1.png\" alt=\"\" class=\"wp-image-16281\" srcset=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_2_packet_class-1.png 934w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_2_packet_class-1-600x491.png 600w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_2_packet_class-1-768x628.png 768w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_2_packet_class-1-900x736.png 900w\" sizes=\"auto, (max-width: 934px) 100vw, 934px\" \/><figcaption>The Packet class with functions, and a Packet class variable<\/figcaption><\/figure>\n\n\n\n<p>Components are active, operating on transactions. (Technically, they have class variables with handles to the transaction objects.)&nbsp; Components have tasks to send and receive transactions. You would never print, copy, clone, or compare a component.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_3_driver_class-1-1024x616.png\" alt=\"\" class=\"wp-image-16282\" srcset=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_3_driver_class-1-1024x616.png 1024w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_3_driver_class-1-600x361.png 600w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_3_driver_class-1-768x462.png 768w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_3_driver_class-1-900x542.png 900w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_3_driver_class-1.png 1118w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>The Packet_Driver class with run_phase task, and a class variable<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Summary: UVM Categories<\/h2>\n\n\n\n<p>The following table compares the two major categories of classes in UVM, with examples based on the above code.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>What<\/strong><\/td><td><strong>Transactions<\/strong><\/td><td><strong>Components<\/strong><\/td><\/tr><tr><td>UVM Topology<\/td><td>No fixed location<\/td><td>Fixed location<\/td><\/tr><tr><td>Constructor<\/td><td>function new(name=&#8221;default&#8221;)<\/td><td>function new(name, parent)<\/td><\/tr><tr><td>Factory macro<\/td><td>`uvm_object_utils(class_name)<\/td><td>`uvm_component_utils(class_name)<\/td><\/tr><tr><td>create call<\/td><td>pkt = packet::type_id::create(&#8220;pkt&#8221;)<\/td><td>drv = packet_driver::type_id::create(&#8220;driver&#8221;, this)<\/td><\/tr><tr><td>Lifetime<\/td><td>Short<\/td><td>Permanent<\/td><\/tr><tr><td>active\/passive<\/td><td>Passive: method operate on itself<\/td><td>Active: methods operate on transaction objects<\/td><\/tr><tr><td>Methods<\/td><td>Functions to print, copy, clone, compare, this object&#8217;s properties<\/td><td>Tasks such as run_phase() and functions that operate on transactions<\/td><\/tr><\/tbody><\/table><figcaption>Comparison between UVM transaction and component classes<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Final Note<\/h2>\n\n\n\n<p>This post goes over many concepts that confused me when I first learned UVM, such as why some constructors have one argument, and other have two. Another issue: what is the difference between a sequence and a sequencer? Just remember that a sequencer, like a driver, and monitor, is an active component \u2013 they all end in \u2018r\u2019. Hopefully you can get up to speed faster than me!<\/p>\n\n\n\n<p>This describes a very simple system with the minimum number of classes. The code examples left out many details. Otherwise, this post would be twice as long and twice as confusing!<\/p>\n\n\n\n<p>Here is the next <a href=\"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/2021\/06\/28\/runtime-checks-with-the-cast-method\/\">post <\/a>in this series.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction What can you describe with Object-Oriented Programming? When I learned OOP, we had cute classes like animals, cars, and&#8230;<\/p>\n","protected":false},"author":72251,"featured_media":16262,"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":[1,982,10],"tags":[951,382,383,950,952,953,515,910,612,614,707,858,708,709,751,769,787,803,873,859,860,862],"industry":[],"product":[],"coauthors":[942],"class_list":["post-16260","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","category-systemverilog","category-tips-tricks","tag-base-class","tag-class","tag-class-handles","tag-class-variable","tag-derived-class","tag-extended-class","tag-handle","tag-hardware-verification","tag-object-oriented-programming","tag-oop","tag-sequence","tag-sequence-item","tag-sequencer","tag-sequencers","tag-systemverilog","tag-transaction","tag-uvm","tag-uvm-sequences","tag-uvm_object_utils","tag-uvm_sequence","tag-uvm_sequence_item","tag-uvm_sequencer"],"featured_image_url":"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2021\/06\/2_1_uvm_topo.png","_links":{"self":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/16260","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\/72251"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/comments?post=16260"}],"version-history":[{"count":4,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/16260\/revisions"}],"predecessor-version":[{"id":16375,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/16260\/revisions\/16375"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/media\/16262"}],"wp:attachment":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/media?parent=16260"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/categories?post=16260"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/tags?post=16260"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/industry?post=16260"},{"taxonomy":"product","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/product?post=16260"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/coauthors?post=16260"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}