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::set<AstNode*> m_ignore; // Nodes to ignore for capturing
|
||||
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
|
||||
|
||||
|
|
@ -2252,6 +2253,11 @@ class CaptureVisitor final : public VNVisitor {
|
|||
if (varIsParam) return CaptureMode::CAP_VALUE;
|
||||
// Static var in function (will not be inlined, because it's in class)
|
||||
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;
|
||||
UASSERT_OBJ(!callerIsClass, varRefp, "Invalid reference?");
|
||||
return CaptureMode::CAP_VALUE;
|
||||
|
|
@ -2372,10 +2378,12 @@ class CaptureVisitor final : public VNVisitor {
|
|||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
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_callerp{callerp}
|
||||
, m_targetp{targetp} {
|
||||
, m_targetp{targetp}
|
||||
, m_staticContext{staticContext} {
|
||||
iterateAndNextNull(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -3771,9 +3779,16 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
if (nodep->classOrPackagep() && nodep->classOrPackagep()->name() == "std") {
|
||||
// Handle std::randomize; create wrapper function that calls basicStdRandomization on
|
||||
// each varref argument, then transform nodep to call that wrapper
|
||||
const bool inStaticContext = m_ftaskp && m_ftaskp->isStatic();
|
||||
AstVar* const stdrand = createStdRandomGenerator(m_modp);
|
||||
AstFunc* const randomizeFuncp = V3Randomize::newRandomizeStdFunc(
|
||||
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(
|
||||
new AstAssign{nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
|
||||
|
|
@ -3829,7 +3844,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
}
|
||||
if (withp) {
|
||||
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);
|
||||
// Clear old constraints and variables for std::randomize with clause
|
||||
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