Hello,
I am trying to create a base driver for my UVM that is capable of doing drive and handling reset in an easy way that is easy for developers. This base driver shall also permit extension, I mean, adding new functionalities to it should be easy. What I thought is to have the class parameterized for the type of transaction it has to drive to the virtual interface. This is pretty easy. The first problem I faced is when I need an interface type that is valid for every possible interface that I want to implement on my driver when extending the base driver.
// Note that this does not compile, it's pseudocode
class base_driver #(type T) extends uvm_driver #(T);
T trans; // Transaction
base_if_proxy if_proxy; // Base class for interface proxy
...
function void run_phase(uvm_phase phase);
do_all();
endfunction : run_phase
...
task do_all();
drive_as_usual();
do_something();
endtask : do_all
pure virtual task do_something();
endclass : base_driver
class specific_driver extends base_driver #(my_transaction_type);
specific_if_proxy s_if_proxy; // Proxy extending base_if_proxy
function void build_phase(uvm_phase phase);
if (!$cast(this.s_if_proxy, if_proxy)) begin // Get the specific proxy type!!!
`uvm_fatal(get_type_name(), "Fatal")
end
...
endfunction : build_phase
virtual task do_something();
s_if_proxy.wait_for_clock(); // Tasks implemented in the extended class of the proxy!
s_if_proxy.drive_random();
endtask : do_something
endclass : specific_driver
As you can see the problem is that I want to do a $cast in the build_phase of the specific_driver to have the specific class of the proxy for the driver that I am implementing. The cast could work like a charm if the specific proxy class wasn’t defined in the interface for the driver. How is it possible to solve this problem? Any approach?
To be honest, it is comoletely unclear to me what your needs are and why you are dealing with the proxies.
Why do you not use the standard approach, extending your driver from the base class uvm_driver?
In reply to Marc43:
To be honest, it is comoletely unclear to me what your needs are and why you are dealing with the proxies.
Why do you not use the standard approach, extending your driver from the base class uvm_driver?
Okay, I already have a UVM, which is composed of 12 sub-interfaces that communicate with each other if needed, more or less in a master-slave fashion. Now, I need a more sophisticated handle for reset than the one that I have implemented first. I want to create a base class for those drivers so I don’t have to change them manually one by one. This will also be great for the drivers that I will have to implement in the future.
Sorry, but it is confusing what you are writing. A reset should be handled by the same sequencer/driver as the common functionality.
I have a few questions with respect to your DUT.
You say you have 12 sub-interfaces. The components connected to are working like a master/slave configuration.
(1) are your so called sub-interfaces o09f the same type, having the same signals inside? The master-slave would require this.
(2) Your driver should handle also the reset functionality. You might have a reset task in the driver which ias called in the drivers run_phase when the reset sequence is executed.
(3) If you have a master/slave configuration you need only 2 different types of drivers, a master driver and a slave driver. And you might have more than 1 instances of these drivers types.
(4) Why do you believe you need to modify your drivers one by one?
In reply to Marc43:
Sorry, but it is confusing what you are writing. A reset should be handled by the same sequencer/driver as the common functionality.
I have a few questions with respect to your DUT.
You say you have 12 sub-interfaces. The components connected to are working like a master/slave configuration.
(1) are your so called sub-interfaces o09f the same type, having the same signals inside? The master-slave would require this.
(2) Your driver should handle also the reset functionality. You might have a reset task in the driver which ias called in the drivers run_phase when the reset sequence is executed.
(3) If you have a master/slave configuration you need only 2 different types of drivers, a master driver and a slave driver. And you might have more than 1 instances of these drivers types.
(4) Why do you believe you need to modify your drivers one by one?
(1) Maybe I confused the terminology of master-slave. In order to reduce complexity, I divided the interface of my DUT into sub-components, that’s it.
(2) Yes, I have a reset task that is different for each driver as it is implemented for a different sub-interface.
(3) Confused, already told you in (1)
(4) Because my drivers don’t have the reset task. I thought that it would be great to have a base class for each driver and the proxy to the base interface.
Without taking into account, why I decided to do this, do you think is possible to do what I am trying to?
If your sub-interfaces are different you need a specific reset task for each driver.
I do not see how you’ll benefit from a bas class common for all different drivers.
The common class is a template that implements the classic “fork join any” with the reset and the retrieve of the sequence. Then, I leave to the user extending the driver to implement methods drive() and reset(). I think you didn’t understand me.