Erling Posted May 19, 2011 Report Share Posted May 19, 2011 When importing a class from a package, do other classes in that package need to be loadable at point of import? Say I have a driver and a monitor in a package, both components originally written to operate on the following interface: interface MyIf; logic any; endinterface What I want to do is to import the monitor only, and have it operate on a modified version of the interface: interface MyIf(input logic any); endinterface The simulator I am using does not allow this, because the driver isn't loadable with the modified interface. This seems to be irrelevant, since the driver isn't referenced in the importing context. Is the simulator in error or is the behavior to be expected? Regards, Erling Quote Link to comment Share on other sites More sharing options...
jadec Posted May 20, 2011 Report Share Posted May 20, 2011 I'd expect that. A package is a compiled unit. If the package cannot elaborate that's an error. It doesn't matter how little of the package you intend to reference. Quote Link to comment Share on other sites More sharing options...
dave_59 Posted May 20, 2011 Report Share Posted May 20, 2011 Although you didn't mention it, I assume that your problem is because both driver and monitor class are referencing the same virtual interface. Unless the compiler has some very sophisticated dead code analysis, it not going to know that that your driver is not going to be used - especially if the driver is registered with the factory. I'll use this as another plug to get people to think about using abstract classes instead of virtual interfaces to connect to the DUT. See the following papers http://www.dvcon.org/2010/proceedings/papers/06_1.pdf http://www.dvcon.org/2011/proceedings/papers/01_4.pdf http://ovmworld.org/forums/showthread.php?100-OVM-wrapper-for-Verilog-Bfms&p=350#post350 Dave Rich Quote Link to comment Share on other sites More sharing options...
Erling Posted May 23, 2011 Author Report Share Posted May 23, 2011 I'll use this as another plug to get people to think about using abstract classes instead of virtual interfaces to connect to the DUT. See the following papers Dave Rich In what way would abstract class interfacing help? The workaround I am using right now is to keep components in separate files, and then use include-statements to compose or rearrange packages. Hardly elegant, but it works. With abstract class interfacing there will be even more components and layers to think about, and I would not know how to put it in a package to be reused easily in another context. Regards, Erling Quote Link to comment Share on other sites More sharing options...
dave_59 Posted May 23, 2011 Report Share Posted May 23, 2011 In what way would abstract class interfacing help?Because it is a more elegant solution. This is a standard OO programming patern and it means you don't have to have an RTL interface around if you don't need it. Quote Link to comment Share on other sites More sharing options...
Erling Posted May 25, 2011 Author Report Share Posted May 25, 2011 Because it is a more elegant solution. This is a standard OO programming patern and it means you don't have to have an RTL interface around if you don't need it. The solution is more elegant, but it seems to come with its own set of problems. A driver, for example, will not have access to the dut-pins, and there will be a level of indirection. The driver will either have to forward all transactions to the interface class or there will be a job division between the driver and the interface helper class, which means that driver functionality will have to be maintained in two places. Also, the handle to the helper class in the interface still has to be distributed via the config_db, just like a virtual interface. It seems that slightly modified component relationships will enable component placement in such a way that there is no need for an explicit interface handle, neither virtual nor abstract. What follows is probably trivial, so for what it's worth, consider this driver: class MyDrv extends uvm_driver #(MyItem); function new(...); task run_phase(...); endclass: MyDrv The inherited infrastructure is obviously needed by the agent to create and connect MyDrv, but the run_phase does not have to be here, it is virtual and can be placed elsewhere. So the driver (and monitor/etc that need pin-access) can be split in two, with the base class in a package and the actual implementation in an interface (or module), for example: package MyPkg; class MyDrv extends uvm_driver #(MyItem); function new(...); endclass: MyDrv endpackage: MyPkg interface MyIf; // pin signals here import MyPkg::*; class MyDrvImp extends MyDrv; function new(...); task run_phase(...); endclass: MyDrvImp endinterface: MyIf The is-a relationship between the MyDrv and MyDrvImp allows factory override for MyDrv so that the (unchanged) agent, when creating MyDrv, actually creates an instance of MyDrvImp: module top; initial factory.set_type_override_by_name("MyDrv", "MyDrvImp"); endmodule: top With this arrangement, every vif.signalName in the driver run_phase can be replaced with signalName, and the interface can be replaced with a module to have the compiler locate all instances of virtual interface distribution, since this is not needed anymore (and can't compile with a module). The result is a 100% interface free testbench held together by uvm as usual, it's just that the low level activities have been moved to the machine room, while the rest of the testbench is on the bridge directing operations. Experiments seems to indicate that it is surprisingly simple to convert an ubus-like testbench to a world without interfaces with this method, but there may be issues that I have overlooked. One problem could be name clashes when removing the vif qualification in the low level tasks. Regards, Erling Quote Link to comment Share on other sites More sharing options...
dave_59 Posted May 25, 2011 Report Share Posted May 25, 2011 Erling, I like your solution. What you have just described is essentially making MyDrv an abstract class without explicitly using the keyword "virtual" in front of the class declaration. In both cases you have to extend MyDrv to get a working driver implementation. Adding "virtual" to the class means that the compiler could check that it was never constructed directly, but then you would not be able to register it with the UVM factory. The other thing it does is keep all the signal and timing related references inside the interface or module where the class is declared. This eliminates all the indirect references that normally would be through a virtual interface reference. Dave Quote Link to comment Share on other sites More sharing options...
Erling Posted May 27, 2011 Author Report Share Posted May 27, 2011 Erling, I like your solution. What you have just described is essentially making MyDrv an abstract class without explicitly using the keyword "virtual" in front of the class declaration. In both cases you have to extend MyDrv to get a working driver implementation. Adding "virtual" to the class means that the compiler could check that it was never constructed directly, but then you would not be able to register it with the UVM factory. And, if virtual, the class definition would not fix the original problem, i.e my package would not elaborate. There is one issue to think about, though. The solution does not work as is if an interface is intantiated multiple times, because there will be multiple factory registrations with the same name. First try in order to fix this was to copy the %m trick from your abstract sample code. That didn't work, however, because there is a parameterized driver now in the interface, thus %m isn't available in the class. It is available in the enclosing module, though, but %m would add hierachical paths, and that was not according to plan. The solution I came up with for this problem was to add a localparam string suffix to the interface (or module), and then create unique names for classes in the interface by appending the suffix to the class name for each factory registration. For a single interface application, the suffix can be empty, and things will work as before. When instantiating multiple interfaces, the suffix has to be set to something unique, for example, in a generate loop, the suffix can be a string representation of an interface index parameter, and the class names will be "MyDrvImp[0]", "MyDrvImp[1]" and so on, and these names can either be used to add instance overrides to the factory, or used directly with create_component(...) in a loop instantiating components in the interface. Thus hierarchical paths is not required, but it seems to be a good idea to think about how to name things for ease of reuse. Other than that, no problems so far. Quite the contrary, the solution works well and feels right from a software point of view. Regards, Erling Quote Link to comment Share on other sites More sharing options...
Erling Posted May 30, 2011 Author Report Share Posted May 30, 2011 Dave, You wrote (on the ovm forum) about a related issue that: "The only issue that may be tool dependent is that if you have a package with a class that registers itself with the factory, but that package is never imported, does the package exist? Depending on each tool's separate compilation flow, there may be different answers to that question." With "package is never imported", do you mean that there is a wildcard import, but nothing is directly referenced, for example: module top; import TestPkg::*; initial run_test(); endmodule and that the effect of this code is implementation defined? Regards, Erling Quote Link to comment Share on other sites More sharing options...
dave_59 Posted May 31, 2011 Report Share Posted May 31, 2011 I mean any reference to a package by name implies that the package exists. The LRM says "The compilation of a package shall precede the compilation of scopes in which the package is imported." When you do a wildcard import, you have to look inside the package to build a list of candidates to imports, or identify collisions with wildcard imports from other packages. To do that, the package must exist. But what does existence mean to a simulation run? Certainly you have to compile it, but not everything you have ever compiled is included in a simulation run. Quote Link to comment Share on other sites More sharing options...
Erling Posted June 1, 2011 Author Report Share Posted June 1, 2011 ... but what does existence mean to a simulation run? Certainly you have to compile it, but not everything you have ever compiled is included in a simulation run. No, but it seems static initializers have to be included even if nothing is actually imported from the package. The LRM says that "Variable declaration assignments within the package shall occur before any initial (and other) blocks are started, in the the same way as variables declared in a compilation unit or module". I find nothing in the LRM stating that such variables have to be referenced in any way to have the init happen. Factory registration uses static init, and one should therefore think that components in the package would be included in the simulation with a wildcard import alone, and that this is a portable solution. The alternative is including components explicitly with the preprocessor, but this seems to be a poor-man solution had the language not supported compiled packages. However, the ubus code (for example) does not package the test components, the source is included inside a module instead. There is perhaps a valid reason for this, I don't know. Regards, Erling Quote Link to comment Share on other sites More sharing options...
dave_59 Posted June 1, 2011 Report Share Posted June 1, 2011 Erling, If you do a wildcard import of a package, that package has to exist, and the static initializations inside that package must be executed. I believe that should be a portable solution. The question that usually comes up is what happens if I have a package with static init's and there is no mention of the package anywhere. Let's say there are two packages (A and with static init's in a single file. I compile that file, but only import package A. There is no reference to package B anywhere else in the design. Will the init's in package B get executed? That answer is tool flow dependent. With Questa, and other tools that support a separate compilation flow, the answer is the same as what happens with modules: a module will be loaded into a design if there is a reference to it and the module that references it contained in the design. As part of the elaboration step, you need to tell the tool the top-level modules and packages that should be loaded into the design, and it will recursively descend through the design to find the other packages and modules that need to be load in as well. Dave 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.