diff --git a/Changes b/Changes index 9c6a3557e..d73136e44 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support elaboration assertions, bug973. [Johan Bjork] +*** Support $display with non-format arguments, bug467. [Jamey Hicks] + **** Add VerilatedScopeNameMap for introspection, bug966. [Todd Strader] **** Ignore %l in $display, bug983. [Todd Strader] diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 759d93a42..d67aec04a 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -254,7 +254,7 @@ private: } } - void expectFormat(AstNode* nodep, const string& format, AstNode* argp, bool isScan) { + string expectFormat(AstNode* nodep, const string& format, AstNode* argp, bool isScan) { // Check display arguments bool inPct = false; for (string::const_iterator it = format.begin(); it != format.end(); ++it) { @@ -290,8 +290,57 @@ private: } // switch } } - if (argp) { - argp->v3error("Extra arguments for $display-like format"); + if (argp && !isScan) { + int skipCount = 0; // number of args consume by any additional format strings + string newFormat(format); + while (argp) { + if (skipCount) { + argp = argp->nextp(); + skipCount--; + continue; + } + AstConst *constp = argp->castConst(); + bool isFromString = (constp) ? constp->num().isFromString() : false; + if (isFromString) { + int numchars = argp->dtypep()->width()/8; + string str(numchars, ' '); + // now scan for % operators + bool inpercent = false; + for (int i = 0; i < numchars; i++) { + int ii = numchars - i - 1; + char c = constp->num().dataByte(ii); + str[i] = c; + if (!inpercent && c == '%') { + inpercent = true; + } else if (inpercent) { + inpercent = 0; + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': + inpercent = true; + break; + case '%': + break; + default: + if (V3Number::displayedFmtLegal(c)) { + skipCount++; + } + } + } + } + newFormat.append(str); + AstNode *nextp = argp->nextp(); + argp->unlinkFrBack(); pushDeletep(argp); VL_DANGLING(argp); + argp = nextp; + } else { + newFormat.append("%h"); + argp = argp->nextp(); + } + } + return newFormat; + } else { + return string(); } } @@ -322,7 +371,9 @@ private: } virtual void visit(AstSFormatF* nodep, AstNUser*) { nodep->iterateChildren(*this); - expectFormat(nodep, nodep->text(), nodep->exprsp(), false); + string newFormat = expectFormat(nodep, nodep->text(), nodep->exprsp(), false); + if (newFormat.size()) + nodep->text(newFormat); if ((nodep->backp()->castDisplay() && nodep->backp()->castDisplay()->displayType().needScopeTracking()) || nodep->formatScopeTracking()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); diff --git a/src/V3Number.h b/src/V3Number.h index bacf082d2..f8e7efc2d 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -205,6 +205,7 @@ public: double toDouble() const; uint32_t toHash() const; uint32_t dataWord(int word) const; + uint8_t dataByte(int byte) const { return (dataWord(byte/4) >> (8*(byte&3))) & 0xff; } uint32_t countOnes() const; uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0. diff --git a/test_regress/t/t_display.pl b/test_regress/t/t_display.pl index 3f2256662..f54b434a9 100755 --- a/test_regress/t/t_display.pl +++ b/test_regress/t/t_display.pl @@ -28,6 +28,9 @@ execute ( [0] %s=! %s= what! %s= hmmm!1234 [0] hello, from a very long string. Percent %s are literally substituted in. +hello, from a concatenated string. +hello, from a concatenated format string [0]. +extra argument: 0000000000000000 [0] Embedded <#013> return [0] Embedded multiline diff --git a/test_regress/t/t_display.v b/test_regress/t/t_display.v index 0ee1e73e1..ddba4d1c1 100644 --- a/test_regress/t/t_display.v +++ b/test_regress/t/t_display.v @@ -43,6 +43,9 @@ module t; $display("[%0t] %s%s%s", $time, "hel", "lo, fr", "om a very long string. Percent %s are literally substituted in."); + $display("hel", "lo, fr", "om a concatenated string."); + $write("hel", "lo, fr", "om a concatenated format string [%0t].\n", $time); + $display("extra argument: ", $time); $write("[%0t] Embedded \r return\n", $time); $display("[%0t] Embedded\ multiline", $time); diff --git a/test_regress/t/t_display_bad.pl b/test_regress/t/t_display_bad.pl index 91992754d..a43289ea7 100755 --- a/test_regress/t/t_display_bad.pl +++ b/test_regress/t/t_display_bad.pl @@ -12,7 +12,6 @@ compile ( fails=>1, expect=> '%Error: t/t_display_bad.v:\d+: Missing arguments for \$display-like format -%Error: t/t_display_bad.v:\d+: Extra arguments for \$display-like format %Error: t/t_display_bad.v:\d+: Unknown \$display-like format code: %q %Error: Exiting due to.*', ); diff --git a/test_regress/t/t_display_noopt.pl b/test_regress/t/t_display_noopt.pl index 33271f3e6..cc1e647f7 100755 --- a/test_regress/t/t_display_noopt.pl +++ b/test_regress/t/t_display_noopt.pl @@ -31,6 +31,9 @@ execute ( [0] %s=! %s= what! %s= hmmm!1234 [0] hello, from a very long string. Percent %s are literally substituted in. +hello, from a concatenated string. +hello, from a concatenated format string [0]. +extra argument: 0000000000000000 [0] Embedded <#013> return [0] Embedded multiline