Object-Oriented Programming Basic Concepts

introduction

 In the early days of software engineering, Epic struggled with project complexity, growth, and the challenges of managing large development teams. Object-Oriented Programming (OOP) introduced a revolution to the software community to help solve these problems. OOP focuses on modularity, change tolerance, code reuse, ease of understanding and distributed development. Most projects today use object-oriented concepts.

Since C++ introduced OOP, user experience has generated more knowledge about how to best utilize OOP. There's a lot of debate about object-oriented protocols and more. Which features should be encouraged? Does C++ define which functions are object oriented.

OOP is applicable as reusing and verifying IP becomes popular in hardware verification. In fact, functional verification provides ideal conditions for reuse, as standard protocols, systems and even tests and interesting transaction sequences utilize OOP.

Design large software applications

 Traditionally, programs are viewed as a collection of functions. This is fine for small applications, but prevents reusing a subset of the program or exploiting a distributed parallel development process where different engineers own different aspects of the program. So how do we design a large application? OOP recommends a "divide and conquer" approach, where an application is a set of related interacting objects. For example, an application that simulates traffic will involve cars, drivers, and traffic lights, and instead of designing an application for the entire traffic system, we should focus on separate modules to capture car, driver, and traffic light operations. The same goes for testbeds or validation projects. Instead of focusing on the complete application, we focus on the data items or protocol-specific components that ultimately make up the testbed.

What is an object in OOP?

 An object is an entity that has data and methods to operate on that data. Each object can be thought of as an independent little machine or role with different responsibilities. In our traffic simulation example, cars, drivers, and traffic lights are all objects.

 Distributed Development Environment

 One of the challenges of OOP is defining objects and the interactions between them. The initial agreement is the key to getting individuals and teams working together. These objects provide services through an agreed public interface (contract). Other objects can use this public API. Object internal implementation can be independently developed and improved. Languages ​​provide information hiding facilities to restrict objects from using public methods. The following diagram demonstrates two developers working in an OOP environment, using a protocol interface between separate objects.


                       OOP interface objects enable parallel development

separation problem

 Can we use the same object to create other systems? Or copy an object and use it for a different system? This requires the creation of separate objects. There should be no functional overlap between objects. For example, our traffic simulation example might also include a race track. On a typical track, there are no traffic lights, no turn signals, and the car is faster. If a car's implementation assumes the presence of traffic lights, it cannot participate in a track system without traffic lights. Likewise, a functional verification example can have a packet that should not be sent or submitted to a specific protocol/driver by itself. If so, it cannot be used in environments that require different driver protocols or protocol layering.

 Classes, Objects and Programs

 A class defines the abstract characteristics (properties) and behavior (methods) of an object. This is a blueprint that allows the creation of one or more objects of the same type. For example, there might be a car class that defines everything a car object can contain. Then, a special car, say... Plorsche, is a subclass (specialization) of the car class, with special properties that go beyond the normal car class. Finally, a car object is a specific instance of a car with a specific color and engine properties, such as a silver Plorsche coupe. There may be many Plorsche cars sharing these properties; all of them would be objects of a Plorsche subclass or car specialization.

Objects hold runtime data and are used as building blocks for programs. A program or application instantiates objects and triggers their interaction.


 Note: SystemVerilog classes are not the same as dynamic Verilog module instances. Module instances, their numbering and hierarchy are created when elaborated in Verilog and are static throughout the simulation. Objects can be created on request at runtime. This allows the creation of modular and optimized data structures. In functional verification, the testbench build process is dynamic, which makes it more flexible. It uses program flow control to instantiate the required testbench structure. Dynamic objects are used to represent data items (such as packets, frames, or transactions) as needed, and usually take into account other environment variable values

 Using generalization and inheritance

 Humans use generalization to perceive the world. The abstract concept of a car means: four wheels, an engine, at least two doors, a steering wheel, etc. This ability to abstract allows us to organize data and enable effective communication. For example, you can say "I drove my car to work yesterday" and the audience doesn't need you to define a car, talk about the specific car you drive, or the way you drive it. These details are not necessary to understand the intent of your simple statement

 Object-oriented programming enables us to do the same in software design. You can define the concept of a generic class and use inheritance to create a specialization of that abstract class. The sports car could be a specialization of the GM concept. In addition to having all the attributes of a car, it has more horsepower, better handling, and often draws attention. The user can express the desired function - for example, drive() a car - without knowing the specifics of the driving style in a particular car.

Using inheritance allows objects with sufficiently similar interfaces to share implementation code. A parent class that should never be instantiated - meaning it is only used for modeling purposes for reuse and abstraction - is declared as a virtual class.


Create compact reusable code

 If you have overlap between objects, consider creating an abstract class to hold common functionality and deriving a class to capture variants. This will reduce the amount of code required for development and maintenance. For example, request and response packets may have similar properties, but the data generated in the request is collected in the response, and vice versa.



Polymorphism in OOP

 A program may need to manipulate a set of objects in a programmatic manner. For example, you might want an abstract handle to a car and call the run() method of all cars in the array in a loop. Each car class has a different implementation of the run() method. The ability to perform a run() on an abstract class and perform a specific run() is called "polymorphism". The programmer does not have to know the exact type of the object in advance. Example 3-2 below demonstrates how the Plorsche and Flerrari cars are derived from an abstract sports car class. Polymorphism allows the program's print() task to hold a pointer to a virtual class array that may contain Plorsche and Flerrari cars, but execute the correct print() function for each item

 Example 3-2 Inheritance and Polymorphism


Downcast

 Imagine a new vehicle is invented that has the ability to fly, while other vehicles cannot. A car user doesn't want to find out that their car can't fly after driving over a chasm. Advance warning is required before you start driving to ensure your car can fly. In this case you need to get a compile-time error message before the simulation starts. For example, you don't want an illegal assignment to break the simulation after two days of execution. The compiler forces the user to explicitly downcast a generic reference before using one of its subtype traits or properties. (The term downward means descending in the inheritance tree.)

Note: In our car example, the user needs to explicitly declare the pointer to hold the car with the fly() method. Assigning a generic handle to a specific handle is called downcasting.


class library

 A class library is a collection of classes used to speed up system implementation. Users can derive new classes from library classes by customizing them, or just instantiate and use them instead of implementing them from scratch. Examples include math libraries, graphics libraries, and even verification-oriented libraries. UVM has a class library. An important advantage of a class library is that it codifies best practices and enables standardization and reuse. The disadvantage of using a class library is that you need to learn the class library specification. While a class library comes with an API specification, it's a good practice to implement and understand the functionality and recommended implementation through the class library.

static methods and properties

 Objects have properties that hold their specific data and state. For example, a Plorsche state can be "driven", while a different Plorsche can be "parked". However, SystemVerilog supports static properties that belong to a class rather than a specific instance. These properties can be accessed even if no instance exists, and allow multi-instance subscriptions and settings. For example, you can use a static property to count the number of instances of a particular class. You can also have static methods that can manipulate static properties. Static methods cannot access non-static properties because those properties may not exist.

Calling a static method does not involve a specific instance and can be achieved by using class_name::method_name(). For example, we can use a car static method like this: car::increment_counter()

parameterized class

 Parameterized classes are used when similar logic is required for different data types or sizes. The classic usage of parameterized classes applies to containers. The following examples show containers for different types of objects.


packages and namespaces

 A typical application utilizes many classes from multiple sources. It is possible that some type, class or function names may collide and cause compilation errors. Modifying class and type names for uniqueness can be costly. Furthermore, this problem is more challenging when using encrypted code such as Verified IP (VIP).

To avoid global namespace collisions, object-oriented languages ​​add package or namespace capabilities. This creates a different scope for each package definition. In the absence of conflicts, the user can use the import command to import all definitions into the federated namespace. If there is a conflict and it is not possible to include an import, the user can import a specific type or use the fully qualified type name of the class (a combination of the package name and the class name).

For example, suppose that in our system, two types of car categories (sports_car) are developed, one is brand A and the other is brand Z. Without the package, the two categories are called "sports_car" (from brand A and one each for brand Z) cannot be compiled

In the following example, we import the package into a single module scope. This is possible because there is no conflict with the name within the package. You can import all symbols in the package, or use only selected symbols that do not collide.


 It is critical to use packages for all reusable code to coexist with other similar classes in other packages and to prevent code modification.

software design patterns

 Creative solutions to software problems can have random benefits and consequences. Also, proven solutions can yield more consistent results. We are not against creativity, but most verification challenges require creativity and common sense without reinventing the wheel. Design patterns are general repeatable solutions to common problems in software design. The book "Design Patterns: Elements of Reusable Object-Oriented Software" (often referred to as the "Gang of Four" or "GoF" book), published in 1995, coined the term design pattern and became a great source for object-oriented software, oriented toward Design theory and practice. These best known practices are captured in templates containing names, challenges, code samples, and more. For more information, read the book "Design Patterns: Elements of Reusable Object-Oriented Software" by Gamma, Helm, Johnson, and Vlissides.

Software Design Patterns: Singleton Pattern

Many systems require that system resources should only be instantiated once. This could be a memory manager, global coordinator or other system level coordinator. The question is how to create a class with a built-in restriction that it can only be instantiated once? The singleton solution works by making the constructor dedicated to the class, preventing the class from being instantiated. The only way to instantiate a class is to call a static method, which on first call allocates a local instance of the class and returns the caller's object handle. Successive calls to this static method will return the instantiated instance handle without allocating a new class. An example of a singleton in the UVM library is reporting that the server has a protected constructor to limit the creation of the server to a single instance

software design anti-patterns

 Anti-patterns, also known as pitfalls, are often a complete overhaul of a bad software solution to a problem. The term was coined by Andrew Koenig in 1995 and was inspired by the Gang of Four. There are many reasons for using bad practice. In some cases, it involves a lack of planning; in others, using the perfect solution in the wrong situation makes it counterproductive. Like design patterns, anti-patterns have formal templates, their names, whys, meanings, and more. Anti-patterns also include the practice of recovery processes (refactoring) to patch misuses. An example of an anti-pattern is "spaghetti" code - source code, which has complex and tangled control structures. For more information, read the book "AntiPatterns: Software Refactoring, Architecture, and Projects in Crisis" by Brown, Marley, McCormick, and Mowbray

Why Are Existing Object Oriented Methods Not Enough?

 Mentioned above are some of the books that document the accumulated and proven experience in object-oriented programming over the years. So why do we need more methods? Most general concepts apply to functional verification tasks and are valid. But functional verification introduces unique challenges and is different from software development. Contrary to programs that are released every six months, the results of functional verification are final tests, several of which may be created within a day. Consider the testbench in the image below and the three tests that use it. Each test involves a different aspect of the testbed. It may change configuration, introduce different sequences, use constraints on generated data items, etc. to achieve its goals. Object-oriented programming is not for such extreme reuse, nor does it allow for the openness of classes to be further modified by testing.


Aspect Oriented Programming

 More recently, software design patterns have been criticized for suggesting complex recipes rather than improving tools or languages. OOPSLA (Object-Oriented Programming, Systems, Languages, and Applications), an annual ACM conference held primarily in the United States, hosts a group called the "Gang of Four" experiment. Verisity introduced the e language to solve verification challenges and use this built-in solution instead of design patterns. Aspect-oriented programming provides a simple solution to many of the limitations of the SystemVerilog language, building on the aspect-oriented feature, which is a superset of object-orientation. In SystemVerilog UVM we use factory solutions, callbacks, field macros, configuration mechanisms and more. None of these are required. In addition, e allows additional features such as coverage and enumeration type extensions, more powerful modeling capabilities for data item randomization, and other language features that significantly simplify verification tasks. The industry has made some efforts to provide limited AOP extensions to other HVLs, but these extensions are limited and the challenges and solutions are not understood. We can only hope that SystemVerilog will at some point adopt these features and simplify verification for the benefit of the SystemVerilog user base

Overview

 Object-oriented programming introduces a way to deal with the complexity of large software applications. It focuses on modularity, adaptability to change and reuse, which are key to functional verification. Knowing the theory and motivation is beneficial, but it is not necessary to master the theory in order to use the UVM library. One of the advantages of using the UVM library is that it codifies the best verification practices into the library base classes, enabling you to follow the recommended directions to do the right thing

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325855545&siteId=291194637