Can I provide macro/reference as parameter for hierarchical access in testbench? (SystemVerilog) - system-verilog

I have some modules that I want to print some wires from in a PRINTER module. I have two different testbenches, which wraps these modules slightly differently, see code below. Is it possible to use the same PRINTER to print print_me_a and print_me_b using hierarchical references?
I know all the hierarchical references in the testbenches, and I know I could expand the PRINTER to instead take inputs and then connect relative references there, but hierarchical references inside the PRINTER are easier to expand if I want to add a lot of new prints, then I only have to change in the PRINTER.
Given the structure below I can't really utilize bind to make it work in both testbenches. I tried to instead of instance references use MOD_A.print_me_a and MOD_B.print_me_b, and that worked when I use VCS, but not in Questa, and I would like for the solution to work in both.
Is there any way to provide an hierarchical reference or name, or some macro, to the PRINTER as a parameter maybe, so that I can have the same code inside PRINTER for printing the wires in both testbenches? Or can I utilize some parameter which tells me which testbench the instance is used in to generate some different macros like `define MOD_A_DEF known_name_wrap_a.known_name_a for later common usage in PRINTER?
module MOD_A();
wire print_me_a; // I want to print this
endmodule
module WRAP_A();
MOD_A known_name_a();
endmodule
module MOD_B();
wire print_me_b; // I want to print this
endmodule
module TOP_MOD();
WRAP_A known_name_wrap_a();
MOD_B known_name_b();
endmodule
module PRINTER();
// Pseudo code, can I access these with hierarchical ref?
$display(known_name_wrap_a.known_name_a.print_me_a) // Only works in TOP_TB
$display(known_name_a.print_me_a) // Only works in OTHER_TB
$display(known_name_b.print_me_b); // Happens to work fine in both
endmodule
module TOP_TB();
TOP_MOD top_mod();
bind top_mod
PRINTER top_tb_printer();
endmodule
module OTHER_TB();
MOD_A known_name_a();
MOD_B known_name_b();
PRINTER other_tb_printer();
endmodule

You could use ports in your PRINTER module and connect them with relative hierarchical references.
module PRINTER(input wire a,b);
initial $display(a);
initial $display(b);
endmodule
module TOP_TB();
TOP_MOD top_mod();
bind top_mod PRINTER top_tb_printer(
known_name_wrap_a.known_name_a.print_me_a,
known_name_b.print_me_b
);
endmodule
module OTHER_TB();
MOD_A known_name_a();
MOD_B known_name_b();
PRINTER other_tb_printer(
known_name_a.print_me_a
known_name_b.print_me_b);
endmodule

Related

packages declared inside system verilog interface

Is it possible to define a package inside of a SystemVerilog Interface?
example:
interface my_ifc();
package a;
logic reset;
logic clk_usb;
endpackage
logic Rwn;
logic [7:0] Addr;
endinterface
No. A package must be declared outside of any other nested scope (at the compilation unit level)
Package is a way to share code between modules, interfaces and programs in SystemVerilog. In your case, you could create a package outside the interface and then just import whatever you wish inside the package, in order to be made visible. Like this:
import a::*;
But the package, written inside the interface, is of no usefulness.

how to connect DV code embedded inside an RTL module to the testbench

I have to embed DV code inside an RTL module for verification purposes. There are many (1000s) of instances of this RTL module. How do I make it controllable on a per instance basis from the test? Testbench is in SystemVerilog UVM. I want to stay away from CDPI?
Any suggestions would be appreciated
-Hawki
You use the bind construct to insert a module or interface into your RTL module. Inside this bound module you construct a class with methods that interact with your RTL module. The class object is set into the uvm_config_db for each instance. Then your testbench gets these objects from the uvm_config_db and you can call those object methods from the testbench.
I wrote a DVCon 2012 paper The Missing Link: The Testbench to DUT Connection with a complete example for doing this.
As Dave described in his answer, bind statements are usually the best way to go.
Though there are other ways as well, which might be more convenient in some cases. They are based on parameterized modules.
1) direct instantiation with parameters
module rtl #(bit dvflag = 0) ();
...
if (dvflag)
dv_module dv_instance(...);
...
endmodule
module dut;
rtl rtl1();
rtl #(.dvflag(1)) rtl2();
...
endmodule
2) Overwriting instances with v2k config statements.
module dut;
rtl rtl1();
rtl rtl2();
endmodule
...
config dv_cfg;
instance dut.rtl2 use #(.dvflag(1));
...
endocnfig

Disable the instance of DUT from Test-bench

Please help to resolve one issue that I am facing connected with disabling DUT instanced.
My DUT top module has many instances in it, but my test does not need them.
Is there any way to disable these instances from test-bench.
For example this is my DUT module prototype:
module top (…….);
// instances needs to be disabled
module1 #(16) inst1 (.CLK(clk_100),.PAD_RSTN(ext_reset_n),.RSTN(global_reset_n));
module2 #(16) inst2 (.CLK(clk_100),.PAD_RSTN(ext_reset_n),.RSTN(pcie_reset_n));
pcie_module #(…) inst_pci (…..);
// main test target instances
target_testmodule #(…) test_inst(…);
child1_of_target_testmodule #(…) test_inst_child1(…);
child2_of_target_testmodule #(…) test_inst_child2(…);
endmodule
so my test-bench will only test the target_testmodule and its child modules.
I am using bind to connect the interface to target_testmodule and then starting to drive the pins of target_testmodule. And the target_testmodule drives its child module pins.
So for this test I don’t need pci_module instace or other instaces, because they are big instances take much time, provides lots of warning and also they drive some of the target_testmodule ports which I don’t neet.
My question is there some mechanism to disable the pci module from the test-bench. I don’t have write permission to top module to comment the instances or put them inside `ifdefs.
Your first mechanism is to ask the person who locked the file to change it so you can get your job done more efficiently. They can put in generate or ifdef statements for you.
If you had separate clock or enables signals, you could force them to an inactive state
copy and modify a local copy of the top-level file and have that file used instead. The are a number of ways to substitute the local module
Beyond getting write permission, the next easiest way would be to make you own top.
Verilog (since IEEE1364-2001) and SystemVerilog do have a way to compile different modules of the same name into different libraries, then use a configuration to decided which one will be used during elaboration. You could use this technique to use swap the module instances you don't want with simplified or dummy version. Depending your testing environment is configured, implementing this configurations can be tricky. If you are up for the challenge, then read IEEE Std 1800-2012 § 33. Configuring the contents of a design

Where should I put code instead of a top level testbench?

In my OVM testbench.sv, I have added code to the bottom of the module to force and release internal signals. However, this code takes up space. What options do I have for putting the code into a different file? Should I put the code in another .sv and bind it the testbench?
If you just want to hide this code from the top-level module, you could put it an include file to be `included by the top-level testbench module.
You could put your code in a separate top-level module. All of the hierarchical references to internal DUT signals would start from the other top-level module that instantiates the DUT.
You could also put your code into a module or group of modules and bind it into the DUT module. If you can separate your code into groups for different blocks within the DUT, then you can bind each module into that block. That will save you repeating the same hierarchical paths over and over.

When to use define macro vs generate

What are the guidelines for choosing generate statements over `define macros and vice versa in Systemverilog?
For example, if I want to conditionally instantiate either module1 or module2, it seems I can either do
`ifdef COND1
module1 ();
`else
module2 ();
or
generate
if (COND1) begin
module1 ();
end else begin
module2();
end
endgenerate
People will have differing opinions, but one big difference between the two is that generates allow different instances to be configured differently, but macros do not. This is because generates are evaluated at elaboration, rather than at compile time.
For example, if we have a module:
module ahwoogaa #(bit COND1) ();
generate
if (COND1) begin
module1 ();
end else begin
module2();
end
endgenerate
endmodule
I can instantiate that twice with COND1 like so:
module neeenaaaw();
ahwoogaa #(1'b0) alarm1();
ahwoogaa #(1'b1) alarm2();
endmodule
With a define you have to have a single value of COND1 for all instances, as you set the value once when you compile the module.
Personally I say go for generates whenever you can.
`ifdef can be used inside port lists:
module music
output [31:0] left,
`ifdef STEREO
output [31:0] right,
`enfif
...
Generate allows loops, instantiate X times
genvar inst;
generate
for (inst=0; inst<3; inst=inst+1) begin : gen_block
sub_module instancex( .clk, .din(din[inst]), .dout(dout[inst]) );
end
endgenerate
NB: this introduces an extra level of hierarchy (gen_block).
I'm assuming that the questions concerns conditional instantiation only.
We had similar dilemma some time ago, when our project, initially developed in order to be integrated into specific platform, had to be adapted for additional platform. We wanted to use IFDEFs/Generates for differentiating a single source code.
In my opinion:
1) IFDEFs look much simpler than Generates (and they really are), but they are dangerous. Use them only when you're completely sure that your conditional instantiation will be exclusive (see the answer by Paul S), you can't achieve the same functionality with generates, and you're completely sure you need this conditional instantiation. The usual place to use IFDEFs is in top hierarchies.
EDIT: there is another question on StackOverflow which is an example of struggling of verification engineer due to abuse of `ifdefs by some designer.
2) After I warned you with the 1 above, I can tell that IFDEFs has a huge advantage (as a result of them being pre-processed): you can conditionally instantiate nets, parameters and ports with IFDEFs. Compare the following use of IFDEF:
module module1 (
input in1,
output logic out1
`ifdef COND
, output logic out2
`endif
);
assign out1 = in1;
`ifdef COND
submodule submodule1(.in(in1), .out(out2));
`else
endmodule
and generate:
module module1 (
input in1,
output logic out1,
output logic out2
);
assign out1 = in1;
generate if (COND)
submodule submodule1(.in(in1), .out(out2));
else
assign out2 = in1;
endgenerate
endmodule
In the above (very simple) example, when COND is not true and you use IFDEF, you may not worry about driving "out2" - this port will not be present. As a downside, you'll have to use the same IFDEF when instantiating "module1".
The advantage of IFDEF may not be obvious in this example, but imagine that you have 100 ports (or nets) which connect some sub-module. If the sub module is not instantiated you'll have all these ports tied to some value when using Generate, but you can remove them with IFDEFs.
3) As Morgan mentioned, Generate introduces one extra level of hierarchy. While it is slightly irritating to see this in design navigator, it becomes a real pain in the #ss when you want to insert generates into existing code and there are tools which make use of paths to modules - you have to find all these tools and change hierarchy there.
4) I heard an opinion that IFDEFs "age" badly. It means that maintaining your code will be more difficult if you use IFDEFs over Generates.
Summary: after trying some time to differentiate our design with IFDEFs and Generates, we realized that it is not practical. Now we maintain two source codes in parallel - one for each platform. Use IFDEFs in top modules to remove/switch between modules and remove unnecessary ports and parameters. Use Generates when you want to use the same modules in slightly different parametrization. Do not use these constructs to apply major changes to your design.