Support multiple variables on RHS of a `force` assignment (#6163)
This commit is contained in:
parent
4e8a8a0398
commit
58b867c39c
|
@ -150,9 +150,11 @@ private:
|
|||
// 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
|
||||
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;
|
||||
|
||||
|
@ -185,6 +187,12 @@ public:
|
|||
ForceComponentsVarScope* tryGetForceComponents(AstVarRef* nodep) const {
|
||||
return m_forceComponentsVarScope.tryGet(nodep->varScopep());
|
||||
}
|
||||
void setValVscpRhsExpr(AstVarScope* valVscp, AstNodeExpr* rhsExpr) {
|
||||
valVscp->user4p(rhsExpr);
|
||||
}
|
||||
AstNodeExpr* getValVscpRhsExpr(AstVarScope* valVscp) const {
|
||||
return VN_CAST(valVscp->user4p(), NodeExpr);
|
||||
}
|
||||
};
|
||||
|
||||
class ForceConvertVisitor final : public VNVisitor {
|
||||
|
@ -233,9 +241,8 @@ class ForceConvertVisitor final : public VNVisitor {
|
|||
= new AstAssign{flp, lhsp->cloneTreePure(false), rhsp->cloneTreePure(false)};
|
||||
transformWritenVarScopes(setValp->lhsp(), [this, rhsp](AstVarScope* vscp) {
|
||||
AstVarScope* const valVscp = m_state.getForceComponents(vscp).m_valVscp;
|
||||
// TODO support multiple VarRefs on RHS
|
||||
if (AstVarRef* const refp = VN_CAST(rhsp, VarRef))
|
||||
ForceState::setValVscp(refp, valVscp);
|
||||
m_state.setValVscpRhsExpr(valVscp, rhsp->cloneTreePure(false));
|
||||
rhsp->foreach([valVscp](AstVarRef* refp) { ForceState::setValVscp(refp, valVscp); });
|
||||
return valVscp;
|
||||
});
|
||||
|
||||
|
@ -267,11 +274,14 @@ class ForceConvertVisitor final : public VNVisitor {
|
|||
transformWritenVarScopes(resetEnp->lhsp(), [this](AstVarScope* vscp) {
|
||||
return m_state.getForceComponents(vscp).m_enVscp;
|
||||
});
|
||||
// IEEE 1800-2023 10.6.2: If this is a net, and not a variable, then reset the read
|
||||
// signal directly as well, in case something in the same process reads it later. Also, if
|
||||
// it is a variable, and not a net, set the original signal to the forced value, as it
|
||||
// needs to retain the forced value until the next procedural update, which might happen on
|
||||
// a later eval. Luckily we can do all this in a single assignment.
|
||||
|
||||
// IEEE 1800-2023 10.6.2: When released, then if the variable is not driven by a continuous
|
||||
// assignment and does not currently have an active procedural continuous assignment, the
|
||||
// variable shall not immediately change value and shall maintain its current value until
|
||||
// the next procedural assignment to the variable is executed. Releasing a variable that is
|
||||
// driven by a continuous assignment or currently has an active assign procedural
|
||||
// continuous assignment shall reestablish that assignment and schedule a reevaluation in
|
||||
// the continuous assignment's scheduling region.
|
||||
AstAssign* const resetRdp
|
||||
= new AstAssign{flp, lhsp->cloneTreePure(false), lhsp->unlinkFrBack()};
|
||||
// Replace write refs on the LHS
|
||||
|
@ -376,10 +386,12 @@ class ForceReplaceVisitor final : public VNVisitor {
|
|||
if (AstVarScope* const valVscp = ForceState::getValVscp(nodep)) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstVarRef* const valp = new AstVarRef{flp, valVscp, VAccess::WRITE};
|
||||
AstVarRef* const rhsp = new AstVarRef{flp, nodep->varScopep(), VAccess::READ};
|
||||
AstNodeExpr* rhsp = m_state.getValVscpRhsExpr(valVscp);
|
||||
UASSERT_OBJ(rhsp, flp, "RHS of force/release must be an AstNodeExpr");
|
||||
rhsp = rhsp->cloneTreePure(false);
|
||||
|
||||
ForceState::markNonReplaceable(valp);
|
||||
ForceState::markNonReplaceable(rhsp);
|
||||
rhsp->foreach([](AstVarRef* refp) { ForceState::markNonReplaceable(refp); });
|
||||
|
||||
m_stmtp->addNextHere(new AstAssign{flp, valp, rhsp});
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
%Error: t/t_force_rhs_ref_multiple.v:23: got='h0a exp='h00000009
|
||||
%Error: t/t_force_rhs_ref_multiple.v:27: got='h0a exp='h00000007
|
||||
%Error: t/t_force_rhs_ref_multiple.v:31: got='h0a exp='h00000004
|
||||
%Error: t/t_force_rhs_ref_multiple.v:35: got='h0a exp='h00000000
|
||||
%Error: t/t_force_rhs_ref_multiple.v:39: got='h0a exp='h00000000
|
|
@ -13,6 +13,6 @@ test.scenarios('vlt')
|
|||
|
||||
test.compile(verilator_flags2=["--exe", "--main", "--timing"])
|
||||
|
||||
test.execute(expect_filename=test.golden_filename)
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); end while(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;
|
||||
logic [7:0] a = 1;
|
||||
|
@ -19,7 +20,6 @@ module t;
|
|||
#1;
|
||||
a = 0;
|
||||
#1;
|
||||
// TODO support multiple VarRefs on RHS
|
||||
`checkh(e, 9);
|
||||
|
||||
b = 0;
|
||||
|
|
Loading…
Reference in New Issue