diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 291cc1a68..8a7f69be0 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -895,10 +895,10 @@ class OrderProcess final : VNDeleter { // Map from Trigger reference AstSenItem to the original AstSenTree const std::unordered_map& m_trigToSen; - // This is a function provided by the invoker of the ordering that can and provide additional + // This is a function provided by the invoker of the ordering that can provide additional // sensitivity expression that when triggered indicates the passed AstVarScope might have // changed external to the code being ordered. - const std::function m_externalDomain; + const V3Order::ExternalDomainsProvider m_externalDomains; SenTreeFinder m_finder; // Global AstSenTree manager AstSenTree* const m_deleteDomainp; // Dummy AstSenTree indicating needs deletion @@ -957,6 +957,8 @@ class OrderProcess final : VNDeleter { // Make a domain that merges the two domains AstSenTree* combineDomains(AstSenTree* ap, AstSenTree* bp) { + if (ap == m_deleteDomainp) return bp; + UASSERT_OBJ(bp != m_deleteDomainp, bp, "Should not be delete domain"); AstSenTree* const senTreep = ap->cloneTree(false); senTreep->addSensesp(bp->sensesp()->cloneTree(true)); V3Const::constifyExpensiveEdit(senTreep); // Remove duplicates @@ -974,11 +976,10 @@ class OrderProcess final : VNDeleter { // CONSTRUCTOR OrderProcess(AstNetlist* netlistp, OrderGraph& graph, const std::unordered_map& trigToSen, - const string& tag, bool slow, - std::function externalDomain) + const string& tag, bool slow, V3Order::ExternalDomainsProvider externalDomains) : m_graph{graph} , m_trigToSen{trigToSen} - , m_externalDomain{externalDomain} + , m_externalDomains{externalDomains} , m_finder{netlistp} , m_deleteDomainp{makeDeleteDomainSenTree(netlistp->fileline())} , m_tag{tag} @@ -994,8 +995,8 @@ public: main(AstNetlist* netlistp, OrderGraph& graph, const std::unordered_map& trigToSen, const string& tag, bool parallel, bool slow, - std::function externalDomain) { - OrderProcess visitor{netlistp, graph, trigToSen, tag, slow, externalDomain}; + V3Order::ExternalDomainsProvider externalDomains) { + OrderProcess visitor{netlistp, graph, trigToSen, tag, slow, externalDomains}; visitor.process(parallel); return std::move(visitor.m_result); } @@ -1046,6 +1047,9 @@ void OrderProcess::processDomainsIterate(OrderEitherVertex* vertexp) { if (OrderLogicVertex* const lvtxp = dynamic_cast(vertexp)) { domainp = lvtxp->hybridp(); } + + std::vector externalDomainps; + for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { OrderEitherVertex* const fromVertexp = static_cast(edgep->fromp()); if (edgep->weight() && fromVertexp->domainMatters()) { @@ -1054,12 +1058,13 @@ void OrderProcess::processDomainsIterate(OrderEitherVertex* vertexp) { if (OrderVarVertex* const varVtxp = dynamic_cast(fromVertexp)) { AstVarScope* const vscp = varVtxp->vscp(); - if (AstSenTree* const externalDomainp = m_externalDomain(vscp)) { - UASSERT(!externalDomainp->hasCombo(), - "There should be no need for combinational domains"); - fromDomainp = fromDomainp == m_deleteDomainp - ? externalDomainp - : combineDomains(fromDomainp, externalDomainp); + // Add in any external domains + externalDomainps.clear(); + m_externalDomains(vscp, externalDomainps); + for (AstSenTree* const externalDomainp : externalDomainps) { + UASSERT_OBJ(!externalDomainp->hasCombo(), vscp, + "There should be no need for combinational domains"); + fromDomainp = combineDomains(fromDomainp, externalDomainp); } } @@ -1538,12 +1543,12 @@ AstCFunc* order(AstNetlist* netlistp, // const string& tag, // bool parallel, // bool slow, // - std::function externalDomain) { + ExternalDomainsProvider externalDomains) { // Order the code const std::unique_ptr graph = OrderBuildVisitor::process(netlistp, logic, trigToSen); const auto& nodeps = OrderProcess::main(netlistp, *graph.get(), trigToSen, tag, parallel, slow, - externalDomain); + externalDomains); // Create the result function AstScope* const scopeTopp = netlistp->topScopep()->scopep(); diff --git a/src/V3Order.h b/src/V3Order.h index 12ef3d2eb..9dc6a0fdf 100644 --- a/src/V3Order.h +++ b/src/V3Order.h @@ -38,13 +38,17 @@ struct LogicByScope; namespace V3Order { -AstCFunc* order(AstNetlist* netlistp, // - const std::vector& logic, // - const std::unordered_map& trigToSen, - const string& tag, // - bool parallel, // - bool slow, // - std::function externalDomain); +using ExternalDomainsProvider = std::function&)>; + +AstCFunc* order( + AstNetlist* netlistp, // + const std::vector& logic, // + const std::unordered_map& trigToSen, + const string& tag, // + bool parallel, // + bool slow, // + ExternalDomainsProvider externalDomains + = [](const AstVarScope*, std::vector&) {}); }; // namespace V3Order diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index a44fe75c1..129761da9 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -699,9 +699,9 @@ void createSettle(AstNetlist* netlistp, SenExprBuilder& senExprBulider, AstSenTree* const inputChanged = trig.createTriggerSenTree(netlistp, firstIterationTrigger); // Create and the body function - AstCFunc* const stlFuncp - = V3Order::order(netlistp, {&comb, &hybrid}, trigToSen, "stl", false, true, - [=](const AstVarScope*) { return inputChanged; }); + AstCFunc* const stlFuncp = V3Order::order( + netlistp, {&comb, &hybrid}, trigToSen, "stl", false, true, + [=](const AstVarScope*, std::vector& out) { out.push_back(inputChanged); }); splitCheck(stlFuncp); // Create the eval loop @@ -763,10 +763,13 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, SenExprBuilder& senExprBuilde AstSenTree* const inputChanged = trig.createTriggerSenTree(netlistp, firstIterationTrigger); // Create and Order the body function - AstCFunc* const icoFuncp = V3Order::order( - netlistp, {&logic}, trigToSen, "ico", false, false, [=](const AstVarScope* vscp) { - return vscp->scopep()->isTop() && vscp->varp()->isNonOutput() ? inputChanged : nullptr; - }); + AstCFunc* const icoFuncp + = V3Order::order(netlistp, {&logic}, trigToSen, "ico", false, false, + [=](const AstVarScope* vscp, std::vector& out) { + if (vscp->scopep()->isTop() && vscp->varp()->isNonOutput()) { + out.push_back(inputChanged); + } + }); splitCheck(icoFuncp); // Create the eval loop @@ -1016,7 +1019,7 @@ void schedule(AstNetlist* netlistp) { AstCFunc* const actFuncp = V3Order::order( netlistp, {&logicRegions.m_pre, &logicRegions.m_act, &logicReplicas.m_act}, trigToSenAct, - "act", false, false, [](const AstVarScope*) { return nullptr; }); + "act", false, false); splitCheck(actFuncp); if (v3Global.opt.stats()) V3Stats::statsStage("sched-create-act"); @@ -1030,9 +1033,9 @@ void schedule(AstNetlist* netlistp) { std::unordered_map trigToSenNba; invertAndMergeSenTreeMap(trigToSenNba, nbaTrigMap); - AstCFunc* const nbaFuncp = V3Order::order( - netlistp, {&logicRegions.m_nba, &logicReplicas.m_nba}, trigToSenNba, "nba", - v3Global.opt.mtasks(), false, [](const AstVarScope*) { return nullptr; }); + AstCFunc* const nbaFuncp + = V3Order::order(netlistp, {&logicRegions.m_nba, &logicReplicas.m_nba}, trigToSenNba, + "nba", v3Global.opt.mtasks(), false); splitCheck(nbaFuncp); netlistp->evalNbap(nbaFuncp); // Remember for V3LifePost if (v3Global.opt.stats()) V3Stats::statsStage("sched-create-nba");