This commit is contained in:
parent
108d209bd7
commit
8a413b3ec7
|
|
@ -2180,6 +2180,7 @@ class CaptureVisitor final : public VNVisitor {
|
||||||
std::map<const AstVar*, AstVar*> m_varCloneMap; // Map original var nodes to their clones
|
std::map<const AstVar*, AstVar*> m_varCloneMap; // Map original var nodes to their clones
|
||||||
std::set<AstNode*> m_ignore; // Nodes to ignore for capturing
|
std::set<AstNode*> m_ignore; // Nodes to ignore for capturing
|
||||||
AstVar* m_thisp = nullptr; // Variable for outer context's object, if necessary
|
AstVar* m_thisp = nullptr; // Variable for outer context's object, if necessary
|
||||||
|
bool m_staticContext = false; // True when capturing from a static function context
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
|
|
@ -2252,6 +2253,11 @@ class CaptureVisitor final : public VNVisitor {
|
||||||
if (varIsParam) return CaptureMode::CAP_VALUE;
|
if (varIsParam) return CaptureMode::CAP_VALUE;
|
||||||
// Static var in function (will not be inlined, because it's in class)
|
// Static var in function (will not be inlined, because it's in class)
|
||||||
if (callerIsClass && varIsFuncLocal) return CaptureMode::CAP_VALUE;
|
if (callerIsClass && varIsFuncLocal) return CaptureMode::CAP_VALUE;
|
||||||
|
// Static class members in static context don't need 'this' capture;
|
||||||
|
// V3Class will move both the function and the member to __Vclpkg
|
||||||
|
if (m_staticContext && callerIsClass && varIsFieldOfCaller
|
||||||
|
&& varRefp->varp()->lifetime().isStatic())
|
||||||
|
return CaptureMode::CAP_NO;
|
||||||
if (callerIsClass && varIsFieldOfCaller) return CaptureMode::CAP_THIS;
|
if (callerIsClass && varIsFieldOfCaller) return CaptureMode::CAP_THIS;
|
||||||
UASSERT_OBJ(!callerIsClass, varRefp, "Invalid reference?");
|
UASSERT_OBJ(!callerIsClass, varRefp, "Invalid reference?");
|
||||||
return CaptureMode::CAP_VALUE;
|
return CaptureMode::CAP_VALUE;
|
||||||
|
|
@ -2372,10 +2378,12 @@ class CaptureVisitor final : public VNVisitor {
|
||||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CaptureVisitor(AstNode* const nodep, AstNodeModule* callerp, AstClass* const targetp)
|
explicit CaptureVisitor(AstNode* const nodep, AstNodeModule* callerp, AstClass* const targetp,
|
||||||
|
bool staticContext = false)
|
||||||
: m_argsp{nullptr}
|
: m_argsp{nullptr}
|
||||||
, m_callerp{callerp}
|
, m_callerp{callerp}
|
||||||
, m_targetp{targetp} {
|
, m_targetp{targetp}
|
||||||
|
, m_staticContext{staticContext} {
|
||||||
iterateAndNextNull(nodep);
|
iterateAndNextNull(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3771,9 +3779,16 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
if (nodep->classOrPackagep() && nodep->classOrPackagep()->name() == "std") {
|
if (nodep->classOrPackagep() && nodep->classOrPackagep()->name() == "std") {
|
||||||
// Handle std::randomize; create wrapper function that calls basicStdRandomization on
|
// Handle std::randomize; create wrapper function that calls basicStdRandomization on
|
||||||
// each varref argument, then transform nodep to call that wrapper
|
// each varref argument, then transform nodep to call that wrapper
|
||||||
|
const bool inStaticContext = m_ftaskp && m_ftaskp->isStatic();
|
||||||
AstVar* const stdrand = createStdRandomGenerator(m_modp);
|
AstVar* const stdrand = createStdRandomGenerator(m_modp);
|
||||||
AstFunc* const randomizeFuncp = V3Randomize::newRandomizeStdFunc(
|
AstFunc* const randomizeFuncp = V3Randomize::newRandomizeStdFunc(
|
||||||
m_memberMap, m_modp, m_inlineUniqueStdName.get(nodep));
|
m_memberMap, m_modp, m_inlineUniqueStdName.get(nodep));
|
||||||
|
// When called from a static function, mark helper and stdrand as static
|
||||||
|
// so V3Class moves them to __Vclpkg alongside the calling function
|
||||||
|
if (inStaticContext) {
|
||||||
|
stdrand->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||||
|
randomizeFuncp->isStatic(true);
|
||||||
|
}
|
||||||
randomizeFuncp->addStmtsp(
|
randomizeFuncp->addStmtsp(
|
||||||
new AstAssign{nodep->fileline(),
|
new AstAssign{nodep->fileline(),
|
||||||
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
|
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
|
||||||
|
|
@ -3829,7 +3844,8 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
if (withp) {
|
if (withp) {
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
withCapturep = std::make_unique<CaptureVisitor>(withp->exprp(), m_modp, nullptr);
|
withCapturep = std::make_unique<CaptureVisitor>(withp->exprp(), m_modp, nullptr,
|
||||||
|
inStaticContext);
|
||||||
withCapturep->addFunctionArguments(randomizeFuncp);
|
withCapturep->addFunctionArguments(randomizeFuncp);
|
||||||
// Clear old constraints and variables for std::randomize with clause
|
// Clear old constraints and variables for std::randomize with clause
|
||||||
if (stdrand) {
|
if (stdrand) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
if not test.have_solver:
|
||||||
|
test.skip("No constraint solver installed")
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||||
|
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
// Test std::randomize() called from a static function referencing static
|
||||||
|
// class members in the 'with' clause.
|
||||||
|
|
||||||
|
// verilog_format: off
|
||||||
|
`define stop $stop
|
||||||
|
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||||
|
// verilog_format: on
|
||||||
|
|
||||||
|
module t;
|
||||||
|
|
||||||
|
typedef enum bit [3:0] {
|
||||||
|
INSTR_ADD = 0,
|
||||||
|
INSTR_SUB = 1,
|
||||||
|
INSTR_MUL = 2,
|
||||||
|
INSTR_AND = 4
|
||||||
|
} instr_name_t;
|
||||||
|
|
||||||
|
class instr_base;
|
||||||
|
static instr_name_t allowed_instrs[$];
|
||||||
|
|
||||||
|
static function void init();
|
||||||
|
allowed_instrs.push_back(INSTR_ADD);
|
||||||
|
allowed_instrs.push_back(INSTR_SUB);
|
||||||
|
allowed_instrs.push_back(INSTR_MUL);
|
||||||
|
allowed_instrs.push_back(INSTR_AND);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
static function instr_name_t get_rand_instr();
|
||||||
|
instr_name_t name;
|
||||||
|
int ok;
|
||||||
|
ok = std::randomize(name) with {
|
||||||
|
name inside {allowed_instrs};
|
||||||
|
};
|
||||||
|
`checkd(ok, 1);
|
||||||
|
return name;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
instr_name_t result;
|
||||||
|
|
||||||
|
instr_base::init();
|
||||||
|
|
||||||
|
repeat (20) begin
|
||||||
|
result = instr_base::get_rand_instr();
|
||||||
|
`checkd(result == INSTR_ADD || result == INSTR_SUB
|
||||||
|
|| result == INSTR_MUL || result == INSTR_AND, 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue