-
The biggest advantage is that you can modify the behavior of task xyz() without modifying it in the base or child class. It is a big advantage as no one wants to fiddle with known good functioning code.
-
Consider a case where you are writing a base class which is going to be used by multiple test environment, and for each test environment a known part of the code, or a known function/task is going to change. The natural choice is to implement those change-in-every-case functions/tasks as callback method and let the user extend your base class with specifying only that part of the code which need to be changed in his case.
Callback is one of the major confusing point for a System Verilog learner. Many people have asked the same question in many forums, but the answer doesn't seems to satisfy fully the quest of the person who has raised the querry. I too had the same issue, but I learned it slowly in a hard way. I am presenting here a way in which if I had an answer, I would have learned faster.
We can pass data member to any function. Now consider a case where you are passing a function (say func1) as a data member to another function (say func2) and you get what is called callback. The reason why it is called callback is that the function func2 now can call anywhere in its code function func1.
In computer programming, a callback is executable code that is passed as an argument to other code. It allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer.
Note that SV doesn't give a straight-forward way of passing a function as argument for another function. But we can get the same result (almost we can say!) by using OOP. The idea is to describe all the functions (both func1 type and func2 type) in a base class (don't implement the funct2 kind of function and make them virtual for polymorphism), and then extend the class to a derived class where you implement the func2 type of function.
Example:-
class abc_transactor;
virtual task pre_send(); endtask
virtual task post_send(); endtask
task xyz();
// Some code here
this.pre_send();
// Some more code here
this.post_send();
// And some more code here
endtask : xyz
endclass : abc_transactor
class my_abc_transactor extend abc_transactor;
virtual task pre_send();
... // This function is implemented here
endtask
virtual task post_send();
... // This function is implemented here
endtask
endclass : my_abc_transactor
Now let me explain how it is going to work. The base class abc_transactor has 3 tasks, 2 of which are declared virtual and are not implemented. But they are being called from another task xyz() which is fully implemented. The unimplemented virtual task are called callback class.
The child class, which extends from the base class, implements the previous unimplemented tasks. It inherits the xyz() task from the base class and hence doesn't need to change it. By this we can inject executable code to a function without modifying it.
Now the next question is why is done. There are many reasons for it.
No comments:
Post a Comment
Please provide valuable comments and suggestions for our motivation. Feel free to write down any query if you have regarding this post.