2024-07-10 00:31:58 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Removal of SAMPLED
|
|
|
|
|
//
|
|
|
|
|
// Code available from: https://verilator.org
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
2024-07-10 00:31:58 +02:00
|
|
|
// 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
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Sampled's Transformations:
|
|
|
|
|
//
|
|
|
|
|
// Top Scope:
|
|
|
|
|
// Replace each variable reference under SAMPLED with a new variable.
|
|
|
|
|
// Remove SAMPLED.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
|
|
|
|
#include "V3Sampled.h"
|
|
|
|
|
|
|
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Clock state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class SampledVisitor final : public VNVisitor {
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// AstVarScope::user1() -> AstVarScope*. The VarScope that stores sampled value
|
|
|
|
|
// AstVarRef::user1() -> bool. Whether already converted
|
|
|
|
|
const VNUser1InUse m_user1InUse;
|
2025-04-27 20:17:24 +02:00
|
|
|
|
|
|
|
|
// STATE - for current visit position (use VL_RESTORER)
|
2024-07-10 00:31:58 +02:00
|
|
|
AstScope* m_scopep = nullptr; // Current scope
|
|
|
|
|
bool m_inSampled = false; // True inside a sampled expression
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
|
|
|
|
|
AstVarScope* createSampledVar(AstVarScope* vscp) {
|
|
|
|
|
if (vscp->user1p()) return VN_AS(vscp->user1p(), VarScope);
|
|
|
|
|
const AstVar* const varp = vscp->varp();
|
|
|
|
|
const string newvarname
|
|
|
|
|
= "__Vsampled_" + vscp->scopep()->nameDotless() + "__" + varp->name();
|
|
|
|
|
FileLine* const flp = vscp->fileline();
|
|
|
|
|
AstVar* const newvarp = new AstVar{flp, VVarType::MODULETEMP, newvarname, varp->dtypep()};
|
|
|
|
|
m_scopep->modp()->addStmtsp(newvarp);
|
|
|
|
|
AstVarScope* const newvscp = new AstVarScope{flp, m_scopep, newvarp};
|
|
|
|
|
newvarp->direction(VDirection::INPUT); // Inform V3Sched that it will be driven later
|
|
|
|
|
newvarp->primaryIO(true);
|
|
|
|
|
vscp->user1p(newvscp);
|
|
|
|
|
m_scopep->addVarsp(newvscp);
|
|
|
|
|
// At the top of _eval, assign them (use valuep here as temporary storage during V3Sched)
|
|
|
|
|
newvarp->valuep(new AstVarRef{flp, vscp, VAccess::READ});
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(4, "New Sampled: " << newvscp);
|
2024-07-10 00:31:58 +02:00
|
|
|
return newvscp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
|
|
|
|
void visit(AstScope* nodep) override {
|
|
|
|
|
VL_RESTORER(m_scopep);
|
|
|
|
|
m_scopep = nodep;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstSampled* nodep) override {
|
|
|
|
|
VL_RESTORER(m_inSampled);
|
|
|
|
|
m_inSampled = true;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstVarRef* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
if (m_inSampled && !nodep->user1SetOnce()) {
|
|
|
|
|
UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "Should have failed in V3Access");
|
|
|
|
|
AstVarScope* const varscp = nodep->varScopep();
|
|
|
|
|
AstVarScope* const lastscp = createSampledVar(varscp);
|
|
|
|
|
AstNode* const newp = new AstVarRef{nodep->fileline(), lastscp, VAccess::READ};
|
|
|
|
|
newp->user1SetOnce(); // Don't sample this one
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
explicit SampledVisitor(AstNetlist* netlistp) { iterate(netlistp); }
|
|
|
|
|
~SampledVisitor() override = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Sampled class functions
|
|
|
|
|
|
|
|
|
|
void V3Sampled::sampledAll(AstNetlist* nodep) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2024-07-10 00:31:58 +02:00
|
|
|
{ SampledVisitor{nodep}; } // Destruct before checking
|
|
|
|
|
V3Global::dumpCheckGlobalTree("sampled", 0, dumpTreeEitherLevel() >= 3);
|
|
|
|
|
}
|