SystemVerilog is primarily and extensively used as a Hardware Verification Language (HVL). Also known as Super Verilog, it encompasses Verilog, VHDL and OOPS (Object Oriented Programming) concepts. As the designs began to get increasingly complex, it became tougher for the verification team to verify those designs using the legacy test bench approach. Engineers had to invest a lot of time and effort into building test benches that could verify the complex weaves of the design such as multitasking wherein handling interprocess synchronization and communication was a huge challenge. An upgrade in the design also meant more efforts to tailor the test bench for verifying those upgrades. With the legacy test bench approach, it was not possible to reuse the test bench owing to hierarchical dependencies. Apart from this, measuring the coverage metrics or generating ‘constrained’ random stimulus was also a tall asking in legacy test benches. Above all, the legacy test bench approach viewed the design as a bunch of variables and procedures rather than an ‘object in its entirety’. Thus in order to verify the design accurately, it became essential to model a test bench which was more ‘real’ and ‘closer’ to the design.
The procedural method for ASIC verification has now largely been replaced by the layered test bench architecture. Bus functional Models have now been replaced with objects that ‘contain’ the necessary code that can drive, monitor, check and the likes. Data is no longer viewed as a variable or a set of variables, it is now an object that can be randomized or directed at whim and will and can be passed on between concurrent processes keeping the code hierarchy a secret. Interfaces are no longer a mere set of signals and no longer does signal change(s) compel one to modify a whole lot of code. The interface is now an ‘object’ containing a bunch of signals and their ‘clocking’ information. Any changes in signals would require only a single change in the ‘object declaration’, the remaining instantiations shall follow suit. By imbibing the OOPS concepts such as Abstraction, Encapsulation, Inheritance and Polymorphism, SystemVerilog has not just accelerated but also simplified the ASIC verification process.
Data Abstraction
Data abstraction is a significant OOPS concept that has found great usage in building SystemVerilog test benches. The main motive of ‘Abstraction’ is to keep the complexity a secret by showing only the relevant details to the user. As an example, if you use your ‘microwave oven’ to warm up your food, all you need to know is to keep the food in and set the temperature/power settings as well as the timer right. The internal workings of the oven are not something you ‘must’ know in order to warm your food. Similarly, data abstraction in SystemVerilog is a concept that ‘hides’ the complex implementation details and divulges information only that is relevant.
Communication between components in Verilog such as the DUT (Design Under Test) and the driver BFM (Bus Functional Model) happens via an interface comprising of a bunch of signals. A single change or multiple edits in signals would mean that the verification engineer would have to wade through the code and make changes. While in the case of SystemVerilog the ‘interface’ between two components of the test bench or the test bench and the design can be ‘clubbed’ into a ‘modport’. A single edit in the ‘modport’ declaration would be enough to reflect the changes across all areas of code where it has been utilized. Similarly, if we have concurrent processes such as multiple drivers driving the same set of signals or multiple processes writing to the same address space, then handling the ‘handshake’ would mean adding a lot of complexity and hence time as well as effort. SystemVerilog offers features such mailbox and semaphore for an instance that completely ‘offloads’ the complexity and thus simplifying the task of developing as well as maintaining test benches.
Encapsulation
As we look around, we see objects around us. If we brood a little more ‘some’ objects can be classified into ‘furniture’ and ‘some’ could be household appliances or electronics. Each ‘class’ of an object holds certain features and exhibits functions unique to themselves. Similarly, in SystemVerilog, each class or object ‘encapsulates’ certain features and functions that aptly describe it. As an example, a driver class would contain a handle to drive the interface, a handle to the data packet to be driven, a delay variable (if needed) and a method that ‘drives’ data. Thus ‘encapsulation’ refers to the concept wherein data and the methods that work on them are grouped into a ‘class’. Unlike the methods and data that are easily accessible in procedural programming, here they are ‘bunched’ into a class.
Encapsulation also comes handy in information hiding. Although by default, all class properties can be accessed via its object handle, this level of information is not as explicit as in procedural programming. It is up to the ‘object’ to decide whether to allow another object to modify or retrieve information regarding its ‘properties’. A classic example of this is the implementation of get() and set() methods that render the authority to other objects to modify or view class properties. But what if we are dealing with variables associated with state machines, data encryption or even data corruption. Ideally, such variables that must be ‘confined’ should not be tampered. Thus in order to handle data hiding, we can declare a class property to be ‘local’ or ‘protected’. In case the property has been declared ‘local’, any access to that property ‘outside’ the class is disallowed. However, if the property has been declared ‘protected’, it can be accessed from the extended class.
Inheritance
Inheritance is a key concept behind making the layered test benches ‘reusable’. A derived class inherits all the properties and methods of the base class. Besides this, it is possible to enhance the derived class to contain more functionality by adding properties and methods. As a simple example of the application of inheritance, let us take a ‘base data frame’ wherein the payload size has been confined to be less than 100 bytes. Now by extending the ‘base data frame’, we can override these payload constraints to make the payload greater than 100, or empty or even tamper with the error detection codes in order to test some corner case scenarios. Hence in order to verify such corner case scenarios, one does not need to ‘reinvent the wheel’ by rewriting a whole lot of code like in procedural programming. ‘Inheritance’ thus helps in ‘reuse’ as the ‘original’ code does not need to be modified and it also helps to accelerate verification as only ‘additional logic’ needs to be written to reflect design enhancements/upgrades.
Here Base_packet is defined in a way such that all the ‘public’ methods defined in it and can be used by its derivatives are declared as ‘virtual’. In this case, despite Base_Packet being an ‘abstract’ class it still can be used to declare a variable bp that can store pointers to derived class objects.
Polymorphism
The word Polymorphism is derived from a Greek word ‘poly’ that means many and ‘morph’ means form. So, polymorphism is a concept wherein one piece of code can be extended to assume many different forms. By means of ‘polymorphism’, it becomes possible to access the subclass methods using the superclass handle, provided those methods have been declared as ‘virtual’ in the superclass. Hence even if there are multiple extensions (read variations) of this superclass, the interface can be the superclass handle (since it can point to the extended class memory) and that can remain constant. This promotes reusability of code as only the ‘extended’ class needs to be defined, no change is required in the test bench code.
In the figure above, the ‘Base_Packet’ is the base class, while ‘Ether_Packet’ and ‘Token_Packet’ are its extensions. By using the principle of polymorphism which allows a superclass handle to hold subclass object, we can simply assign the extended class object to the base class handle here in order to construct a packet array of different packet types. Now if there are changes in the specifications and it demands an additional type of packet to be driven to the DUT, then, in that case, the only modification needed is a new packet ‘definition’. The higher layers remain blissfully unaware’ as the external interface which is the handle of the base class remains the same. A large part of the code remains unchanged if one deploys ‘Polymorphism’, hence promoting code reusability.
Summary
Technological advancements have never happened overnight, just as Rome wasn’t built in a day. It took years of research, experiments and innovative approach to discovering something revolutionary. SystemVerilog that is now a highly popular and used Hardware Verification Language (HVL) too hasn’t sprung overnight, nor have the underlying principles been an ‘unknown’ territory for engineers. The interesting part of SystemVerilog is that it takes the best of three worlds; Verilog, VHDL and OOPS. It is often called Super Verilog and it is not just a Hardware Verification Language, but also a Hardware Description Language (HDL) like VHDL and Verilog. A vast amount of useful features, functions and concepts are ingrained into this HVL that addresses all that a complex design verification process demands.
By ‘encapsulating’ data and the methods/procedures that work on it into a ‘class’, it not just gives a higher level of ‘abstraction’, but also ‘information hiding’ in a way. By a number of features inbuilt into it such as the semaphore and mailbox, the verification engineer does not have to worry about the ‘intricacies’ and ‘complexities’ of handling ‘interprocess synchronization and communication’ which otherwise would be a headache when multiple processes are involved. Thus ‘isolating’ the higher level details and keeping the simpler and useful information for the user, ‘abstraction’ really helps in accelerating the test bench building process. With concepts such as ‘inheritance’ and ‘polymorphism’ wherein, it is possible to add features to the ‘extended class’ besides inheriting the ones from the ‘base’ class, the headache of reinventing the wheel or rewriting a whole lot of code is given a miss. And with polymorphism, the ‘interface’ of an object can remain the same, no matter ‘how many versions’ of it are to be used/driven in the test bench. Thus keeping code modifications limited to coding extended classes and keeping the ‘higher level’ test bench code untouched. This also promotes reusability, speeds up test bench bring up and maintenance. Hence, with such ‘useful’ concepts in-built plus important features borrowed from Verilog and VHDL SystemVerilog, based verification is the ‘right’ choice to make.