Any C / C++ programmers now programming in SystemVerilog must feel pretty constrained by language limitations. One of the frustrations that I felt today was the lack of variable argument (varargs) support. I wanted to be able to overload a print function (ie write my own $display) and selectively print or not print based on debug levels or the like. Actually... what I wanted was to store all the debug prints between runs, and only print them in the case of an error, but that's besides the point. I needed a way to overload the $display function.
Here is what I've finally come up with: (be ready, it's wild)
$display("Print with no arguments");
$display("Print with 1 argument %t", $time());
$display("Print with 2 arguments %t, %d", $time(), 5);
$display("Print with 3 arguments %t, %d, %s", $time(), 5, "debug");
etc...
I wanted this to become:
DEBUG_PRINT("Print with no arguments");
DEBUG_PRINT("Print with 1 argument %t", $time());
DEBUG_PRINT("Print with 2 arguments %t, %d", $time(), 5);
DEBUG_PRINT("Print with 3 arguments %t, %d, %s", $time(), 5, "debug");
etc...
Is it possible??
Yes! (at least until someone points out a flaw)
The solution is based on macros that can have variable number of arguments, and the preprocessor allowing ifdef on substituted strings
function void my_debug(string s);
...
endfunction
`define DELIM
`define DEBUG_PRINT(p0, p1=ELIM, p2=ELIM, p3=ELIM, p4=ELIM, p5=ELIM) \
`ifdef D``p1 \
my_debug($psprintf(p0)); \
`else \
`ifdef D``p2 \
my_debug($psprintf(p0, p1)); \
`else \
`ifdef D``p3 \
my_debug($psprintf(p0, p1, p2)); \
`else \
`ifdef D``p4 \
my_debug($psprintf(p0, p1, p2, p3)); \
`else \
`ifdef D``p5 \
my_debug($psprintf(p0, p1, p2, p3, p4)); \
`else \
my_debug($psprintf(p0, p1, p2, p3, p4, p5)); \
`endif \
`endif \
`endif \
`endif \
`endif
This solution works on Cadence Incisive 12.1
Tell me what you think of this solution,
Nachum
It ain't pretty but 10 years later, this still seems to be the best solution to the need for varargs in system verilog or PLI/VPI/DPI. Runs in VCS. Just one issue- the code below throws compile error on 'else', presumably because the macro expands to more than 1 statement (?):
ReplyDeleteif (test)
`DEBUG_PRINT("took if");
else
`DEBUG_PRINT("took else");