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.
Related
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
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.
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.
When you have variable parameters in a macro, for instance
<#macro m a b c...>
Do you have to pass a minimum of 3 arguments or 2 while calling the macro? Does the parameter c here have to have at least 1 value? Also is there any way to specify a parameter as null by default?
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
Where:
name: name of macro variable. It's not an expression. It follows the
same syntax as like top-level variable references, like myMacro or
my-macro. However, it can also be written as a string literal, which
is useful if the macro name contains characters that can't be
specified in an identifier, for example <#macro "foo~bar">.... Note
that this string literal does not expand interpolations (as
"${foo}").
param1, param2, ...etc.: the name of the local variables store the
parameter values (not expression), optionally followed by = and the
default value (that's an expression). The default value can even be
another parameter, for example <#macro section title label=title>.
The parameter name uses the same syntax as like top-level variable
references, so the same features and restrictions apply.
paramN, the last parameter may optionally has 3 trailing dots (...),
which indicates that the macro takes a variable number of parameters
and the parameters that doesn't match any other parameters will be
collected in this last parameter (also called the catch-all
parameter). When the macro is called with named parameters, paramN
will be a hash containing all of the undeclared key/value pairs
passed to the macro. When the macro is called using positional
parameters, paramN will be the sequence of the extra parameter
values. (Inside the macro, to find out which was the case, you can
use myCatchAllParam?is_sequence.)
Therefore as you can see macro does not have any limitation to take N parameters.
This structure creates a macro variable (in the current namespace, if you know namespace feature). If you are new to macros and user-defined directives you should read the the tutorial about user-defined directives.
Macro variable stores a template fragment (called macro definition body) that can be used as user-defined directive. The variable also stores the name of allowed parameters to the user-defined directive. You must give value for all of those parameters when you use the variable as directive, except for parameters that has a default value. The default value will be used if and only if you don't give value for the parameter when you call the macro.
The variable will be created at the beginning of the template; it does not mater where the macro directive is placed in the template.
Example: Macro with parameters:
<#macro test foo bar baaz>
Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<#-- call the macro: -->
<#test foo="a" bar="b" baaz=5*5-2/>
Output:
Test text, and the params: a, b, 23
Example: Macro with parameters and default parameter values:
<#macro test foo bar="Bar" baaz=-1>
Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<#test foo="a" bar="b" baaz=5*5-2/>
<#test foo="a" bar="b"/>
<#test foo="a" baaz=5*5-2/>
<#test foo="a"/>
Output:
Test text, and the params: a, b, 23
Test text, and the params: a, b, -1
Test text, and the params: a, Bar, 23
Test text, and the params: a, Bar, -1
However, about last part of your question there is an explanation:
The null reference is by design an error in FreeMarker. Defining a custom null value - which is a string - is not a good idea for the reasons you mention. The following constructs should be used instead:
Macro and function parameters can have a default value, so the
callers can omit them
To check if a variable is null, you should use the ?? operator: <#if
(name??)>
When you use a variable that can be null, you should use the !
operator to specify a default value: name!"No name"
To check if a sequence (or a string) is empty, use the ?has_content
builtin: <#if (names?has_content)>
You can specify an empty sequence as default parameter value in a macro, and simply test whether it's empty.
When you have variable parameters in a macro, you don't have to pass a value for the last argument.
For example:
<#macro m a b c...>
a = ${a!}
b = ${b!}
<#list c?keys as attr>
${attr} = ${c[attr]}
</#list>
</#macro>
<#m a='A' b='B' />
<#m a='A' b='B' c='C' d='D'/>
Will output:
a = A
b = B
a = A
b = B
c = C
d = D
Suppose I have some macro #define NAME name, and I want to define some other macro which will expand to the quoted value. That is, as if I had also defined #define NAME_STR "name". Is there a neater way than the following?
#define QUOT(str) #str
#define QUOT_ARG(str) QUOT(str)
#define NAME_STR QUOT_ARG(NAME)
Not really, due to the fact that macro arguments are not expanded when used in stringification. From the GNU C PreProcessor manual:
Unlike normal parameter replacement,
the argument is not macro-expanded
first. This is called stringification.
From the same source:
If you want to stringify the result of
expansion of a macro argument, you
have to use two levels of macros.
...which continues with an example:
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
==> "foo"
xstr (foo)
==> xstr (4)
==> str (4)
==> "4"