How to pass debug messages to a macro in SystemVerilog - macros

I'm attempting the following SystemVerilog:
`define DEBUG (ARG) \
`ifdef DEBUG_ON \
$display ARG;
`endif
module my_mod;
logic a;
logic [1:0] b;
assign a = 1'b0;
assign b = 2'b01;
`DEBUG(("a=%x, b=%b", a, b))
endmodule
VCS gives me the following compile error:
Error-[SE] Syntax error
Following verilog source has syntax error :
"/media/psf/Home/projects/dep2/hw/rtl/dep_dc/dep_dc_cs.sv", 254 (expanding
macro): token is '('
`DEBUG(("a=%x, b=%b", a, b))
^
#0, DEBUG : "<my_file>":21
full expansion of macro (DEBUG), error at line 1
=>(ARG)
`ifdef DEP_DEBUG_ON
...
According to this answer: How to emulate $display using Verilog Macros?
This seems like the correct syntax to me. Can someone spot anything wrong?

So I found it apparently, the compiler doesn't like spaces between the macro definition and arguments:
`define DEBUG(ARG) \
`ifdef DEBUG_ON \
$display ARG;
`endif
Works.

Related

Macro with arguments with default values, where default value is previous argument

I have a macro defined like this:
`define some_macro(ARG0, ARG1 = ARG0) \
...
I'd like the expansion some_macro(2) to expand to some_macro(2, 2). It expands to some_macro(2, ARG0), because in the default value specification for ARG1 the text ARG0 is used and not the value of the ARG0 argument.
Is it possible to specify the default of the second argument to be the value of ARG0?
Here's a good summary of what you can do with SV macros.
You could mostly achieve this with two macros, like
`define M(A1) \
`M2(A1, A1)
`define M2(A1, A2) \
"A1 A2"
module m();
initial begin
$display("joined string %s", `M(bye));
$finish;
end
endmodule
The difference is that this would require using either M or M2 depending on the number of arguments, not just one macro for both cases.

nested preprocessor directives using backslash for joining lines

systemverilog allows lines to be concatenated with a trailing "\", and this is used very commonly with the tick ("`") preprocessor commands. So the following 2 sets of definitions are identical:
`define A(b) b + \
5
`define A(b) b + 5
Similarly, in the following code, the definitions of X and P are expected to be identical. The only difference is that one version uses the "\" and the other version does not.
`define Y
`define X(a) `ifdef Y \
`define Z a+2 \
$display(`Z); \
`endif
`define P(a) `ifdef Y `define R a+2 $display(`R); `endif
module m();
initial begin
`X(5) // expands as: $display(5+2);
$display(`Z); // expands as: $display(5+2);
`P(7) // expansion was empty, but no error reported
$display(`R); // this reports an error: cyclical definition of R
end
endmodule
But, as the comments mention, one of the versions does not work with the comercial simulators. So my question is: why is the second version wrong, and what exactly are the semantics of "\" for joining consecutive lines, especially in the context of using within `define and other preprocessor commands?
Anything that is written after define is considered as macro name and anything after a space after macro name is considered as macro value/text. The optional formal arguments are delimited with braces as shown below.
text_macro_definition ::= `define text_macro_name macro_text
text_macro_name ::= text_macro_identifier [ ( list_of_formal_arguments
) ]
list_of_formal_arguments ::= formal_argument { , formal_argument }
formal_argument ::= simple_identifier [ = default_text ]
text_macro_identifier ::= identifier
Here, in order to compile successfully, you have to consider define R a+2 as one line and $display as another line. The simulator will not understand by itself that when to end the define macro value and when to start another $display line.
It gets expanded as an assignment and display in a single line:
// Actual expansion
<macro> R = a+2 $display(R);
// Intended expansion
<macro> R = a+2 // assign value to R
$display(R); // then display R
If more than one
line is necessary to specify the text, the newline shall be preceded by a backslash ( \ ).
The issue in this code is that there is no delimiter for the define of R. So R is getting defined as full a+2 $display(R). Now if we add a \, then the simulator understands that it is a new line and hence it considers $display as next statement in compiling.
`define P(a) `ifdef Y `define R a+2 \
$display(`R); `endif
Refer to IEEE 1800-2012 Sntax 22-2 for more information.

Quote macro literal string argument inside string

I have the following macro:
`define check(CONDITION) \
begin \
if (!(CONDITION)) \
$display("'%s' failed.", `"CONDITION`"); \
end
And the following expansions:
module test;
initial begin
`check(0)
`check(1 == 0)
end
endmodule
They print the following:
'0' failed.
'1 == 0' failed.
If I have a condition over strings, though, then the macro expansion won't work properly. Concretely, adding the following line leads to a compile error:
`check("foo" == "bar")
What I would like, though, is to have the following printed:
'"foo" == "bar"' failed.
Is there a way to write the macro body that would allow this? I would like to avoid solutions where I have two macros, one where strings aren't allowed inside the condition and one explicitly for strings.
You can't do this with just one macro in SystemVerilog. It would take something like the qq() operator in PERL for this to work.

How to bind an interface to multiple ports without duplicating code?

In this example, how do I create a single interface bind statement that can be reused for both ports of the module:
module adderSubtractor2(
input clk,
input [7:0] a0,
input [7:0] b0,
input doAdd0, // if this is 1, add; else subtract
output reg [8:0] result0
`ifdef HAS_UNIT_2
,
input [7:0] a1,
input [7:0] b1,
input doAdd1, // if this is 1, add; else subtract
output reg [8:0] result1
`endif
);
// ...
endmodule
interface adderSubtractor_if(
input bit clk,
input [7:0] a,
input [7:0] b,
input doAdd,
input [8:0] result
);
// ...
endinterface: adderSubtractor_if
// BIND STATEMENT(S) HERE
// The test that will be run on the DUT
program automatic test(adderSubtractor_if addSub);
initial begin
// do stuff with interface
end
endprogram // test
// The top level testbench.
module testbench;
reg clk;
adderSubtractor2 dut(.clk (clk));
test test0(dut.adderSubtractor_if0);
`ifdef HAS_UNIT_2
test test1(dut.adderSubtractor_if1);
`endif
// ...
endmodule // testbench
I believe that what you're looking for is parametrizable interface.
In general, masking ports with `ifdef is very risky, and you must have very good reasons to do this. There has already been a discussion on this topic here.
I don't see any reason to use `ifdef in your case. You can:
define a parameter NUM_OF_INSTANCES
define all (except clk and rst) the ports of your module as packed arrays. i.e.
input [1:NUM_OF_INSTANCES][7:0] a;
use "generate for" statement inside the module to instantiate multiple adders
Use parametrizable interface and bind it to the ports of the module in the usual way.
Hope this helps.
You can use macros:
`define BIND_ADD_SUB(INDEX) \
bind adderSubtractor2 adderSubtractor_if adderSubtractor_if``INDEX``( \
.clk(clk), \
.a(a``INDEX``), \
.b(b``INDEX``), \
.doAdd(doAdd``INDEX``), \
.result(result``INDEX``) \
); \
`BIND_ADD_SUB(0)
`ifdef HAS_UNIT_2
`BIND_ADD_SUB(1)
`endif
Then pass dut.adderSubtractor_if0 and dut.adderSubtractor_if1 to your testbench.

Calling a macro

I have the following macro:
#define testMethod(a, b) \
if (a.length > b.length) \
return a; \
return b;
When I try to call it with:
NSString *s = testMethod(#"fir", #"sec");
I get an error:
"Excepted ";" at end of declaration"
Why?
if is a statement, not an expression. It can't return a value like that.
You probably mean:
#define testMethod(a, b) ((a).length > (b).length ? (a) : (b))
The extra parenthesis around the arguments on the right side are common, and are there to protect you against unexpected precendence-related incidents.
Also note that because the above is pre-processed by doing textual replacement, it will probably construct more objects than the equivalent function would.
If you want to use the macro within expressions, it should be defined as an expression itself, not as a group of statements. You end up with a syntax error because the macro is literally substituted, and statements are not allowed within another statement.
GCC has an extension called "statement expressions" that can help you achieve this, but it is non-standard:
#define testMethod(a, b) ({ \
typeof(a) result = (a).length > (b).length ? (a) : (b); \
result; \
})
Actually, in your case none of this is needed because the statements can be easily converted to an expression:
#define testMethod(a, b) ((a).length > (b).length ? (a) : (b))
You need not to use the return statement... try to use the following code
#define testMethod(a,b) ((a) < (b) ? (a) : (b))
may this will help you..