2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Generated Clock repairs
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2022-01-01 14:26:40 +01:00
|
|
|
// Copyright 2003-2022 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// GENCLK TRANSFORMATIONS:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Follow control-flow graph with assignments and var usages
|
|
|
|
|
// ASSIGNDLY to variable later used as clock requires change detect
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "V3GenClk.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Ast.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// GenClk state, as a visitor of each AstNode
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class GenClkBaseVisitor VL_NOT_FINAL : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
protected:
|
2018-05-14 12:50:47 +02:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// GenClk Read
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class GenClkRenameVisitor final : public GenClkBaseVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on top scope
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstVarScope::user2() -> AstVarScope*. Signal replacing activation with
|
|
|
|
|
// AstVarRef::user3() -> bool. Signal is replaced activation (already done)
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser2InUse m_inuser2;
|
|
|
|
|
const VNUser3InUse m_inuser3;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// STATE
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstActive* m_activep = nullptr; // Inside activate statement
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeModule* const m_topModp; // Top module
|
2021-10-17 11:29:17 +02:00
|
|
|
AstScope* const m_scopetopp = v3Global.rootp()->topScopep()->scopep(); // The top AstScope
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
AstVarScope* genInpClk(AstVarScope* vscp) {
|
2022-02-11 11:46:02 +01:00
|
|
|
if (!vscp->user2p()) {
|
2021-08-12 22:43:32 +02:00
|
|
|
// In order to create a __VinpClk* for a signal, it needs to be marked circular.
|
|
|
|
|
// The DPI export trigger is never marked circular by V3Order (see comments in
|
|
|
|
|
// OrderVisitor::nodeMarkCircular). The only other place where one might mark
|
|
|
|
|
// a node circular is in this pass (V3GenClk), if the signal is assigned but was
|
|
|
|
|
// previously used as a clock. The DPI export trigger is only ever assigned in
|
|
|
|
|
// a DPI export called from outside eval, or from a DPI import, which are not
|
|
|
|
|
// discovered by GenClkReadVisitor (note that impure tasks - i.e.: those setting
|
|
|
|
|
// non-local variables - cannot be no-inline, see V3Task), hence the DPI export
|
|
|
|
|
// trigger should never be marked circular. Note that ordering should still be
|
|
|
|
|
// correct as there will be a change detect on any signals set from a DPI export
|
|
|
|
|
// that might have dependents scheduled earlier.
|
|
|
|
|
UASSERT_OBJ(vscp != v3Global.rootp()->dpiExportTriggerp(), vscp,
|
|
|
|
|
"DPI export trigger should not need __VinpClk");
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVar* const varp = vscp->varp();
|
2021-11-26 23:55:36 +01:00
|
|
|
const string newvarname
|
2020-04-15 13:58:34 +02:00
|
|
|
= "__VinpClk__" + vscp->scopep()->nameDotless() + "__" + varp->name();
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create: VARREF(inpclk)
|
|
|
|
|
// ...
|
|
|
|
|
// ASSIGN(VARREF(inpclk), VARREF(var))
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVar* const newvarp
|
2022-01-02 19:56:40 +01:00
|
|
|
= new AstVar(varp->fileline(), VVarType::MODULETEMP, newvarname, varp);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_topModp->addStmtp(newvarp);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_scopetopp->addVarp(newvscp);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstAssign* const asninitp = new AstAssign(
|
2020-09-07 23:09:25 +02:00
|
|
|
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
|
|
|
|
|
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
|
2019-05-19 22:13:13 +02:00
|
|
|
m_scopetopp->addFinalClkp(asninitp);
|
|
|
|
|
//
|
|
|
|
|
vscp->user2p(newvscp);
|
|
|
|
|
}
|
2022-02-11 11:46:02 +01:00
|
|
|
return VN_AS(vscp->user2p(), VarScope);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstVarRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Consumption/generation of a variable,
|
2022-02-11 11:46:02 +01:00
|
|
|
if (m_activep && !nodep->user3SetOnce()) {
|
|
|
|
|
AstVarScope* const vscp = nodep->varScopep();
|
2019-05-19 22:13:13 +02:00
|
|
|
if (vscp->isCircular()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " VarActReplace " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Replace with the new variable
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVarScope* const newvscp = genInpClk(vscp);
|
|
|
|
|
AstVarRef* const newrefp
|
|
|
|
|
= new AstVarRef(nodep->fileline(), newvscp, nodep->access());
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newrefp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstActive* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_activep = nodep;
|
2021-10-26 02:19:49 +02:00
|
|
|
iterate(nodep->sensesp());
|
2020-08-15 16:12:55 +02:00
|
|
|
m_activep = nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
GenClkRenameVisitor(AstTopScope* nodep, AstNodeModule* topModp)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_topModp{topModp} {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
virtual ~GenClkRenameVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// GenClk Read
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class GenClkReadVisitor final : public GenClkBaseVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on top scope
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstVarScope::user() -> bool. Set when the var has been used as clock
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// STATE
|
2020-08-15 19:11:27 +02:00
|
|
|
bool m_tracingCall = false; // Iterating into a call to a cfunc
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstActive* m_activep = nullptr; // Inside activate statement
|
|
|
|
|
const AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
|
2020-08-15 19:11:27 +02:00
|
|
|
AstNodeModule* m_topModp = nullptr; // Top module
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// VISITORS
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstTopScope* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
{
|
2022-02-11 11:46:02 +01:00
|
|
|
const VNUser1InUse user1InUse;
|
|
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-02-11 11:46:02 +01:00
|
|
|
// Make the new clock signals and replace any activate references
|
|
|
|
|
// See rename, it does some AstNode::userClearTree()'s
|
|
|
|
|
GenClkRenameVisitor{nodep, m_topModp};
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Only track the top scopes, not lower level functions
|
|
|
|
|
if (nodep->isTop()) {
|
|
|
|
|
m_topModp = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstNodeCCall* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2017-11-29 00:38:19 +01:00
|
|
|
if (!nodep->funcp()->entryPoint()) {
|
|
|
|
|
// Enter the function and trace it
|
|
|
|
|
m_tracingCall = true;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterate(nodep->funcp());
|
2017-11-29 00:38:19 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstCFunc* nodep) override {
|
2017-11-29 00:38:19 +01:00
|
|
|
if (!m_tracingCall && !nodep->entryPoint()) {
|
2017-11-23 14:21:20 +01:00
|
|
|
// Only consider logic within a CFunc when looking
|
|
|
|
|
// at the call to it, and not when scanning whatever
|
|
|
|
|
// scope it happens to live beneath.
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-11-29 00:38:19 +01:00
|
|
|
m_tracingCall = false;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2017-11-23 14:21:20 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
//----
|
|
|
|
|
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstVarRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Consumption/generation of a variable,
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVarScope* const vscp = nodep->varScopep();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_activep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " VarAct " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
vscp->user1(true);
|
|
|
|
|
}
|
2020-11-07 16:37:55 +01:00
|
|
|
if (m_assignp && nodep->access().isWriteOrRW() && vscp->user1()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Variable was previously used as a clock, and is now being set
|
|
|
|
|
// Thus a unordered generated clock...
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " VarSetAct " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
vscp->circular(true);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstNodeAssign* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
// UINFO(8, "ASS " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignp = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_assignp = nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstActive* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, "ACTIVE " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_activep = nodep;
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
2021-10-26 02:19:49 +02:00
|
|
|
iterate(nodep->sensesp());
|
2020-08-15 16:12:55 +02:00
|
|
|
m_activep = nullptr;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----
|
2020-08-15 16:03:34 +02:00
|
|
|
virtual void visit(AstVar*) override {} // Don't want varrefs under it
|
|
|
|
|
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
explicit GenClkReadVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2020-11-17 01:56:16 +01:00
|
|
|
virtual ~GenClkReadVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// GenClk class functions
|
|
|
|
|
|
|
|
|
|
void V3GenClk::genClkAll(AstNetlist* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2021-11-26 16:52:36 +01:00
|
|
|
{ GenClkReadVisitor{nodep}; } // Destruct before checking
|
2017-09-18 04:52:57 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|