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: Break always into sensitivity active domains
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2024-01-01 09:19:59 +01:00
|
|
|
// Copyright 2003-2024 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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Active's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Note this can be called multiple times.
|
|
|
|
|
// Across all ACTIVES
|
2019-05-19 22:13:13 +02:00
|
|
|
// SenTrees are now under each ACTIVE statement, we want them global:
|
|
|
|
|
// Find SenTree in under global TopScope, or create it there
|
|
|
|
|
// Move SenTree the global SenTree
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3ActiveTop.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2009-01-07 15:37:59 +01:00
|
|
|
#include "V3Const.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3SenTree.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Active class functions
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class ActiveTopVisitor final : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
// STATE
|
2021-10-17 11:29:17 +02:00
|
|
|
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
|
2009-01-21 22:56:50 +01:00
|
|
|
|
|
|
|
|
// METHODS
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
static bool isInitial(AstNode* nodep) {
|
|
|
|
|
const VNUser1InUse user1InUse;
|
|
|
|
|
// Return true if no variables that read.
|
2022-10-20 14:48:44 +02:00
|
|
|
return nodep->forall([&](const AstVarRef* refp) -> bool {
|
2022-05-15 17:03:32 +02:00
|
|
|
AstVarScope* const vscp = refp->varScopep();
|
|
|
|
|
// Note: Use same heuristic as ordering does to ignore written variables
|
|
|
|
|
// TODO: Use live variable analysis.
|
|
|
|
|
if (refp->access().isWriteOnly()) {
|
|
|
|
|
vscp->user1(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Read or ReadWrite: OK if written before
|
|
|
|
|
return vscp->user1();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create required actives and add to module
|
|
|
|
|
// We can start ordering at a module, or a scope
|
2020-04-14 04:51:35 +02:00
|
|
|
UINFO(4, " MOD " << nodep << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstActive* nodep) override {
|
2020-04-14 04:51:35 +02:00
|
|
|
UINFO(4, " ACTIVE " << nodep << endl);
|
|
|
|
|
// Remove duplicate clocks and such; sensesp() may change!
|
|
|
|
|
V3Const::constifyExpensiveEdit(nodep);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSenTree* const sensesp = nodep->sensesp();
|
2020-08-15 16:12:55 +02:00
|
|
|
UASSERT_OBJ(sensesp, nodep, "nullptr");
|
2021-10-22 18:36:58 +02:00
|
|
|
if (sensesp->sensesp() && sensesp->sensesp()->isNever()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Never executing. Kill it.
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
|
|
|
|
|
"Never senitem should be alone, else the never should be eliminated.");
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Move the SENTREE for each active up to the global level.
|
|
|
|
|
// This way we'll easily see what clock domains are identical
|
2021-11-13 19:50:44 +01:00
|
|
|
AstSenTree* const wantp = m_finder.getSenTree(sensesp);
|
2020-04-14 04:51:35 +02:00
|
|
|
UINFO(4, " lookdone\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
if (wantp != sensesp) {
|
|
|
|
|
// Move the active's contents to the other active
|
2020-04-14 04:51:35 +02:00
|
|
|
UINFO(4, " merge active " << sensesp << " into " << wantp << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->sensesStorep()) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp == nodep->sensesStorep(), nodep,
|
|
|
|
|
"sensesStore should have been deleted earlier if different");
|
2019-05-19 22:13:13 +02:00
|
|
|
sensesp->unlinkFrBack();
|
|
|
|
|
// There may be other references to same sense tree,
|
|
|
|
|
// we'll be removing all references when we get to them,
|
|
|
|
|
// but don't dangle our pointer yet!
|
|
|
|
|
pushDeletep(sensesp);
|
|
|
|
|
}
|
|
|
|
|
nodep->sensesp(wantp);
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
|
|
|
|
|
// If this is combinational logic that does not read any variables, then it really is an
|
|
|
|
|
// initial block in disguise, so move such logic under an Initial AstActive, V3Order would
|
|
|
|
|
// prune these otherwise.
|
|
|
|
|
// TODO: we should warn for these if they were 'always @*' as some (including strictly
|
|
|
|
|
// compliant) simulators will never execute these.
|
|
|
|
|
if (nodep->sensesp()->hasCombo()) {
|
|
|
|
|
FileLine* const flp = nodep->fileline();
|
|
|
|
|
AstActive* initialp = nullptr;
|
|
|
|
|
for (AstNode *logicp = nodep->stmtsp(), *nextp; logicp; logicp = nextp) {
|
|
|
|
|
nextp = logicp->nextp();
|
|
|
|
|
if (!isInitial(logicp)) continue;
|
|
|
|
|
if (!initialp) initialp = new AstActive{flp, "", m_finder.getInitial()};
|
|
|
|
|
initialp->addStmtsp(logicp->unlinkFrBack());
|
|
|
|
|
}
|
|
|
|
|
if (initialp) nodep->addHereThisAsNext(initialp);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
2010-04-06 02:01:17 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
//--------------------
|
2022-10-12 11:19:21 +02:00
|
|
|
void visit(AstNodeExpr*) override {} // Accelerate
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarScope*) override {} // Accelerate
|
|
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2020-04-04 04:31:54 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2022-09-16 12:22:11 +02:00
|
|
|
~ActiveTopVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Active class functions
|
|
|
|
|
|
|
|
|
|
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
2020-04-14 04:51:35 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2021-11-26 16:52:36 +01:00
|
|
|
{ ActiveTopVisitor{nodep}; } // Destruct before checking
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeEitherLevel() >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|