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: Block code ordering
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Order's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Compute near optimal scheduling of always/wire statements
|
|
|
|
|
// Make a graph of the entire netlist
|
|
|
|
|
//
|
2019-05-19 22:13:13 +02:00
|
|
|
// For seq logic
|
|
|
|
|
// Add logic_sensitive_vertex for this list of SenItems
|
|
|
|
|
// Add edge for each sensitive_var->logic_sensitive_vertex
|
2025-08-19 10:27:59 +02:00
|
|
|
// For AlwaysPre's
|
2019-05-19 22:13:13 +02:00
|
|
|
// Add vertex for this logic
|
|
|
|
|
// Add edge logic_sensitive_vertex->logic_vertex
|
|
|
|
|
// Add edge logic_consumed_var_PREVAR->logic_vertex
|
|
|
|
|
// Add edge logic_vertex->logic_generated_var (same as if comb)
|
|
|
|
|
// Add edge logic_vertex->generated_var_PREORDER
|
|
|
|
|
// Cutable dependency to attempt to order dlyed
|
|
|
|
|
// assignments to avoid saving state, thus we prefer
|
|
|
|
|
// a <= b ... As the opposite order would
|
|
|
|
|
// b <= c ... require the old value of b.
|
2020-10-24 00:30:10 +02:00
|
|
|
// Add edge consumed_var_POST->logic_vertex
|
|
|
|
|
// This prevents a consumer of the "early" value to be
|
|
|
|
|
// scheduled after we've changed to the next-cycle value
|
2019-05-19 22:13:13 +02:00
|
|
|
// For Logic
|
|
|
|
|
// Add vertex for this logic
|
|
|
|
|
// Add edge logic_sensitive_vertex->logic_vertex
|
|
|
|
|
// Add edge logic_generated_var_PREORDER->logic_vertex
|
2025-08-19 10:27:59 +02:00
|
|
|
// This ensures the AlwaysPre gets scheduled before this logic
|
2019-05-19 22:13:13 +02:00
|
|
|
// Add edge logic_vertex->consumed_var_PREVAR
|
|
|
|
|
// Add edge logic_vertex->consumed_var_POSTVAR
|
|
|
|
|
// Add edge logic_vertex->logic_generated_var (same as if comb)
|
2025-08-19 10:27:59 +02:00
|
|
|
// For AlwaysPost's
|
2019-05-19 22:13:13 +02:00
|
|
|
// Add vertex for this logic
|
|
|
|
|
// Add edge logic_sensitive_vertex->logic_vertex
|
|
|
|
|
// Add edge logic_consumed_var->logic_vertex (same as if comb)
|
|
|
|
|
// Add edge logic_vertex->logic_generated_var (same as if comb)
|
2020-10-24 00:30:10 +02:00
|
|
|
// Add edge consumed_var_POST->logic_vertex (same as if comb)
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
2019-05-19 22:13:13 +02:00
|
|
|
// For comb logic
|
|
|
|
|
// For comb logic
|
|
|
|
|
// Add vertex for this logic
|
|
|
|
|
// Add edge logic_consumed_var->logic_vertex
|
|
|
|
|
// Add edge logic_vertex->logic_generated_var
|
|
|
|
|
// Mark it cutable, as circular logic may require
|
|
|
|
|
// the generated signal to become a primary input again.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Rank the graph starting at INPUTS (see V3Graph)
|
|
|
|
|
//
|
|
|
|
|
// Visit the graph's logic vertices in ranked order
|
2019-05-19 22:13:13 +02:00
|
|
|
// For all logic vertices with all inputs already ordered
|
|
|
|
|
// Make ordered block for this module
|
|
|
|
|
// For all ^^ in same domain
|
|
|
|
|
// Move logic to ordered activation
|
|
|
|
|
// When we have no more choices, we move to the next module
|
|
|
|
|
// and make a new block. Add that new activation block to the list of calls to make.
|
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
|
|
|
|
|
|
2024-03-07 23:12:19 +01:00
|
|
|
#include "V3OrderInternal.h"
|
2022-08-05 13:15:59 +02:00
|
|
|
#include "V3Sched.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <memory>
|
2022-08-05 11:56:57 +02:00
|
|
|
#include <vector>
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2024-03-09 13:43:09 +01:00
|
|
|
void V3Order::orderOrderGraph(OrderGraph& graph, const std::string& tag) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// Dump data
|
2024-03-09 13:43:09 +01:00
|
|
|
if (dumpGraphLevel()) graph.dumpDotFilePrefixed(tag + "_orderg_pre");
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2024-03-09 13:43:09 +01:00
|
|
|
// Break cycles. Note that the OrderGraph only contains cuttable cycles
|
|
|
|
|
// (soft constraints). Actual logic loops must have been eliminated by
|
|
|
|
|
// the introduction of Hybid sensitivity expressions, before invoking
|
|
|
|
|
// ordering (e.g. in V3SchedAcyclic).
|
|
|
|
|
graph.acyclic(&V3GraphEdge::followAlwaysTrue);
|
|
|
|
|
if (dumpGraphLevel()) graph.dumpDotFilePrefixed(tag + "_orderg_acyc");
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2024-03-09 13:43:09 +01:00
|
|
|
// Assign ranks so we know what to follow, then sort vertices and edges by that ordering
|
|
|
|
|
graph.order();
|
|
|
|
|
if (dumpGraphLevel()) graph.dumpDotFilePrefixed(tag + "_orderg_order");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2022-05-15 17:03:32 +02:00
|
|
|
|
2024-03-07 23:12:19 +01:00
|
|
|
AstCFunc* V3Order::order(AstNetlist* netlistp, //
|
|
|
|
|
const std::vector<V3Sched::LogicByScope*>& logic, //
|
2024-03-09 13:43:09 +01:00
|
|
|
const V3Order::TrigToSenMap& trigToSen,
|
2024-03-07 23:12:19 +01:00
|
|
|
const string& tag, //
|
|
|
|
|
bool parallel, //
|
|
|
|
|
bool slow, //
|
|
|
|
|
const ExternalDomainsProvider& externalDomains) {
|
2024-03-09 13:43:09 +01:00
|
|
|
FileLine* const flp = netlistp->fileline();
|
2022-05-15 17:03:32 +02:00
|
|
|
|
|
|
|
|
// Create the result function
|
2024-03-09 13:43:09 +01:00
|
|
|
AstCFunc* const funcp = [&]() {
|
|
|
|
|
AstScope* const scopeTopp = netlistp->topScopep()->scopep();
|
|
|
|
|
AstCFunc* const resp = new AstCFunc{flp, "_eval_" + tag, scopeTopp, ""};
|
|
|
|
|
resp->dontCombine(true);
|
|
|
|
|
resp->isStatic(false);
|
|
|
|
|
resp->isLoose(true);
|
|
|
|
|
resp->slow(slow);
|
|
|
|
|
resp->isConst(false);
|
|
|
|
|
resp->declPrivate(true);
|
|
|
|
|
scopeTopp->addBlocksp(resp);
|
|
|
|
|
return resp;
|
|
|
|
|
}();
|
2022-05-15 17:03:32 +02:00
|
|
|
|
2023-05-10 13:12:34 +02:00
|
|
|
if (v3Global.opt.profExec()) {
|
2024-12-23 16:10:46 +01:00
|
|
|
const string name
|
|
|
|
|
= (v3Global.opt.hierChild() ? (v3Global.opt.topModule() + " ") : "") + "func " + tag;
|
|
|
|
|
funcp->addStmtsp(new AstCStmt{flp, "VL_EXEC_TRACE_ADD_RECORD(vlSymsp).sectionPush(\""
|
|
|
|
|
+ name + "\");\n"});
|
2023-05-10 13:12:34 +02:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 13:43:09 +01:00
|
|
|
// Build the OrderGraph
|
|
|
|
|
const std::unique_ptr<OrderGraph> graph = buildOrderGraph(netlistp, logic, trigToSen);
|
|
|
|
|
// Order it
|
|
|
|
|
orderOrderGraph(*graph, tag);
|
|
|
|
|
// Assign sensitivity domains to combinational logic
|
2024-09-25 11:35:50 +02:00
|
|
|
processDomains(netlistp, *graph, tag, externalDomains);
|
2024-03-09 13:43:09 +01:00
|
|
|
|
|
|
|
|
if (parallel) {
|
|
|
|
|
// Construct the parallel ExecGraph
|
|
|
|
|
AstExecGraph* const execGraphp = createParallel(*graph, tag, trigToSen, slow);
|
|
|
|
|
// Add the ExecGraph to the result function.
|
|
|
|
|
funcp->addStmtsp(execGraphp);
|
|
|
|
|
} else {
|
|
|
|
|
// Construct the serial code
|
|
|
|
|
const std::vector<AstActive*> activeps = createSerial(*graph, tag, trigToSen, slow);
|
|
|
|
|
// Add the resulting Active blocks to the result function
|
|
|
|
|
for (AstNode* const nodep : activeps) funcp->addStmtsp(nodep);
|
2023-05-10 13:12:34 +02:00
|
|
|
}
|
|
|
|
|
|
2024-03-09 13:43:09 +01:00
|
|
|
// Dump data
|
|
|
|
|
if (dumpGraphLevel()) graph->dumpDotFilePrefixed(tag + "_orderg_done");
|
|
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
// Dispose of the remnants of the inputs
|
|
|
|
|
for (auto* const lbsp : logic) lbsp->deleteActives();
|
|
|
|
|
|
2024-03-09 13:43:09 +01:00
|
|
|
if (v3Global.opt.profExec()) {
|
|
|
|
|
funcp->addStmtsp(new AstCStmt{flp, "VL_EXEC_TRACE_ADD_RECORD(vlSymsp).sectionPop();\n"});
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
// Done
|
|
|
|
|
return funcp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|