system verilog disabling `ifndef blocks in specific instances - system-verilog

In a system verilog design, I have a top-module, sub-module and a sub-sub module. sub-sub module instantiated in sub-module instantiated in top module.Top module also has an instance of sub-sub module.The hierarchy tree is shown below
The sub-sub module definition has some code written in a 'ifndef block like this
module sub_sub()
{
...........
`ifndef OFF
<code to avoid>
`endif
...........
}
How can I disable the code to avoid only in sub-sub module instance1 during compilation?
I used `define OFF in sub-module instance but it disables code to avoid from all instances.

The cleaner solution is to pass a parameter and use a generate-if/case statement. Example:
module sub_sub #(parameter OFF=0) ( ... );
generate
if (OFF) begin
<code to avoid>
end
endgenerate
endmodule
module sub ( ... );
...
sub_sub #( .OFF(1'b1) ) inst ( ... );
endmodule
module top ( ... );
...
sub inst0 ( ... );
sub_sub #( .OFF(1'b0) ) inst1 ( ... );
endmodule
Technically the the if (OFF) does not need to be in an explicit generate-endgenerate; it is inferred otherwise. It is recommended for human readability.
For full detail on generate blocks, refer to IEEE Std 1800-2012 § 27. Generate constructs

The scope of `define macros, and most other compiler directives is a compilation unit. A compilation unit is a stream of source text that a compiler parses. A macro gets defined at the point it appears in the compilation unit and is visible from that point onward.
The scopes defined by modules and other namespaces are irrelevant because macros are pre-processed before any Verilog or SystemVerilog syntax gets recognized. This means you can never have instance specific control over macro definitions.
If you want instance specific control over your code, you need to define parameters with instance specific overrides. Then you can use generate-if/case constructs to control the code you want to execute. If the generate construct is too restrictive for you, you can use procedural-if/case statements and optimization will remove branches not taken as a result of constant parameters.

The best way is to modify your sub_sub module using parameter as suggested in other answers.
However, this may not be practical if you can't edit/modify the sub_sub module, for example, it may be an encrypted IP.
In this case, one solution is to create wrapper nested module for each sub_sub module. You can do as follows:
// Wrapper for sub_sub with OFF defined
module sub_sub_wrapper1;
`define OFF
`include "sub_sub.v"
`undef OFF
endmodule
// Wrapper for sub_sub without OFF defined
module sub_sub_wrapper2;
`include "sub_sub.v"
endmodule
////////////////
module sub;
sub_sub_wrapper1 subsub1();
endmodule
module top;
sub sub1();
sub_sub_wrapper2 subsub2();
endmodule
Quick sample
In this case of course I am assuming you are able to edit your top and sub module. And just note that nested module is only supported in system-verilog.

Related

What does the notation "::*" mean in SystemVerilog?

This example was taken from a uvm_users_guide_1.1, page 27:
`timescale 1ns/1ps
package a_pkg;
class a;
function void f(inout time t);
t += 10ns;
endfunction
endclass
endpackage
program p;
import a_pkg::*;
...
endprogram
Is the :: the same as . ? And what does the * stand for?
Refer to IEEE Std 1800-2017, section 26.3 Referencing data in packages. The ::* syntax is a wildcard import, defined as:
A wildcard import allows all identifiers declared within a package to
be imported provided the identifier is not otherwise defined in the
importing scope
:: is the package scope resolution operator. * allows all identifiers to be imported, as opposed to explicitly name identifiers to be imported.
In your example, it allows access to the a class inside the p program.

passing generated modports to instances of the same module

I'm pretty sure there is no way to do what I am trying, but just in case there is an interesting clever solution, I thought I'd ask around. I have a parameterized SystemVerilog interface, inside of which I am generating modports
interface some_interface #(parameter NUM_READERS=3);
logic [`kBitsPerProgramCounter-1:0] read_addr[NUM_READERS];
logic [`kBitsPerProgramCounter-1:0] write_addr;
genvar i;
generate
// generates Reader[n].Modport
for (i = 0; i < NUM_READERS; ++i) begin : Reader
modport Modport
(
output .read_addr(read_addr[i])
);
end
endgenerate
endinterface
Using this is easy if I have different module types taking different modports. However, what I wanted to try doing is to have multiple instances of the same module. I tried this by parameterizing on type
module some_block#(parameter type SOMETYPE) (
input logic CLK200MHZ,
SOMETYPE aarrgghh);
But getting it to work syntactically has been challenging. Giving SOMETYPE a default value doesn't work because Vivado complains about not allowing hierarchical types, so right off the bat I don't think this will work. When instantiating, I tried using the full modport name, the full modport name with the instantiated interface, and a few others, but nothing seems to work.
So I am curious if there is a clever way I can have multiple instantiations of some_block, each taking a different generated modport. And if not, is there some fun clever trick I can do to use the generated modports? The idea in the first place was that I have a thing that has one writer and multiple readers. I wanted to generate a modport for each reader so that it could only touch it's own read address. I guess I could always just parameterize some_block on an integer, pass some_block the whole interface, and then rely on some_block to only touch the read address corresponding to the passed in integer, but that might be error prone.
Assuming that 'generate' works, there is nothing to be concerned about modules. There is no need to pass a type parameter. The module port is just supposed to be of the type of your interface.
module top();
some_interface ifc;
for (genvar gi = 0; gi < NUM_REASDERS; gi++) begin: inst
some_block sb(ifc.Reader[gi].Modport);
end
endmodule
module some_block (some_interface ifc);
always_comb myvar = ifc.read_addr;
some_block just always references the 'read_addr' which is the modport var. You can use a generate block in the 'top' module.

verilog_mode autoreginput behavior when using assignment

I wonder if the following case is possible.
I have :
module a(
input [2:0] a_i
);
endmodule
module b ();
/*AUTOREGINPUTS*/
a u_a(/*AUTOINST*/)
endmodule
It expands to:
module b ();
/*AUTOREGINPUTS*/
reg [2:0] a_i;
a u_a(/*AUTOINST*/
.a_i(a_i))
endmodule
But if I modify adding the line assign a_i = '0;, then it does not expands AUTOREGINPUTS anymore. Is there a way to expand it even if I'm doing an assignment ?
The short answer is because when running verilog-auto to fill in /*AUTOREGINPUT*/ will exclude any signal that is already declared and by adding assign a_i = '0;, you are declaring a_i.
In Verilog, explicit variable declarations are not required and will take on the default nettype if left undeclared under certain circumstances. So, if I had the following:
module x;
assign myVar = '0;
endmodule
myVar will be implicitly declared to be a net with the default nettype (which by default is wire). You can read more in the System-Verilog LRM (IEEE1800-2009 Section 6.10). One recommendation to avoid typos generating implicitly declared variables is to change the default nettype with the `default_nettype macro to none (ie `default_nettype none on the top of every file); doing this forces all variables to be explicitly declared or the compiler/synthesizer will throw an error.
verilog-mode mode in emacs is aware of implicit declaration and, as such, will not autogenerate anything declared. Thus, when you add the assign statement, you are declaring a_i and so the autogenerator will not "redefine" a_i.
To avoid this, I can only recommend running the generator before you assign any of the variables to be autogenerated. Im not sure if it handles `default_nettype none correctly, but I would assume not.
Also note, it should be /*AUTOREGINPUT*/, not /*AUTOREGINPUTS*/, no 's' at the end.

How to pass a class between two modules?

I have two modules and a class and I would like to move that class from one module to the other. Something like this:
class foo;
int x;
int y;
endclass
module mod_A(output foo foo_inst, output event trig);
initial begin
foo my_foo = new;
my_foo.x = 1;
my_foo.y = 2;
foo_inst = my_foo;
->trig;
end
endmodule
module mod_B(input foo foo_inst, input event trig);
always #(trig) begin
$display("%d%d, is a funky number.", foo_inst.x, foo_inst.y);
end
endmodule
module top();
event trig;
foo foo_inst;
mod_A mod_A(.trig, .foo_inst);
mod_B mod_B(.trig, .foo_inst);
endmodule
Of course there're also some functions defined in the class which are used in each module.
The issue with this setup is that I'm seeing errors for each ports of mod_B:
Error-[RIPLIP] Register in low conn of input port
Non-net variable 'foo_inst' cannot be an input or inout port.
Non-net variable 'trig' cannot be an input or inout port.
EDAplayground does not support class objects as module ports and 1800-2012 only mentions interface declarations, events, arrays structures or unions in Port declarations (23.2.2) so my questions are:
Is it even legal to pass classes through ports? If not, what is an elegant
method of accomplishing this?
What does "Register in low conn of
input port" mean? I'm aware that this might be a compiler specific
error and nothing indicative but if I knew what it was trying to tell me I might be a step closer to fixing this.
A variable of any type can be an input or output port. You might have to write for your compiler
input var foo foo_inst,
But it would be better to use a ref when a port is really a handle.
module mod_A(ref foo foo_inst, ref event trig);
Note that you have a typo with foo_o or foo_inst and a race condition between a trigger ->trig and an event control #(trig).

Can I use bind inside generate block

I've a simple assertion:
Lets say
assert #(posedge clk) (a |=> b);
I generally connect it with design signals using separate binding module
module bind_module;
bind dut assertion a1 (.*);
endmodule
I've a situation: dut has a bus of 45bits, each bit is generated / driven individually but all of them follow same assertion.
Can I use bind statement inside generate block? (for a range of 0 to 44) and then instead of .* use .a (in_bus[i]), .b (out_bus[i])
Assuming you intend the following:
genvar i;
generate
for(i=0; i<45; i=i+1) begin : gen_asrt
bind dut assertion a1( .a(in_bus[i]), .b(out_bus[i]), .* );
end
This will not work for 2 reasons:
The instance name a1 is being clobbered on each loop. Each instance name within a module needs to be unique. Quoting from IEEE std 1800-2012 § 23.11 'Binding auxiliary code to scopes or instances':
It is legal for more than one bind statement to bind a bind_instantiation into the same target scope. However, it shall be an error for a bind_instantiation to introduce an instance name that clashes with another name in the module name space of the target scope (see 3.13). This applies to both preexisting names as well as instance names introduced by other bind statements. The latter situation will occur if the design contains more than one instance of a module containing a bind statement.
i in the bind statement is referring to an i variable name within the scope of dut, not the genvar i. Again, quoting from IEEE std 1800-2012 § 23.11 'Binding auxiliary code to scopes or instances':
When an instance is bound into a target scope, the effect will be as if the instance was present at the very end of the target scope. In other words, all declarations present in the target scope or imported into the target scope are visible to the bound instance. Wildcard import candidates that have been imported into the scope are visible, but a bind statement cannot cause the import of a wildcard candidate. Declarations present or imported into $unit are not visible in the bind statement.
How to bind this kind of checker:
You could create one module that handles the generate statements, then instantiate that module with a bind statement. Example:
module bind_assertions #(parameter SIZE=1) ( input clock, input [SIZE-1:0] a,b );
genvar i;
generate
for(i=0; i<SIZE; i=i+1) begin : gen_asrt
assertion a1_even( .a(a[i]), .b(b[i]), .* );
end
endgenerate
endmodule
bind dut bind_assertions#(45) a1( .a(in_bus), .b(out_bus), .* );
Technically, you could bind an array of instances. It is legal syntax according to &sect 23.11's Syntax 23-9 plus Appendix A.4.1.1 'Module instantiation'. However it this seems to fail on all the simulators I currently have access to. Example (if it works on your simulator):
bind dut assertion a1[44:0]( .a(in_bus[44:0]), .b(out_bus[44:0]), .* );
Can bind exist within a generate block?
IEEE std 1800-2012 § 27.3 'Generate construct syntax' does mention bind_directive within the syntax for generate constructs is given in Syntax 27-1. Like binding an array of instances, not all simulators support this feature yet. IEEE std 1800-2009 § 27.3 also mentions bind_directive but IEEE std 1800-2005 (first IEEE version of SystemVerilog) does not. Example (if it works on your simulator):
parameter DO_BIND=1;
generate
if(DO_BIND==1) begin
bind dut bind_assertions#(45) a1( .a(in_bus), .b(out_bus), .* );
end
endgenerate