Add `$cpure` (#6580)

This commit is contained in:
Igor Zaworski 2025-10-22 15:18:27 +02:00 committed by GitHub
parent cb3c2706a8
commit 43373010dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 71 additions and 9 deletions

View File

@ -156,7 +156,7 @@ or "`ifdef`"'s may break other tools.
.. t_dist_docs_style restart_sort
.. option:: $c([string], ...);
.. option:: $c([string], ...);, $cpure([string], ...);
The string will be embedded directly in the output C++ code at the point
where the surrounding Verilog code is compiled. It may either be a
@ -196,6 +196,11 @@ or "`ifdef`"'s may break other tools.
compatibility with other simulators, which require a differently named
PLI function name for each different output width.
`$cpure` is similar to `$c` except that it indicates the
expression is pure, versus `$c` which is assumed impure.
`$cpure` is for internal use only, and it might change
without notice in any future version or Verilator.
.. option:: $display, $write, $fdisplay, $fwrite, $sformat, $swrite
Format arguments may use C fprintf sizes after the % escape. Per the

View File

@ -603,23 +603,30 @@ public:
void add(AstNode* nodep) { addNodesp(nodep); }
};
class AstCExprUser final : public AstNodeExpr {
// User '$c' statement - Like AstCStmt, with text tracking and optimizations disabled.
// User '$c' or '$cpure' expression - Like AstCStmt, with text tracking and optimizations
// disabled.
//
// Use AstCExpr instead, unless the text is from user input.
//
// @astgen op1 := nodesp : List[AstNode<AstNodeExpr|AstText>]
const bool m_pure; // Whether the function is pure
public:
class Pure {};
AstCExprUser(FileLine* fl)
: ASTGEN_SUPER_CExprUser(fl) {}
: ASTGEN_SUPER_CExprUser(fl)
, m_pure{false} {}
AstCExprUser(FileLine* fl, Pure)
: ASTGEN_SUPER_CExprUser(fl)
, m_pure{true} {}
ASTGEN_MEMBERS_AstCExprUser;
// METHODS
bool cleanOut() const override { return false; }
std::string emitC() override { V3ERROR_NA_RETURN(""); }
std::string emitVerilog() override { V3ERROR_NA_RETURN(""); }
bool isGateOptimizable() const override { return false; }
bool isGateOptimizable() const override { return m_pure; }
bool isOutputter() override { return true; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; }
bool isPredictOptimizable() const override { return m_pure; }
bool isPure() override { return m_pure; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
// Add some text, or a node to this expression
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }

View File

@ -1376,7 +1376,9 @@ public:
putnbs(nodep, "");
ofp()->putsNoTracking("\n");
if (/* is always from $c */ v3Global.opt.decoration() && !v3Global.opt.protectIds()) {
ofp()->putsNoTracking("// $c expression at " + nodep->fileline()->ascii() + "\n");
ofp()->putsNoTracking(
(nodep->isPure() ? "// $cpure expression at " : "// $c expression at ")
+ nodep->fileline()->ascii() + "\n");
}
emitNodesWithText(nodep->nodesp(), m_useSelfForThis, false, "");
puts("\n");

View File

@ -174,7 +174,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
{ws} { FL_FWD; FL_BRK; } /* otherwise ignore white-space */
{crnl} { FL_FWD; FL_BRK; } /* Count line numbers */
/* Extensions to Verilog set, some specified by PSL */
"$c"[0-9]* { FL; return yD_C; } /*Verilator only*/
"$c"[0-9]* { FL; return yD_C; } /*Verilator only*/
"$cpure"[0-9]* { FL; return yD_CPURE; } /*Verilator only*/
/* System Tasks */
"$acos" { FL; return yD_ACOS; }
"$acosh" { FL; return yD_ACOSH; }

View File

@ -611,6 +611,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yD_BITSTOREAL "$bitstoreal"
%token<fl> yD_BITSTOSHORTREAL "$bitstoshortreal"
%token<fl> yD_C "$c"
%token<fl> yD_CPURE "$cpure"
%token<fl> yD_CAST "$cast"
%token<fl> yD_CEIL "$ceil"
%token<fl> yD_CHANGED "$changed"
@ -4101,7 +4102,7 @@ system_t_call<nodeStmtp>: // IEEE: system_tf_call (as task)
}
$$ = cstmtp;
}
| yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); DEL($3); }
| yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); DEL($3); }
| yD_STACKTRACE parenE { $$ = new AstStackTraceT{$1}; }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT{$1, $3}; }
//
@ -4268,6 +4269,14 @@ system_f_call<nodeExprp>: // IEEE: system_tf_call (as func)
}
$$ = cexprp;
}
| yD_CPURE '(' cStrList ')' {
AstCExprUser* cexprp = nullptr;
if (!v3Global.opt.ignc()) {
cexprp = new AstCExprUser{$1, AstCExprUser::Pure{}};
cexprp->add($3);
}
$$ = cexprp;
}
| yD_CAST '(' expr ',' expr ')' { $$ = new AstCastDynamic{$1, $5, $3}; }
| yD_STACKTRACE parenE { $$ = new AstStackTraceF{$1}; }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF{$1, $3}; }

18
test_regress/t/t_cpure.py Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

20
test_regress/t/t_cpure.v Normal file
View File

@ -0,0 +1,20 @@
// DESCRIPTION: Verilator: Verilog Test module for SystemVerilog 'alias'
//
// Simple bi-directional transitive alias test.
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
function int func();
static int someVar = 12;
return $cpure(someVar, "+ 6");
endfunction
module t;
initial begin
if (func() != 18) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule