dudi Posted August 16, 2011 Report Share Posted August 16, 2011 Hello everyone, first post here I have a problem when using parameterized interfaces. My current solution is not very pretty, so I will appreciate your suggestions. I have a parameterized interface (and ofcourse a corresponding parameterized virtual interface). The problem is that in every place I create an instance of the vif, I must supply the parameters which forces me to make those classes (driver, monitor etc...) parameterized as well. I pretty much end with almost all classes being parameterized (since the agent must supply the parameters to the instances of the driver and so on). This is ofcourse not very elegant. Do you know of a good way to overcome this limitation? I can't use `define to pass the parameters since the idea is to later create multiple instances of the same agent with different parameters. Thanks for your help! Quote Link to comment Share on other sites More sharing options...
adielkhan Posted August 16, 2011 Report Share Posted August 16, 2011 Hi, I wrote an article on this a while back with a simple generic coding example using pure SV1800 code. Maximizing Reuse of Parameterized Interfaces within a Testbench However, personally I do not feel there is a truly elegant solution using just pure SV1800-2009 code. You can do some tricks like simplify the coding of the virtual interface by embedding it within the interface. interface bus_if #( BUS_WIDTH= `MAX_ADDR_SIZE ) ( input logic clock ); logic [bUS_WIDTH:0] addr; typedef virtual bus_if #(.BUS_WIDTH(BUS_WIDTH)) vif_t; endinterface // bus_if Somewhere, somehow you need to get the object-specialization into the object which wants to use it. adiel@synopsys.com Quote Link to comment Share on other sites More sharing options...
dudi Posted August 16, 2011 Author Report Share Posted August 16, 2011 Perhaps I'm missing something, but I can't see how using typedef helps in case of multiple instances with different parameters. Wouldn't it cause en error declaring the same typedef twice with different values? interface bus_if #( BUS_WIDTH= `MAX_ADDR_SIZE ) ( input logic clock ); logic [BUS_WIDTH:0] addr; typedef virtual bus_if #(.BUS_WIDTH(BUS_WIDTH)) vif_t; endinterface // bus_if module tb bus_if #(16) if1(clk); bus_if #(32) if2(clk); ... endmodule Quote Link to comment Share on other sites More sharing options...
uwes Posted August 17, 2011 Report Share Posted August 17, 2011 hi, type definitions are scoped. in that sense your examples declares the types bus_if#(16).vif_t and bus_if#(32).vif_t Quote Link to comment Share on other sites More sharing options...
dudi Posted August 17, 2011 Author Report Share Posted August 17, 2011 oops, my bad. The typedefs are indeed scoped, but I still need to parameterized all of the classes that require an instance of the virtual interface, except this time I'll need to give it a 'type' parameter of that virtual interface. I guess like previously mentioned, there is no elegant solution here... Quote Link to comment Share on other sites More sharing options...
jeff.schroeder Posted August 17, 2011 Report Share Posted August 17, 2011 I've run into this before myself, so I'll take a stab at it. I believe what you're looking for is polymorphic behavior from the virtual interface: There is some set of behaviors that all parametrized versions of bus_if share, and you want your driver, monitor, etc. classes to be able to use these common behaviors without caring about BUS_WIDTH. That way you don't have to parametrize your classes. Of course, interfaces are not classes and cannot use inheritance and polymorphism. What you can do, though, is to make a wrapper class for your interface and manually abstract the behaviors you want into the wrapper. Here is an example: `define MAX_ADDR_SIZE 64 interface bus_if #( BUS_WIDTH= `MAX_ADDR_SIZE ) ( input logic clock ); logic [BUS_WIDTH-1:0] addr; endinterface // bus_if virtual class bus_if_wrapper; pure virtual function int get_width(); pure virtual function logic [`MAX_ADDR_SIZE-1:0] get_addr(); endclass class bus_if_param_wrapper #(BUS_WIDTH=`MAX_ADDR_SIZE) extends bus_if_wrapper; virtual bus_if #(BUS_WIDTH) intf; function new(virtual bus_if #(BUS_WIDTH) intf_); super.new(); intf = intf_; endfunction virtual function int get_width(); return BUS_WIDTH; endfunction virtual function logic [`MAX_ADDR_SIZE-1:0] get_addr(); return {{`MAX_ADDR_SIZE-BUS_WIDTH{1'b0}}, intf.addr}; endfunction endclass module top; wire clk; bus_if #(32) if32 (clk); bus_if #(64) if64 (clk); bus_if_param_wrapper #(32) wrapper32 = new(if32); bus_if_param_wrapper #(64) wrapper64 = new(if64); initial begin bus_if_wrapper wrappers [] = '{wrapper32, wrapper64}; foreach (wrappers[i]) begin $display("width=%d, addr = %x\n", wrappers[i].get_width(), wrappers[i].get_addr()); end end endmodule Here the behaviors I abstracted are the ability to get the bus width and to get the address from the interface, zero-padded to the maximum address width in our system. Of course, if the behaviors that you want to access from your classes do depend on BUS_WIDTH, then you have no choice but to parametrize those classes. Quote Link to comment Share on other sites More sharing options...
mea1201 Posted August 17, 2011 Report Share Posted August 17, 2011 There is a DVCon 2011 paper titled "Parameters and OVM -- Can't They Just Get Along?" that addresses this issue in sections 6 and 7 (I didn't write it nor have anything to do with it). Hopefully, the link will take you to the 2011 proceedings archive, and this paper is under the UVM Applications session. The highlight is that you can greatly simplify maintenance of all these parameters up and down your class hierarchy by using some macros defined in a file that you include anywhere you require the parameter declarations or usage. The macros would provide symbols for the parameter declaration and the parameter mapping. So, you could have // -- File: params_defines.svh: `ifndef __PARAMS_DEFINES_SVH__ `define __PARAMS_DEFINES_SVH__ `define params_declare #(BUS_WIDTH = 32) `define params_map #(.BUS_WIDTH(BUS_WIDTH)) `endif Your interface and TB could look like `include "params_defines.svh" interface bus_if `params_declare (input logic clock); logic [BUS_WIDTH-1:0] addr; endinterface : bus_if module tb; bus_if #(16) if1(clk); bus_if #(32) if2(clk); endmodule : tb Your monitor, for example, could look like `include "params_defines.svh" class my_monitor `params_declare extends uvm_monitor; `uvm_component_param_utils(my_monitor`params_map) virtual bus_if`params_map vif; // -- Skipping rest of monitor... endclass : my_monitor Depending on how you set up the defines file, and use it throughout the class hierarchy in your testbench, you only need to maintain one file as opposed to many. Quote Link to comment Share on other sites More sharing options...
dudi Posted August 18, 2011 Author Report Share Posted August 18, 2011 Thanks for the replies! jeff.schroeder Using a class wrapper doesn't help, since the class it self is parameterized. Instanciating it in a monitor for example (and then using the config_db to get it) still requires passing the parameters. mea1201 I'm currently using something similar to what you suggest: `define my_monitor my_monitor#(DATA_WIDTH) Can't say I'm satisfied though, but it is a bit more elegant Quote Link to comment Share on other sites More sharing options...
dave_59 Posted August 18, 2011 Report Share Posted August 18, 2011 Dudi, If the API required to talk to the interface from the driver/monitor needs parametrization, like is the data bus 32-or 64 bits, there's no getting around the fact that both the driver and interface need to be fed the same parameters. However, if the communication between the driver and interface is independent of those parameters, there is a more elegant solution. Don't use virtual interfaces and stick with abstract classes. There are a number of papers describing this method starting with one I co-authored with Jonathon Bromley at DVCon 2008: "Abstract BFMs Outshine Virtual Interfaces for Advanced SystemVerilog Testbenches" Also Dvcon 2010: 6.1Coverage Driven Verification of an Unmodified DUT within an OVM Testbench And DVCon 2011: 1.4First Reports from the UVM Trenches: User-friendly, Versatile and Malleable, or Just the Emperor's New Methodology? Quote Link to comment Share on other sites More sharing options...
jadec Posted August 18, 2011 Report Share Posted August 18, 2011 If you need the interface to be parameterized, you can avoid parameterization of the rest of the environment by using the factory. Give your parameterized driver a non-parameterized base class and a non-parameterized item so the agent can instantiate it. Then use the factory to override the driver instance with the correct parameterized version. That way the parameterization is kept to a minimum. Quote Link to comment Share on other sites More sharing options...
pratta Posted August 19, 2011 Report Share Posted August 19, 2011 (edited) It isn't elegant, but I've overcome situations like this by creating a non-parameterized port handler class to define empty virtual methods to manipulate the interface. Then I create a parameterized extension of that class which implements those virtual methods to actually do stuff with the parameterized interface. The non-parameterized driver and monitor then create the non-parameterized port handler class and access the interface through those virtual methods. Then the port handler class can be replaced using the factory API with a correctly parameterized port handler class. Edited August 19, 2011 by pratta technical correction Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.