{"id":17656,"date":"2022-10-17T11:20:51","date_gmt":"2022-10-17T15:20:51","guid":{"rendered":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/?p=17656"},"modified":"2026-03-27T08:50:11","modified_gmt":"2026-03-27T12:50:11","slug":"dig-a-pool-of-specialized-systemverilog-classes","status":"publish","type":"post","link":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/2022\/10\/17\/dig-a-pool-of-specialized-systemverilog-classes\/","title":{"rendered":"Dig a Pool of Specialized SystemVerilog Classes"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>SystemVerilog classes are a great way to encapsulate both variables and the routines that operates on them. What if you want to reuse the methods but change the type of properties? Use a parameter and specialize it!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Definition<\/h2>\n\n\n\n<p>In Object-Oriented Programming (OOP), encapsulate variables and routines in a class. A class variable is called a property and a class routine is a method. By grouping them together, the result is more reusable than if they were kept separate.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The First Assignment<\/h2>\n\n\n\n<p>Your manager asks you to write a class to represent a stack. When you tell her that SystemVerilog already has a queue that can be used as a LIFO (Last In, First Out), she responds, \u201cYes, but on the last project, someone kept switching between push_front(), push_back(), and pop_front(), pop_back(), causing testbench bugs. Give me a stack class with just push() and pop().\u201d Phew!<\/p>\n\n\n\n<p>Your first attempt might look like the following, with no error checking.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Stack;\n&nbsp; bit&#91;31:0] items&#91;100];\n&nbsp; int idx = -1;\n&nbsp; string name;\n\n&nbsp; function new(string name);\n&nbsp;&nbsp;&nbsp; this.name = name;\n&nbsp; endfunction\n\n&nbsp; function push(input bit&#91;31:0] val);\n&nbsp;&nbsp;&nbsp; items&#91;++idx] = val;\n&nbsp; endfunction\n\n&nbsp; function bit&#91;31:0] pop();\n&nbsp;&nbsp;&nbsp; return items&#91;idx--];\n&nbsp; endfunction\nendclass<\/code><\/pre>\n\n\n\n<p>Here is a short test.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Stack s;<br>initial begin<br>&nbsp; s = new(\"s32\"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Construct a Stack object<br>&nbsp; s.push('1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\/\/ Push all 1\u2019s<br>&nbsp; $display(\"pop()=%x\", s.pop()); \/\/ Expect FFFF_FFFF<br>end<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">That was good, now specialize it<\/h2>\n\n\n\n<p>Your manager liked that solution but asked why you only used 32-bit numbers. After all, the next project has a 64-bit data path. Can you make a compatible stack class? How about 128-bits?<\/p>\n\n\n\n<p>Rather than make separate classes for each width, create a parameterized class. This one has a default width of 4 bits so it will obvious if you forget to specify the correct width.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Stack #(parameter int WIDTH=4);\n&nbsp; bit&#91;WIDTH-1:0] items&#91;100];\n&nbsp; int idx = -1;\n\n&nbsp; function push(input bit&#91;WIDTH-1:0] val); \u2026\n&nbsp; function bit&#91;WIDTH:0] pop(); \u2026<\/code><\/pre>\n\n\n\n<p>Declare two handles for this class, first with the default width, and another for 64-bit values.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Stack s4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;\/\/ Handle to a 4-bit stack object<br>Stack #(64) s64; \/\/ Handle to a 64-bit stack object<\/code><\/pre>\n\n\n\n<p>Try these two stack types with the test code from the first section.<\/p>\n\n\n\n<p>When you give a value for a parameter when declaring a class handle (or use the default value), it is called &#8220;specialization&#8221;. Under the hood, it is as if the compiler creates a new type (but you can&#8217;t use it directly). You can imagine it creates the following for a specialization of WIDTH=64.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><em>class _<strong>Stack__64<\/strong>; \/\/ Equivalent class for specialization: Stack #(64) s64\n&nbsp; bit&#91;<strong>64<\/strong>-1:0] items&#91;100];\n&nbsp; int idx = -1;\n\n&nbsp; function push(input bit&#91;<strong>64<\/strong>-1:0] val); \u2026\n&nbsp; function bit&#91;<strong>64<\/strong>-1:0] pop(); \u2026\nendclass<\/em><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">A group of stacks<\/h2>\n\n\n\n<p>A verification engineer saw this parameterized class and said that he wanted to make a group of these stacks as part of the reference model. However, when he tried the following code, it wouldn\u2019t compile.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Stack q&#91;$]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ A queue of stack handles\ninitial begin\n&nbsp; q.push_back(s4);\n&nbsp; q.push_back(s64); \/\/ Bad assign to Stack#(4) from Stack#(64)\nend<\/code><\/pre>\n\n\n\n<p>The problem is that the two specializations, Stack#(4) and Stack#(64), are different types, and you can&#8217;t assign between them, not even with the $cast() system task. You can&#8217;t group dissimilar types.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Twisting by the Pool<\/h2>\n\n\n\n<p>You can group multiple objects together if they have the same type. Wrap this group in a class with methods to make it easier to manipulate them. UVM calls this a \u201cpool\u201d.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"650\" height=\"276\" src=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2022\/10\/pool_of_stacks.png\" alt=\"A pool of specialized classes\" class=\"wp-image-17657\" srcset=\"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2022\/10\/pool_of_stacks.png 650w, https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2022\/10\/pool_of_stacks-600x255.png 600w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><figcaption>A pool of specialized classes<\/figcaption><\/figure>\n\n\n\n<p>(The formal name for this group is an \u201caggregate\u201d which means each object can exist on its own. The opposite is \u201ccomposition\u201d, such as an Animal class that is composed from <a href=\"https:\/\/youtu.be\/c3AAnohyZWM?t=428\" target=\"_blank\" rel=\"noopener\">Head<\/a> and Body classes.)<\/p>\n\n\n\n<p>Here is the Pool class. The class defines T, a type based on the width. (Note that the keyword \u201cparameter\u201d is optional.)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Pool #(int WIDTH=4);  \/\/ Pool class\n  typedef Stack #(WIDTH) T; \/\/ Type of objects in pool\n  T queue&#91;$];               \/\/ Queue of specialized handles\n\n  function void add(input Stack s);\n    queue.push_back(s);\n  endfunction\n\n  \/\/ Print the name of all objects\n  function void print();\n    foreach (queue&#91;i])\n      $display(\"Pool&#91;%0d] name='%s'\", i, queue&#91;i].name);\n  endfunction\nendclass<\/code><\/pre>\n\n\n\n<p>Here is code to test the Stack and Pool classes.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Stack #(4) s0, s1;<br>Pool #(4) &nbsp;p4;<br>initial begin<br>&nbsp; p4 = new();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Construct a pool of Stack#(4) handles<br>&nbsp; s0 = new(\"zero\"); \/\/ Construct a 4-bit Stack object<br>&nbsp; p4.add(s0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Add it to the pool<br>&nbsp; s1 = new(\"one\");&nbsp; \/\/ Construct another 4-bit Stack<br>&nbsp; p4.add(s1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\/\/ Add it to the pool<br>&nbsp; p4.print(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Print the names of all Stack objects<br>end<\/code><\/pre>\n\n\n\n<p>What happens if you create a stack of 8-bit values and try to add this to the Pool #(4) instance?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">More Experiments<\/h2>\n\n\n\n<p>The code above showed how to parameterize a class with a value to create vectors of different widths. What if you want to make a stack of real numbers? SystemVerilog also supports type parameters. Here is the start of a stack class where you can change the type. I have deliberately left out the push() and pop() methods so you can write them yourself.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Stack_T #(type T = int);\n\u00a0 int idx;\n\u00a0 T items&#91;100]; \/\/ Store the stack made of items of type T\n\n\u00a0 \/\/ What do the push() and pop() methods look like?\n\nendclass\n\n\/\/ Declare handle to various type stacks\nStack_T\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0  stack_int;\u00a0\u00a0 \/\/ Stack of int\u2019s\nStack_T #(bit&#91;15:0]) stack_bit16; \/\/ Stack of 16-bit values\nStack_T #(real)\u00a0\u00a0\u00a0\u00a0  stack_real;\u00a0 \/\/ Stack of reals<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Learn More<\/h2>\n\n\n\n<p>You can learn more about these topics including Oriented Programming with the Siemens SystemVerilog for Verification course. It is offered in&nbsp;<a href=\"https:\/\/training.plm.automation.siemens.com\/ilt\/iltdescription.cfm?pID=268489-US_____EDA__2021.4_1199\" target=\"_blank\" rel=\"noreferrer noopener\">instructor led<\/a>&nbsp;format by our industry expert instructors, or in a self-paced&nbsp;<a href=\"https:\/\/training.plm.automation.siemens.com\/mytraining\/viewlibrary.cfm?memTypeID=287545&amp;memID=287545\" target=\"_blank\" rel=\"noreferrer noopener\">on-demand<\/a>&nbsp;format. It can also be tailored to address your specific design goals and show you how to set up an environment for reuse for additional designs.&nbsp; Also, you can now earn a digital badge\/level 1 certificate by taking our&nbsp;<a href=\"https:\/\/training.plm.automation.siemens.com\/mytraining\/viewlibrary.cfm?memTypeID=288054&amp;memID=288054\" target=\"_blank\" rel=\"noreferrer noopener\">Advanced Topics Badging Exam<\/a>. This will enable you to showcase your knowledge of this topic by displaying the badge in your social media and email signature.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction SystemVerilog classes are a great way to encapsulate both variables and the routines that operates on them. What if&#8230;<\/p>\n","protected":false},"author":71586,"featured_media":17657,"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":[300,1483,1481,345,382,1482,1486,515,1484,614,630,631,1488,673,1485,1487,751,775,787,807],"industry":[],"product":[],"coauthors":[980],"class_list":["post-17656","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","category-systemverilog","category-tips-tricks","tag-cast","tag-aggregate","tag-aggregation","tag-array","tag-class","tag-composite","tag-composition","tag-handle","tag-object-oriented-programming-2","tag-oop","tag-parameter","tag-parameterized-class","tag-pool","tag-queue","tag-specialized-type","tag-stack","tag-systemverilog","tag-typedef","tag-uvm","tag-uvm_pool"],"featured_image_url":"https:\/\/blogs.sw.siemens.com\/wp-content\/uploads\/sites\/54\/2022\/10\/pool_of_stacks.png","_links":{"self":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/17656","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\/71586"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/comments?post=17656"}],"version-history":[{"count":5,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/17656\/revisions"}],"predecessor-version":[{"id":17810,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/posts\/17656\/revisions\/17810"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/media\/17657"}],"wp:attachment":[{"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/media?parent=17656"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/categories?post=17656"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/tags?post=17656"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/industry?post=17656"},{"taxonomy":"product","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/product?post=17656"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blogs.sw.siemens.com\/verificationhorizons\/wp-json\/wp\/v2\/coauthors?post=17656"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}