nested preprocessor directives using backslash for joining lines - system-verilog

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.

Related

Passing a varying number of macro arguments as a string in System Verilog

I have an existing code that uses some macro definitions in order to display messages from my test cases. I want to change the implementation of these macros, however, as these macros are extensively used in already existing testcases, I am looking to reimplement their functionality witout having to modify how the macros are used.
Currently the macros are difined as such:
`define My_Info $write("INFO:"); $display
`define My_Error $write("ERROR:"); $display
In the testcases, example calls of these macros include:
`My_Info("This is an info message with arguments %0d, %0d, and %0d", var1, var2, var3);
`My_Info("My_ID", $psprintf("ID : %s", var4));
`My_Error("Failed to open file: %s ", fname);
Currently $display, displays the messages in the brakets.
What I want to do is to define the macros in a way that these messages in the brakets of the macro calls could be passed as a string argument to a function (for example the function my_msg(msg) where msg is a string and my_msg is a function that formats and returns this string to the log file.
My issue is, because in the testcases the macro calls have varying number of arguments as seen in the example above, I am not sure how to define the macros in a universal way.
Currenlty my solution is to define the macros like:
`define My_Info(string=" ", var1= , var2= , var3= , var4= ) my_msg($sformat(s,var1, var2, var3, var4)
But this relies on a finite number of arguments (in this case 5).
Is there a more elegant way of doing it?
You can workaround the lack of varying numbers of macro arguments by requiring an extra set of ()'s.
module top;
`define my_error(msg) begin $error({"My ID:",$sformatf msg}); end
int a,b;
initial begin
`my_error( ("hello") )
`my_error( ("A = %0d B = %0d", a,b) )
end
endmodule

How to pass debug messages to a macro in SystemVerilog

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.

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.

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.

Interpolating an expression into an expression inside of a quote

This question builds off of a previous SO question which was for building expressions from expressions inside of of a macro. However, things got a little trucker when quoting the whole expression. For example, I want to build the expression :(name=val). The following:
macro quotetest(name,val)
quote
nm = Meta.quot($(QuoteNode(name)))
v = Meta.quot($(QuoteNode(val)))
println(nm); println(typeof(nm))
println(v); println(typeof(val))
end
end
#quotetest x 5 # Test case: build :(x=5)
prints out
:x
Expr
$(Expr(:quote, 5))
Expr
showing that I am on the right path: nm and val are the expressions that I want inside of the quote. However, I can't seem to apply the previous solution at this point. For example,
macro quotetest(name,val)
quote
nm = Meta.quot($(QuoteNode(name)))
v = Meta.quot($(QuoteNode(val)))
println(nm); println(typeof(nm))
println(v); println(typeof(v))
println(:($(Expr(:(=),$(QuoteNode(nm)),$(QuoteNode(val))))))
end
end
fails, saying nm is not defined. I tried just interpolating without the QuoteNode, escaping the interpolation $(esc(nm)), etc. I can't seem to find out how to make it build the expression.
I think you are using $ signs more than you need to. Is this what you're looking for?
julia> macro quotetest(name,val)
quote
expr = :($$(QuoteNode(name)) = $$(QuoteNode(val)))
println(expr)
display(expr)
println(typeof(expr))
end
end
#quotetest (macro with 1 method)
julia> #quotetest test 1
test = 1
:(test = 1)
Expr