Fix same variable on the RHS forced to two different LHSs. (#6269)
This commit is contained in:
parent
dc049fdd74
commit
5b7188fcaf
|
|
@ -148,15 +148,16 @@ private:
|
|||
// AstVar::user1p -> ForceComponentsVar* instance (via m_forceComponentsVar)
|
||||
// AstVarScope::user1p -> ForceComponentsVarScope* instance (via m_forceComponentsVarScope)
|
||||
// AstVarRef::user2 -> Flag indicating not to replace reference
|
||||
// AstVarScope::user3 -> AstVarScope*, a `valVscp` force component for each VarScope of
|
||||
// forced RHS
|
||||
// AstVarScope::user4p -> AstNodeExpr*, the RHS expression
|
||||
// AstVarScope::user3p -> AstNodeExpr*, the RHS expression
|
||||
const VNUser1InUse m_user1InUse;
|
||||
const VNUser2InUse m_user2InUse;
|
||||
const VNUser3InUse m_user3InUse;
|
||||
const VNUser4InUse m_user4InUse;
|
||||
AstUser1Allocator<AstVar, ForceComponentsVar> m_forceComponentsVar;
|
||||
AstUser1Allocator<AstVarScope, ForceComponentsVarScope> m_forceComponentsVarScope;
|
||||
std::unordered_map<const AstVarScope*,
|
||||
std::pair<std::unordered_set<AstVarScope*>, std::vector<AstVarScope*>>>
|
||||
m_valVscps;
|
||||
// `valVscp` force components of a forced RHS
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
|
|
@ -172,11 +173,21 @@ public:
|
|||
}
|
||||
static bool isNotReplaceable(const AstVarRef* const nodep) { return nodep->user2(); }
|
||||
static void markNonReplaceable(AstVarRef* const nodep) { nodep->user2SetOnce(); }
|
||||
static AstVarScope* getValVscp(AstVarRef* const refp) {
|
||||
return VN_CAST(refp->varScopep()->user3p(), VarScope);
|
||||
|
||||
// Get all ValVscps for a VarScope
|
||||
const std::vector<AstVarScope*>* getValVscps(AstVarRef* const refp) const {
|
||||
auto it = m_valVscps.find(refp->varScopep());
|
||||
if (it != m_valVscps.end()) return &(it->second.second);
|
||||
return nullptr;
|
||||
}
|
||||
static void setValVscp(AstNodeVarRef* const refp, AstVarScope* const vscp) {
|
||||
refp->varScopep()->user3p(vscp);
|
||||
|
||||
// Add a ValVscp for a VarScope
|
||||
void addValVscp(AstVarRef* const refp, AstVarScope* const valVscp) {
|
||||
if (m_valVscps[refp->varScopep()].first.find(valVscp)
|
||||
!= m_valVscps[refp->varScopep()].first.end())
|
||||
return;
|
||||
m_valVscps[refp->varScopep()].first.emplace(valVscp);
|
||||
m_valVscps[refp->varScopep()].second.push_back(valVscp);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
|
|
@ -188,10 +199,10 @@ public:
|
|||
return m_forceComponentsVarScope.tryGet(nodep->varScopep());
|
||||
}
|
||||
void setValVscpRhsExpr(AstVarScope* valVscp, AstNodeExpr* rhsExpr) {
|
||||
valVscp->user4p(rhsExpr);
|
||||
valVscp->user3p(rhsExpr);
|
||||
}
|
||||
AstNodeExpr* getValVscpRhsExpr(AstVarScope* valVscp) const {
|
||||
return VN_CAST(valVscp->user4p(), NodeExpr);
|
||||
return VN_CAST(valVscp->user3p(), NodeExpr);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -242,7 +253,7 @@ class ForceConvertVisitor final : public VNVisitor {
|
|||
transformWritenVarScopes(setValp->lhsp(), [this, rhsp](AstVarScope* vscp) {
|
||||
AstVarScope* const valVscp = m_state.getForceComponents(vscp).m_valVscp;
|
||||
m_state.setValVscpRhsExpr(valVscp, rhsp->cloneTreePure(false));
|
||||
rhsp->foreach([valVscp](AstVarRef* refp) { ForceState::setValVscp(refp, valVscp); });
|
||||
rhsp->foreach([valVscp, this](AstVarRef* refp) { m_state.addValVscp(refp, valVscp); });
|
||||
return valVscp;
|
||||
});
|
||||
|
||||
|
|
@ -380,7 +391,8 @@ class ForceReplaceVisitor final : public VNVisitor {
|
|||
m_stmtp->addNextHere(new AstAssign{flp, lhsp, rhsp});
|
||||
}
|
||||
// Emit valVscp update after each write to any VarRef on forced RHS.
|
||||
if (AstVarScope* const valVscp = ForceState::getValVscp(nodep)) {
|
||||
if (!m_state.getValVscps(nodep)) break;
|
||||
for (AstVarScope* const valVscp : *m_state.getValVscps(nodep)) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstVarRef* const valp = new AstVarRef{flp, valVscp, VAccess::WRITE};
|
||||
AstNodeExpr* rhsp = m_state.getValVscpRhsExpr(valVscp);
|
||||
|
|
@ -396,7 +408,7 @@ class ForceReplaceVisitor final : public VNVisitor {
|
|||
}
|
||||
default:
|
||||
if (!m_inLogic) return;
|
||||
if (m_state.tryGetForceComponents(nodep) || ForceState::getValVscp(nodep)) {
|
||||
if (m_state.tryGetForceComponents(nodep) || m_state.getValVscps(nodep)) {
|
||||
nodep->v3error(
|
||||
"Unsupported: Signals used via read-write reference cannot be forced");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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('vlt')
|
||||
|
||||
test.compile(verilator_flags2=["--exe", "--main", "--timing"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// 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
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
|
||||
|
||||
module t;
|
||||
bit [1:0] a;
|
||||
bit [1:0] b;
|
||||
|
||||
bit [1:0] d;
|
||||
|
||||
initial begin
|
||||
a = 0;
|
||||
force b = a;
|
||||
force d = a;
|
||||
a = 2;
|
||||
#1;
|
||||
`checkh(a, 2);
|
||||
`checkh(b, 2);
|
||||
`checkh(d, 2);
|
||||
a = 3;
|
||||
#1;
|
||||
`checkh(a, 3);
|
||||
`checkh(b, 3);
|
||||
`checkh(d, 3);
|
||||
#1 $finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue