mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
162 lines
6.8 KiB
C++
162 lines
6.8 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
// DESCRIPTION: Verilator: Block code ordering
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you
|
|
// 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
|
|
//
|
|
//*************************************************************************
|
|
// V3Order's Transformations:
|
|
//
|
|
// Compute near optimal scheduling of always/wire statements
|
|
// Make a graph of the entire netlist
|
|
//
|
|
// For seq logic
|
|
// Add logic_sensitive_vertex for this list of SenItems
|
|
// Add edge for each sensitive_var->logic_sensitive_vertex
|
|
// For AssignPre's
|
|
// 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.
|
|
// 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
|
|
// For Logic
|
|
// Add vertex for this logic
|
|
// Add edge logic_sensitive_vertex->logic_vertex
|
|
// Add edge logic_generated_var_PREORDER->logic_vertex
|
|
// This ensures the AssignPre gets scheduled before this logic
|
|
// 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)
|
|
// For AssignPost's
|
|
// 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)
|
|
// Add edge consumed_var_POST->logic_vertex (same as if comb)
|
|
//
|
|
// 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.
|
|
//
|
|
//
|
|
//
|
|
// Rank the graph starting at INPUTS (see V3Graph)
|
|
//
|
|
// Visit the graph's logic vertices in ranked order
|
|
// 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.
|
|
//
|
|
//*************************************************************************
|
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
#include "V3OrderInternal.h"
|
|
#include "V3Sched.h"
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
void V3Order::orderOrderGraph(OrderGraph& graph, const std::string& tag) {
|
|
// Dump data
|
|
if (dumpGraphLevel()) graph.dumpDotFilePrefixed(tag + "_orderg_pre");
|
|
|
|
// 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");
|
|
|
|
// 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");
|
|
}
|
|
|
|
//######################################################################
|
|
|
|
AstCFunc* V3Order::order(AstNetlist* netlistp, //
|
|
const std::vector<V3Sched::LogicByScope*>& logic, //
|
|
const V3Order::TrigToSenMap& trigToSen,
|
|
const string& tag, //
|
|
bool parallel, //
|
|
bool slow, //
|
|
const ExternalDomainsProvider& externalDomains) {
|
|
FileLine* const flp = netlistp->fileline();
|
|
|
|
// Create the result function
|
|
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;
|
|
}();
|
|
|
|
if (v3Global.opt.profExec()) {
|
|
funcp->addStmtsp(new AstCStmt{flp, "VL_EXEC_TRACE_ADD_RECORD(vlSymsp).sectionPush(\"func "
|
|
+ tag + "\");\n"});
|
|
}
|
|
|
|
// Build the OrderGraph
|
|
const std::unique_ptr<OrderGraph> graph = buildOrderGraph(netlistp, logic, trigToSen);
|
|
// Order it
|
|
orderOrderGraph(*graph, tag);
|
|
// Assign sensitivity domains to combinational logic
|
|
processDomains(netlistp, *graph, tag, externalDomains);
|
|
|
|
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);
|
|
}
|
|
|
|
// Dump data
|
|
if (dumpGraphLevel()) graph->dumpDotFilePrefixed(tag + "_orderg_done");
|
|
|
|
// Dispose of the remnants of the inputs
|
|
for (auto* const lbsp : logic) lbsp->deleteActives();
|
|
|
|
if (v3Global.opt.profExec()) {
|
|
funcp->addStmtsp(new AstCStmt{flp, "VL_EXEC_TRACE_ADD_RECORD(vlSymsp).sectionPop();\n"});
|
|
}
|
|
|
|
// Done
|
|
return funcp;
|
|
}
|