object-oriented programming
- object-oriented programming
summary
Object oriented programming (OOP) enables users to create more complex data types and combine them with the use of these data types
The program is closely combined. Users can build test platforms and system models at a more abstract level. By calling a function
Realize the change of level. Use transactions instead of flipping signals. Separate the test platform from the details and increase the maintainability of the system.
Consider nouns instead of verbs
The purpose of the test platform is to motivate the design. Then check whether the result is correct. We distinguish between the operations of traditional test platform construction: creating a transaction, sending, receiving, checking results, and generating reports.
However, in OOP, we need to reconsider the construction of the test platform and the functions of each part.
- Generator: creates transactions and passes them to the next level
- Driver: conversation with design
- Monitor: the transactions returned by the design will be captured by the monitor
- Scoreboard: compare the captured data with the expected data.
Therefore, the test platform is divided into multiple blocks, and then the communication between them is defined.
Write the first class
What we learned earlier is to define a more complex data type. The class encapsulates data and subroutines that operate on these numbers. Examples are as follows:
class Transaction; bit [31: 0] addr,crc, data(8]; function void display; $display("Transaction: 3h", addr); endfunction : display function void calc_crc crc=addr^data.xor; endfunction : calc_crc endclass: Transaction
Add: to make it easier to score and align the beginning and end of a block, you can put a label at the end of the block. In many cases, these marks can easily distinguish the end. For example: endtask, endfunction, endcallss
OOP terminology
1) Class: the basic building block that contains variables and subroutines.
2) Object: an instance of a class.
3) Handle: pointer to the object.
4) Property: a variable that stores data
5) Method: procedural code that operates variables in a task or function.
6) Prototype: program header, including program name, return type and parameter list. The program body contains the execution code.
Create a new object
The class of System Verilog is created when needed during program execution. All classes should be instantiated before use. After instantiation, a certain memory space will be opened up.
Transaction tr;// Declare a handle tr = new(); //A Transaction object allocates space
When declaring a handle, it is initialized to the special format null. Next, when new() is called to create a Transaction object, the nwe function allocates space for it and initializes the variable to the default value. The binary variable is initialized to 0 and the Quaternary variable is initialized to X. We call new the constructor. No return value. When instantiating a class with new, you can specify an initial value for the variable. The method is as follows:
class Transaction; logic [31: 0] addr,crc, data[8]; function new(logic [31:0] a=3,d=5); addr = 1; foreach(data[i]) data[i]=d; endfunction : new endclass: Transaction initial begin Transaction tr; tr=new(10)//data defaults to 5,
Create a handle for the object
First, distinguish between objects and handles. A handle can point to many objects.
Transaction t1,t2;//Declare two handles t1=new();//Assign an address to the first Transaction object t2=t1;//Two handles point to an object. It can be understood that two pointers point to the same memory space t1=new();//Assign an address to the second Transaction object. Since t2 is still the first object, t1 points to a new object
The specific mapping relationship is shown in the figure below
Handle and object are distinguished by the above examples. Object can be understood as a memory space applied to the system. The application method is guaranteed by handle. Here, the handle is equivalent to the search and use of an object. Once an object has no handle to point to, the space of the object will be released.
Deallocation of objects
Examples are as follows. When an object is no longer referenced, there is no handle to it.
Transaction t;//Declare a handle t=new();//Assign an address to the first Transaction object t=new();//This is to recycle the first space and open up a new address space at the same time t=null;//Release the second allocation to free up space
Use object
Assuming that an object has been assigned, the next step is how to use the object. You can use. To reference subvariables and subroutines.
Transaction t;//Declare a handle t=new();//Assign an address to the first Transaction object and create an object t.addr=32'h32;//Set the value of the variable t.display();//Call a subroutine
Static and dynamic variables
Each object has its own local variables that are not shared with any other object. However, if a certain type of variable needs to exist and be shared by all variables, a global variable needs to be created.
Simple static variables
In System Verilog, you can create a static variable in a class that will be shared by all instances of the class. However, the scope of its use is limited to only one class. In the following example, the static variable count is used to protect the number of objects currently created. It is initialized to 0 when declared. After that, every time a new object is built, it is marked as a unique value. At the same time, the value of count is increased by 1.
class Transaction; static int count=0;//Number of objects created int id://Unique identifier of the instance function new() id= count++;//Set the flag and count is incremented endfunction endclass : Transaction Transaction t1,t2; initial begin tl=new();//First instance, id=0,count=1 t2=new();//The second instance id=1, count=2 end
A class should be as self-sufficient as possible when it intends to create a global variable. First of all, we need to consider whether creating static variables of a class can solve the problem. For a class, the fewer external variables applied, the better.
Access static variables by class name
A new method of accessing static variables is introduced here. Instead of using a handle, this method uses class_name:: class scope operator.
class Transaction; static int count=0;//Number of objects created ... endclass Transaction t; initial begin Transaction t; run test(); $display("%d transaction were created",t.count);//Use handle to reference static handle $display("%d transaction were created",Transaction:: count);//Reference static handle end
Initialization of static variables
It is usually initialized at the time of declaration. Static variables are usually initialized when declared. You can't simply initialize static variables in the constructor of a class, because every new object will call the constructor. You may need another static variable as a flag to identify whether the original variable has been initialized. If you need to do a more detailed initialization, you can use the initialization block, but make sure that the static variables are initialized before the first object is created. (to be supplemented)
Static method
(to be supplemented)
Class method
Programs in classes are also called methods. That is, the task or function defined in the scope of the class.
class Transaction; bit [31: 0] addr, crc, data[8]; function void display (); $display("@%0t: TR addr:=%h,crc=%h", stime,addr,crc); $write ("\tdata [0-7]="); foreach (data[i]) $write(data[i]); $display (); endfunction endclass class PCI_Tran; bit [31:0]adx,data;//Use real names function void display(); $display("@%0t: PCT:addr=%h,data=%h", $time,addr,data); endfunction endclass Transaction t; PCI Tran_pc initial begint new();//Create a Transaction object t.display();//Method calling Transaction c=new();//Create a PCI transaction pc.display();//Method of calling PCI transaction end
Define methods outside the class
SV allows you to declare examples outside a block. Use the keyword extern. Examples are as follows
class Transaction; bit [31: 0] addr, crc, data[8]; extern function void display (); endclass function void Transaction::display (); $display("@%0t: TR addr:=%h,crc=%h", stime,addr,crc); $write ("\tdata [0-7]="); foreach (data[i]) $write(data[i]); $display (); endfunction class PCI_Tran; bit [31:0]adx,data;//Use real names extern function void display(); endclass function void PCI_Tran::display(); $display("@%0t: PCT:addr=%h,data=%h", $time,addr,data); endfunction
Scope rule
A scope is a block of code. For example, a module, a program, task, function, class, or begin end block. Each scope uses the variables defined under its scope.
this
When you use a variable name, system Verilog will first look in the current scope, and then look in the upper scope until the variable is found. This is also the algorithm used by Verilog. But what if you want to explicitly reference class level objects in the deep underlying scope of a class? This style of code is most common in constructors because programmers use the same class variable name and parameter name. The keyword this can realize this function.
class Scoping; string oname; function new ( string oname ) ; this.oname = oname // Class variable oname = local variable oname endfunction endclass
You can use another class in a class
class Transact⊥on; bit [31: 0] addr, crc, data[8]; Statistics stats;// Statistics handle function new(); stats=new();//Create stats instance endfunction task create packet();//Populate package data stats.start()//Transmit packet endtask endclass
Remember to instantiate the object, otherwise the handle stats is nu11 and the call to start will fail. This is best done in the constructor of the upper layer, the Transaction class. This involves the compilation order. Sometimes you need to compile a class. This class contains an undefined class. The handle to the contained class will cause an error. In this case, you need to use typedef to declare a class name.
typedef class Statistics; class Transaction; Statistics stats; ... endclass class Statistics; ... endclass