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: main()
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Active.h"
|
|
|
|
|
#include "V3ActiveTop.h"
|
|
|
|
|
#include "V3Assert.h"
|
|
|
|
|
#include "V3AssertPre.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Ast.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Begin.h"
|
|
|
|
|
#include "V3Branch.h"
|
2020-12-08 05:15:29 +01:00
|
|
|
#include "V3Broken.h"
|
2020-05-09 21:00:46 +02:00
|
|
|
#include "V3CCtors.h"
|
|
|
|
|
#include "V3CUse.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Case.h"
|
|
|
|
|
#include "V3Cast.h"
|
2020-05-09 21:00:46 +02:00
|
|
|
#include "V3Cdc.h"
|
2020-04-05 15:30:23 +02:00
|
|
|
#include "V3Class.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Clean.h"
|
|
|
|
|
#include "V3Clock.h"
|
|
|
|
|
#include "V3Combine.h"
|
2021-07-20 17:40:38 +02:00
|
|
|
#include "V3Common.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Const.h"
|
|
|
|
|
#include "V3Coverage.h"
|
2008-12-12 21:34:02 +01:00
|
|
|
#include "V3CoverageJoin.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Dead.h"
|
|
|
|
|
#include "V3Delayed.h"
|
|
|
|
|
#include "V3Depth.h"
|
2007-04-19 20:20:16 +02:00
|
|
|
#include "V3DepthBlock.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Descope.h"
|
Introduce DFG based combinational logic optimizer (#3527)
Added a new data-flow graph (DFG) based combinational logic optimizer.
The capabilities of this covers a combination of V3Const and V3Gate, but
is also more capable of transforming combinational logic into simplified
forms and more.
This entail adding a new internal representation, `DfgGraph`, and
appropriate `astToDfg` and `dfgToAst` conversion functions. The graph
represents some of the combinational equations (~continuous assignments)
in a module, and for the duration of the DFG passes, it takes over the
role of AstModule. A bulk of the Dfg vertices represent expressions.
These vertex classes, and the corresponding conversions to/from AST are
mostly auto-generated by astgen, together with a DfgVVisitor that can be
used for dynamic dispatch based on vertex (operation) types.
The resulting combinational logic graph (a `DfgGraph`) is then optimized
in various ways. Currently we perform common sub-expression elimination,
variable inlining, and some specific peephole optimizations, but there
is scope for more optimizations in the future using the same
representation. The optimizer is run directly before and after inlining.
The pre inline pass can operate on smaller graphs and hence converges
faster, but still has a chance of substantially reducing the size of the
logic on some designs, making inlining both faster and less memory
intensive. The post inline pass can then optimize across the inlined
module boundaries. No optimization is performed across a module
boundary.
For debugging purposes, each peephole optimization can be disabled
individually via the -fno-dfg-peepnole-<OPT> option, where <OPT> is one
of the optimizations listed in V3DfgPeephole.h, for example
-fno-dfg-peephole-remove-not-not.
The peephole patterns currently implemented were mostly picked based on
the design that inspired this work, and on that design the optimizations
yields ~30% single threaded speedup, and ~50% speedup on 4 threads. As
you can imagine not having to haul around redundant combinational
networks in the rest of the compilation pipeline also helps with memory
consumption, and up to 30% peak memory usage of Verilator was observed
on the same design.
Gains on other arbitrary designs are smaller (and can be improved by
analyzing those designs). For example OpenTitan gains between 1-15%
speedup depending on build type.
2022-09-23 17:46:22 +02:00
|
|
|
#include "V3DfgOptimizer.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3EmitC.h"
|
2020-04-22 02:45:23 +02:00
|
|
|
#include "V3EmitCMain.h"
|
2020-05-09 21:00:46 +02:00
|
|
|
#include "V3EmitCMake.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3EmitMk.h"
|
|
|
|
|
#include "V3EmitV.h"
|
2012-03-20 21:13:10 +01:00
|
|
|
#include "V3EmitXml.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Expand.h"
|
|
|
|
|
#include "V3File.h"
|
2022-01-01 18:24:19 +01:00
|
|
|
#include "V3Force.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Gate.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
2010-02-14 16:01:21 +01:00
|
|
|
#include "V3Graph.h"
|
2020-08-15 15:43:53 +02:00
|
|
|
#include "V3HierBlock.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Inline.h"
|
|
|
|
|
#include "V3Inst.h"
|
|
|
|
|
#include "V3Life.h"
|
|
|
|
|
#include "V3LifePost.h"
|
|
|
|
|
#include "V3LinkDot.h"
|
2020-05-29 00:08:15 +02:00
|
|
|
#include "V3LinkInc.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3LinkJump.h"
|
2010-02-14 16:01:21 +01:00
|
|
|
#include "V3LinkLValue.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3LinkLevel.h"
|
2006-12-21 22:53:51 +01:00
|
|
|
#include "V3LinkParse.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3LinkResolve.h"
|
|
|
|
|
#include "V3Localize.h"
|
2020-05-30 22:09:05 +02:00
|
|
|
#include "V3MergeCond.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Name.h"
|
2015-02-27 02:40:45 +01:00
|
|
|
#include "V3Os.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Param.h"
|
2012-08-16 03:28:30 +02:00
|
|
|
#include "V3ParseSym.h"
|
2018-07-23 02:54:28 +02:00
|
|
|
#include "V3Partition.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3PreShell.h"
|
|
|
|
|
#include "V3Premit.h"
|
2019-10-09 12:47:26 +02:00
|
|
|
#include "V3ProtectLib.h"
|
2020-12-07 23:55:22 +01:00
|
|
|
#include "V3Randomize.h"
|
2018-06-23 23:07:22 +02:00
|
|
|
#include "V3Reloop.h"
|
2022-05-15 17:03:32 +02:00
|
|
|
#include "V3Sched.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Scope.h"
|
2018-07-16 04:09:27 +02:00
|
|
|
#include "V3Scoreboard.h"
|
2010-01-19 16:52:11 +01:00
|
|
|
#include "V3Slice.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Split.h"
|
2007-01-18 01:51:26 +01:00
|
|
|
#include "V3SplitAs.h"
|
2020-02-29 01:15:08 +01:00
|
|
|
#include "V3SplitVar.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Stats.h"
|
2015-09-20 00:49:54 +02:00
|
|
|
#include "V3String.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Subst.h"
|
2020-05-09 21:00:46 +02:00
|
|
|
#include "V3TSP.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Table.h"
|
|
|
|
|
#include "V3Task.h"
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
#include "V3Timing.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Trace.h"
|
|
|
|
|
#include "V3TraceDecl.h"
|
2009-01-06 17:03:57 +01:00
|
|
|
#include "V3Tristate.h"
|
2010-12-29 14:06:05 +01:00
|
|
|
#include "V3Undriven.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Unknown.h"
|
|
|
|
|
#include "V3Unroll.h"
|
Add V3VariableOrder pass
A separate V3VariableOrder pass is now used to order module variables
before Emit. All variables are now ordered together, without
consideration for whether they are ports, signals form the design, or
additional internal variables added by Verilator (which used to be
ordered and emitted as separate groups in Emit). For single threaded
models, this is performance neutral. For multi-threaded models, the
MTask affinity based sorting was slightly modified, so variables with no
MTask affinity are emitted last, otherwise the MTask affinity sets are
sorted using the TSP sorter as before, but again, ports, signals, and
internal variables are not differentiated. This yields a 2%+ speedup for
the multithreaded model on OpenTitan.
2021-06-29 18:57:07 +02:00
|
|
|
#include "V3VariableOrder.h"
|
2020-05-26 20:38:14 +02:00
|
|
|
#include "V3Waiver.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Width.h"
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <ctime>
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
V3Global v3Global;
|
|
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
static void reportStatsIfEnabled() {
|
|
|
|
|
if (v3Global.opt.stats()) {
|
|
|
|
|
V3Stats::statsFinalAll(v3Global.rootp());
|
|
|
|
|
V3Stats::statsReport();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-19 13:23:26 +01:00
|
|
|
static void process() {
|
2009-10-31 15:08:38 +01:00
|
|
|
// Sort modules by level so later algorithms don't need to care
|
2006-08-26 13:35:28 +02:00
|
|
|
V3LinkLevel::modSortByLevel();
|
|
|
|
|
V3Error::abortIfErrors();
|
2020-06-09 04:10:55 +02:00
|
|
|
if (v3Global.opt.debugExitParse()) {
|
|
|
|
|
cout << "--debug-exit-parse: Exiting after parse\n";
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(0);
|
2020-06-09 04:10:55 +02:00
|
|
|
}
|
2020-08-25 01:33:26 +02:00
|
|
|
|
|
|
|
|
// Convert parseref's to varrefs, and other directly post parsing fixups
|
|
|
|
|
V3LinkParse::linkParse(v3Global.rootp());
|
2020-08-23 15:05:18 +02:00
|
|
|
if (v3Global.opt.debugExitUvm()) {
|
2020-08-25 01:33:26 +02:00
|
|
|
V3Error::abortIfErrors();
|
2020-08-23 15:05:18 +02:00
|
|
|
cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n";
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(0);
|
2020-08-23 15:05:18 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Cross-link signal names
|
|
|
|
|
// Cross-link dotted hierarchical references
|
2012-07-21 15:27:57 +02:00
|
|
|
V3LinkDot::linkDotPrimary(v3Global.rootp());
|
|
|
|
|
v3Global.checkTree(); // Force a check, as link is most likely place for problems
|
2016-03-25 00:14:15 +01:00
|
|
|
// Check if all parameters have been found
|
|
|
|
|
v3Global.opt.checkParameters();
|
2006-12-21 15:35:19 +01:00
|
|
|
// Correct state we couldn't know at parse time, repair SEL's
|
2006-08-26 13:35:28 +02:00
|
|
|
V3LinkResolve::linkResolve(v3Global.rootp());
|
2006-12-21 15:35:19 +01:00
|
|
|
// Set Lvalue's in variable refs
|
|
|
|
|
V3LinkLValue::linkLValue(v3Global.rootp());
|
2010-02-14 16:01:21 +01:00
|
|
|
// Convert return/continue/disable to jumps
|
|
|
|
|
V3LinkJump::linkJump(v3Global.rootp());
|
2020-05-29 00:08:15 +02:00
|
|
|
// Convert --/++ to normal operations. Must be after LinkJump.
|
|
|
|
|
V3LinkInc::linkIncrements(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link");
|
|
|
|
|
|
|
|
|
|
// Remove parameters by cloning modules to de-parameterized versions
|
|
|
|
|
// This requires some width calculations and constant propagation
|
|
|
|
|
V3Param::param(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules
|
2006-08-26 13:35:28 +02:00
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
|
|
|
|
// Remove any modules that were parameterized and are no longer referenced.
|
2012-04-29 14:24:32 +02:00
|
|
|
V3Dead::deadifyModules(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
v3Global.checkTree();
|
|
|
|
|
|
2022-12-23 17:32:38 +01:00
|
|
|
// Create a hierarchical Verilation plan
|
2020-08-15 15:43:53 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.hierarchical()) {
|
|
|
|
|
V3HierBlockPlan::createPlan(v3Global.rootp());
|
|
|
|
|
// If a plan is created, further analysis is not necessary.
|
|
|
|
|
// The actual Verilation will be done based on this plan.
|
|
|
|
|
if (v3Global.hierPlanp()) {
|
|
|
|
|
reportStatsIfEnabled();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
|
|
|
|
|
V3Width::width(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
|
|
|
|
// Commit to the widths we've chosen; Make widthMin==width
|
|
|
|
|
V3Width::widthCommit(v3Global.rootp());
|
2011-11-30 04:36:51 +01:00
|
|
|
v3Global.assertDTypesResolved(true);
|
2015-05-15 03:46:07 +02:00
|
|
|
v3Global.widthMinUsage(VWidthMinUsage::MATCHES_WIDTH);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Coverage insertion
|
2010-09-25 13:46:09 +02:00
|
|
|
// Before we do dead code elimination and inlining, or we'll lose it.
|
2020-04-15 01:55:00 +02:00
|
|
|
if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-12-07 23:55:22 +01:00
|
|
|
// Add randomize() class methods if they are used by the design
|
|
|
|
|
if (v3Global.useRandomizeMethods()) V3Randomize::randomizeNetlist(v3Global.rootp());
|
|
|
|
|
|
2010-12-29 14:06:05 +01:00
|
|
|
// Push constants, but only true constants preserving liveness
|
|
|
|
|
// so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..."
|
2022-10-04 22:18:39 +02:00
|
|
|
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLive(v3Global.rootp());
|
2010-12-29 14:06:05 +01:00
|
|
|
|
|
|
|
|
// Signal based lint checks, no change to structures
|
|
|
|
|
// Must be before first constification pass drops dead code
|
|
|
|
|
V3Undriven::undrivenAll(v3Global.rootp());
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Assertion insertion
|
|
|
|
|
// After we've added block coverage, but before other nasty transforms
|
2007-03-06 22:43:38 +01:00
|
|
|
V3AssertPre::assertPreAll(v3Global.rootp());
|
|
|
|
|
//
|
|
|
|
|
V3Assert::assertAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Add top level wrapper with instance pointing to old top
|
|
|
|
|
// Move packages to under new top
|
|
|
|
|
// Must do this after we know parameters and dtypes (as don't clone dtype decls)
|
|
|
|
|
V3LinkLevel::wrapTop(v3Global.rootp());
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Propagate constants into expressions
|
2022-10-04 22:18:39 +02:00
|
|
|
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLint(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) {
|
2020-02-29 01:15:08 +01:00
|
|
|
// Split packed variables into multiple pieces to resolve UNOPTFLAT.
|
|
|
|
|
// should be after constifyAllLint() which flattens to 1D bit vector
|
|
|
|
|
V3SplitVar::splitVariable(v3Global.rootp());
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Remove cell arrays (must be between V3Width and scoping)
|
|
|
|
|
V3Inst::dearrayAll(v3Global.rootp());
|
|
|
|
|
V3LinkDot::linkDotArrayed(v3Global.rootp());
|
2012-03-20 21:13:10 +01:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Task inlining & pushing BEGINs names to variables/cells
|
|
|
|
|
// Begin processing must be after Param, before module inlining
|
|
|
|
|
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
2012-03-20 21:13:10 +01:00
|
|
|
|
2018-09-14 12:56:59 +02:00
|
|
|
// Expand inouts, stage 2
|
|
|
|
|
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
|
|
|
|
|
V3Tristate::tristateAll(v3Global.rootp());
|
2020-08-03 17:44:47 +02:00
|
|
|
}
|
2018-09-14 12:56:59 +02:00
|
|
|
|
2020-08-03 17:44:47 +02:00
|
|
|
if (!v3Global.opt.xmlOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Move assignments from X into MODULE temps.
|
|
|
|
|
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
|
|
|
|
V3Unknown::unknownAll(v3Global.rootp());
|
|
|
|
|
v3Global.constRemoveXs(true);
|
2020-08-03 17:44:47 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
|
Introduce DFG based combinational logic optimizer (#3527)
Added a new data-flow graph (DFG) based combinational logic optimizer.
The capabilities of this covers a combination of V3Const and V3Gate, but
is also more capable of transforming combinational logic into simplified
forms and more.
This entail adding a new internal representation, `DfgGraph`, and
appropriate `astToDfg` and `dfgToAst` conversion functions. The graph
represents some of the combinational equations (~continuous assignments)
in a module, and for the duration of the DFG passes, it takes over the
role of AstModule. A bulk of the Dfg vertices represent expressions.
These vertex classes, and the corresponding conversions to/from AST are
mostly auto-generated by astgen, together with a DfgVVisitor that can be
used for dynamic dispatch based on vertex (operation) types.
The resulting combinational logic graph (a `DfgGraph`) is then optimized
in various ways. Currently we perform common sub-expression elimination,
variable inlining, and some specific peephole optimizations, but there
is scope for more optimizations in the future using the same
representation. The optimizer is run directly before and after inlining.
The pre inline pass can operate on smaller graphs and hence converges
faster, but still has a chance of substantially reducing the size of the
logic on some designs, making inlining both faster and less memory
intensive. The post inline pass can then optimize across the inlined
module boundaries. No optimization is performed across a module
boundary.
For debugging purposes, each peephole optimization can be disabled
individually via the -fno-dfg-peepnole-<OPT> option, where <OPT> is one
of the optimizations listed in V3DfgPeephole.h, for example
-fno-dfg-peephole-remove-not-not.
The peephole patterns currently implemented were mostly picked based on
the design that inspired this work, and on that design the optimizations
yields ~30% single threaded speedup, and ~50% speedup on 4 threads. As
you can imagine not having to haul around redundant combinational
networks in the rest of the compilation pipeline also helps with memory
consumption, and up to 30% peak memory usage of Verilator was observed
on the same design.
Gains on other arbitrary designs are smaller (and can be improved by
analyzing those designs). For example OpenTitan gains between 1-15%
speedup depending on build type.
2022-09-23 17:46:22 +02:00
|
|
|
if (v3Global.opt.fDfgPreInline() || v3Global.opt.fDfgPostInline()) {
|
|
|
|
|
// If doing DFG optimization, extract some additional candidates
|
|
|
|
|
V3DfgOptimizer::extract(v3Global.rootp());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.fDfgPreInline()) {
|
|
|
|
|
// Pre inline DFG optimization
|
|
|
|
|
V3DfgOptimizer::optimize(v3Global.rootp(), " pre inline");
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:44:47 +02:00
|
|
|
if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Module inlining
|
|
|
|
|
// Cannot remove dead variables after this, as alias information for final
|
|
|
|
|
// V3Scope's V3LinkDot is in the AstVar.
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fInline()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Inline::inlineAll(v3Global.rootp());
|
|
|
|
|
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
Introduce DFG based combinational logic optimizer (#3527)
Added a new data-flow graph (DFG) based combinational logic optimizer.
The capabilities of this covers a combination of V3Const and V3Gate, but
is also more capable of transforming combinational logic into simplified
forms and more.
This entail adding a new internal representation, `DfgGraph`, and
appropriate `astToDfg` and `dfgToAst` conversion functions. The graph
represents some of the combinational equations (~continuous assignments)
in a module, and for the duration of the DFG passes, it takes over the
role of AstModule. A bulk of the Dfg vertices represent expressions.
These vertex classes, and the corresponding conversions to/from AST are
mostly auto-generated by astgen, together with a DfgVVisitor that can be
used for dynamic dispatch based on vertex (operation) types.
The resulting combinational logic graph (a `DfgGraph`) is then optimized
in various ways. Currently we perform common sub-expression elimination,
variable inlining, and some specific peephole optimizations, but there
is scope for more optimizations in the future using the same
representation. The optimizer is run directly before and after inlining.
The pre inline pass can operate on smaller graphs and hence converges
faster, but still has a chance of substantially reducing the size of the
logic on some designs, making inlining both faster and less memory
intensive. The post inline pass can then optimize across the inlined
module boundaries. No optimization is performed across a module
boundary.
For debugging purposes, each peephole optimization can be disabled
individually via the -fno-dfg-peepnole-<OPT> option, where <OPT> is one
of the optimizations listed in V3DfgPeephole.h, for example
-fno-dfg-peephole-remove-not-not.
The peephole patterns currently implemented were mostly picked based on
the design that inspired this work, and on that design the optimizations
yields ~30% single threaded speedup, and ~50% speedup on 4 threads. As
you can imagine not having to haul around redundant combinational
networks in the rest of the compilation pipeline also helps with memory
consumption, and up to 30% peak memory usage of Verilator was observed
on the same design.
Gains on other arbitrary designs are smaller (and can be improved by
analyzing those designs). For example OpenTitan gains between 1-15%
speedup depending on build type.
2022-09-23 17:46:22 +02:00
|
|
|
if (v3Global.opt.fDfgPostInline()) {
|
|
|
|
|
// Post inline DFG optimization
|
|
|
|
|
V3DfgOptimizer::optimize(v3Global.rootp(), "post inline");
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-08 18:01:39 +01:00
|
|
|
// --PRE-FLAT OPTIMIZATIONS------------------
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Initial const/dead to reduce work for ordering code
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
v3Global.checkTree();
|
2012-03-20 21:13:10 +01:00
|
|
|
|
2012-04-29 14:24:32 +02:00
|
|
|
V3Dead::deadifyDTypes(v3Global.rootp());
|
2012-03-20 21:13:10 +01:00
|
|
|
v3Global.checkTree();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
2022-01-08 18:01:39 +01:00
|
|
|
// --FLATTENING---------------
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// We're going to flatten the hierarchy, so as many optimizations that
|
|
|
|
|
// can be done as possible should be before this....
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Convert instantiations to wassigns and always blocks
|
|
|
|
|
V3Inst::instAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Inst may have made lots of concats; fix them
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
|
|
|
|
V3Scope::scopeAll(v3Global.rootp());
|
|
|
|
|
V3LinkDot::linkDotScope(v3Global.rootp());
|
2020-04-05 15:30:23 +02:00
|
|
|
|
|
|
|
|
// Relocate classes (after linkDot)
|
|
|
|
|
V3Class::classAll(v3Global.rootp());
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2008-06-10 03:25:10 +02:00
|
|
|
|
2022-01-08 18:01:39 +01:00
|
|
|
// --SCOPE BASED OPTIMIZATIONS--------------
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Cleanup
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
|
|
|
|
v3Global.checkTree();
|
2020-04-22 00:14:08 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!v3Global.opt.xmlOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Convert case statements to if() blocks. Must be after V3Unknown
|
|
|
|
|
// Must be before V3Task so don't need to deal with task in case value compares
|
|
|
|
|
V3Case::caseAll(v3Global.rootp());
|
2020-04-22 00:14:08 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Inline all tasks
|
|
|
|
|
V3Task::taskAll(v3Global.rootp());
|
2020-04-22 00:14:08 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2020-04-22 00:14:08 +02:00
|
|
|
if (!v3Global.opt.xmlOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Add __PVT's
|
|
|
|
|
// After V3Task so task internal variables will get renamed
|
|
|
|
|
V3Name::nameAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Loop unrolling & convert FORs to WHILEs
|
|
|
|
|
V3Unroll::unrollAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Expand slices of arrays
|
|
|
|
|
V3Slice::sliceAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Push constants across variables and remove redundant assignments
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// Make large low-fanin logic blocks into lookup tables
|
|
|
|
|
// This should probably be done much later, once we have common logic elimination.
|
2022-06-04 02:43:16 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && v3Global.opt.fTable()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Table::tableAll(v3Global.rootp());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
|
|
|
|
v3Global.checkTree();
|
|
|
|
|
|
|
|
|
|
// Move assignments/sensitives into a SBLOCK for each unique sensitivity list
|
|
|
|
|
// (May convert some ALWAYS to combo blocks, so should be before V3Gate step.)
|
|
|
|
|
V3Active::activeAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Split single ALWAYS blocks into multiple blocks for better ordering chances
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fSplit()) V3Split::splitAlwaysAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
V3SplitAs::splitAsAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Create tracing sample points, before we start eliminating signals
|
2020-04-15 01:55:00 +02:00
|
|
|
if (v3Global.opt.trace()) V3TraceDecl::traceDeclAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2021-12-17 18:56:33 +01:00
|
|
|
// Convert forceable signals, process force/release statements.
|
|
|
|
|
// After V3TraceDecl so we don't trace additional signals inserted to implement forcing.
|
|
|
|
|
V3Force::forceAll(v3Global.rootp());
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Gate-based logic elimination; eliminate signals and push constant across cell boundaries
|
|
|
|
|
// Instant propagation makes lots-o-constant reduction possibilities.
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fGate()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Gate::gateAll(v3Global.rootp());
|
|
|
|
|
// V3Gate calls constant propagation itself.
|
|
|
|
|
} else {
|
2022-06-04 02:43:16 +02:00
|
|
|
v3info("Command Line disabled gate optimization with -fno-gate. "
|
2020-04-15 01:55:00 +02:00
|
|
|
"This may cause ordering problems.");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Combine COVERINCs with duplicate terms
|
2020-04-15 01:55:00 +02:00
|
|
|
if (v3Global.opt.coverage()) V3CoverageJoin::coverageJoin(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// Remove unused vars
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
V3Dead::deadifyAllScoped(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Clock domain crossing analysis
|
|
|
|
|
if (v3Global.opt.cdc()) {
|
|
|
|
|
V3Cdc::cdcAll(v3Global.rootp());
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reorder assignments in pipelined blocks
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fReorder()) V3Split::splitReorderAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
if (v3Global.opt.timing().isSetTrue()) {
|
|
|
|
|
// Convert AST for timing if requested
|
|
|
|
|
// Needs to be after V3Gate, as that step modifies sentrees
|
|
|
|
|
// Needs to be before V3Delayed, as delayed assignments are handled differently in
|
|
|
|
|
// suspendable processes
|
|
|
|
|
V3Timing::timingAll(v3Global.rootp());
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Create delayed assignments
|
|
|
|
|
// This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step
|
|
|
|
|
V3Delayed::delayedAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Make Active's on the top level.
|
|
|
|
|
// Differs from V3Active, because identical clocks may be pushed
|
|
|
|
|
// down to a module and now be identical
|
|
|
|
|
V3ActiveTop::activeTopAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
|
|
|
|
|
|
2022-05-15 17:03:32 +02:00
|
|
|
// Schedule the logic
|
|
|
|
|
V3Sched::schedule(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// Convert sense lists into IF statements.
|
|
|
|
|
V3Clock::clockAll(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Cleanup any dly vars or other temps that are simple assignments
|
|
|
|
|
// Life must be done before Subst, as it assumes each CFunc under
|
|
|
|
|
// _eval is called only once.
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fLife()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
V3Life::lifeAll(v3Global.rootp());
|
|
|
|
|
}
|
2022-05-15 17:03:32 +02:00
|
|
|
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fLifePost()) V3LifePost::lifepostAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
// Remove unused vars
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
V3Dead::deadifyAllScoped(v3Global.rootp());
|
|
|
|
|
|
|
|
|
|
// Create tracing logic, since we ripped out some signals the user might want to trace
|
|
|
|
|
// Note past this point, we presume traced variables won't move between CFuncs
|
|
|
|
|
// (It's OK if untraced temporaries move around, or vars
|
|
|
|
|
// "effectively" activate the same way.)
|
2020-04-15 01:55:00 +02:00
|
|
|
if (v3Global.opt.trace()) V3Trace::traceAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
|
|
|
|
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped");
|
2007-04-19 20:20:16 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-08 18:01:39 +01:00
|
|
|
// --MODULE OPTIMIZATIONS--------------
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
if (!v3Global.opt.xmlOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Split deep blocks to appease MSVC++. Must be before Localize.
|
|
|
|
|
if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
|
|
|
|
|
V3DepthBlock::depthBlockAll(v3Global.rootp());
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 18:44:06 +02:00
|
|
|
// Up until this point, all references must be scoped
|
|
|
|
|
v3Global.assertScoped(false);
|
|
|
|
|
|
|
|
|
|
// Move variables from modules to function local variables where possible
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fLocalize()) V3Localize::localizeAll(v3Global.rootp());
|
2019-05-19 22:13:13 +02:00
|
|
|
|
2021-06-16 18:44:06 +02:00
|
|
|
// Remove remaining scopes; make varrefs/funccalls relative to current module
|
|
|
|
|
V3Descope::descopeAll(v3Global.rootp());
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Icache packing; combine common code in each module's functions into subroutines
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fCombine()) V3Combine::combineAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
2022-01-08 18:01:39 +01:00
|
|
|
// --GENERATION------------------
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2012-03-20 21:13:10 +01:00
|
|
|
if (!v3Global.opt.xmlOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Remove unused vars
|
|
|
|
|
V3Const::constifyAll(v3Global.rootp());
|
|
|
|
|
V3Dead::deadifyAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Here down, widthMin() is the Verilog width, and width() is the C++ width
|
|
|
|
|
// Bits between widthMin() and width() are irrelevant, but may be non zero.
|
|
|
|
|
v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-10-12 11:19:21 +02:00
|
|
|
// Make all expressions either 8, 16, 32 or 64 bits
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Clean::cleanAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
// Move wide constants to BLOCK temps / ConstPool.
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Premit::premitAll(v3Global.rootp());
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Expand macros and wide operators into C++ primitives
|
2022-06-04 02:43:16 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.fExpand()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Expand::expandAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Propagate constants across WORDSEL arrayed temporaries
|
2022-06-04 02:43:16 +02:00
|
|
|
if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubst()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Constant folding of expanded stuff
|
|
|
|
|
V3Const::constifyCpp(v3Global.rootp());
|
|
|
|
|
V3Subst::substituteAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-01-25 02:19:52 +01:00
|
|
|
|
2022-06-04 02:43:16 +02:00
|
|
|
if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubstConst()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Constant folding of substitutions
|
|
|
|
|
V3Const::constifyCpp(v3Global.rootp());
|
|
|
|
|
V3Dead::deadifyAll(v3Global.rootp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) {
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fMergeCond()) {
|
2020-05-30 22:09:05 +02:00
|
|
|
// Merge conditionals
|
|
|
|
|
V3MergeCond::mergeAll(v3Global.rootp());
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-04 02:43:16 +02:00
|
|
|
if (v3Global.opt.fReloop()) {
|
2020-05-30 22:09:05 +02:00
|
|
|
// Reform loops to reduce code size
|
|
|
|
|
// Must be after all Sel/array index based optimizations
|
|
|
|
|
V3Reloop::reloopAll(v3Global.rootp());
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Fix very deep expressions
|
|
|
|
|
// Mark evaluation functions as member functions, if needed.
|
|
|
|
|
V3Depth::depthAll(v3Global.rootp());
|
2007-04-18 20:45:41 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Branch prediction
|
|
|
|
|
V3Branch::branchAll(v3Global.rootp());
|
2007-04-18 20:45:41 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
// Add C casts when longs need to become long-long and vice-versa
|
|
|
|
|
// Note depth may insert something needing a cast, so this must be last.
|
|
|
|
|
V3Cast::castAll(v3Global.rootp());
|
2007-04-18 20:45:41 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
V3Error::abortIfErrors();
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { //
|
2019-05-19 22:13:13 +02:00
|
|
|
V3CCtors::cctorsAll();
|
2016-05-12 13:19:02 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-06-16 13:18:56 +02:00
|
|
|
if (!v3Global.opt.xmlOnly() && v3Global.opt.mtasks()) {
|
|
|
|
|
// Finalize our MTask cost estimates and pack the mtasks into
|
|
|
|
|
// threads. Must happen pre-EmitC which relies on the packing
|
|
|
|
|
// order. Must happen post-V3LifePost which changes the relative
|
|
|
|
|
// costs of mtasks.
|
2022-04-10 12:37:41 +02:00
|
|
|
V3Partition::finalize(v3Global.rootp());
|
2021-06-16 13:18:56 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) {
|
2021-07-20 17:40:38 +02:00
|
|
|
// Add common methods/etc to modules
|
|
|
|
|
V3Common::commonAll();
|
2020-02-02 01:11:19 +01:00
|
|
|
|
Add V3VariableOrder pass
A separate V3VariableOrder pass is now used to order module variables
before Emit. All variables are now ordered together, without
consideration for whether they are ports, signals form the design, or
additional internal variables added by Verilator (which used to be
ordered and emitted as separate groups in Emit). For single threaded
models, this is performance neutral. For multi-threaded models, the
MTask affinity based sorting was slightly modified, so variables with no
MTask affinity are emitted last, otherwise the MTask affinity sets are
sorted using the TSP sorter as before, but again, ports, signals, and
internal variables are not differentiated. This yields a 2%+ speedup for
the multithreaded model on OpenTitan.
2021-06-29 18:57:07 +02:00
|
|
|
// Order variables
|
|
|
|
|
V3VariableOrder::orderAll();
|
|
|
|
|
|
2021-07-20 17:40:38 +02:00
|
|
|
// Create AstCUse to determine what class forward declarations/#includes needed in C
|
|
|
|
|
V3CUse::cUseAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Output the text
|
|
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// emitcInlines is first, as it may set needHInlines which other emitters read
|
|
|
|
|
V3EmitC::emitcInlines();
|
|
|
|
|
V3EmitC::emitcSyms();
|
2021-06-13 16:05:55 +02:00
|
|
|
V3EmitC::emitcConstPool();
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
V3EmitC::emitcModel();
|
2021-07-07 20:16:40 +02:00
|
|
|
V3EmitC::emitcHeaders();
|
2019-08-28 03:36:59 +02:00
|
|
|
} else if (v3Global.opt.dpiHdrOnly()) {
|
|
|
|
|
V3EmitC::emitcSyms(true);
|
2007-04-18 20:26:38 +02:00
|
|
|
}
|
2019-08-28 03:36:59 +02:00
|
|
|
if (!v3Global.opt.xmlOnly()
|
2021-07-07 20:16:40 +02:00
|
|
|
&& !v3Global.opt.dpiHdrOnly()) { // Unfortunately we have some lint checks in emitcImp.
|
|
|
|
|
V3EmitC::emitcImp();
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
|
|
|
|
if (v3Global.opt.xmlOnly()
|
2019-05-19 22:13:13 +02:00
|
|
|
// Check XML when debugging to make sure no missing node types
|
2020-04-15 01:55:00 +02:00
|
|
|
|| (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly() && !v3Global.opt.dpiHdrOnly())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3EmitXml::emitxml();
|
2012-03-20 21:13:10 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-10-09 12:47:26 +02:00
|
|
|
// Output DPI protected library files
|
2021-11-14 15:39:31 +01:00
|
|
|
if (!v3Global.opt.libCreate().empty()) {
|
2022-10-20 02:52:29 +02:00
|
|
|
if (v3Global.rootp()->delaySchedulerp()) {
|
|
|
|
|
v3warn(E_UNSUPPORTED, "Unsupported: --lib-create with --timing and delays");
|
|
|
|
|
}
|
2019-10-09 12:47:26 +02:00
|
|
|
V3ProtectLib::protect();
|
|
|
|
|
V3EmitV::emitvFiles();
|
|
|
|
|
V3EmitC::emitcFiles();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 15:00:06 +01:00
|
|
|
if (v3Global.opt.stats()) V3Stats::statsStage("emit");
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Statistics
|
2020-08-15 15:43:53 +02:00
|
|
|
reportStatsIfEnabled();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Makefile must be after all other emitters
|
2020-04-22 02:45:23 +02:00
|
|
|
if (v3Global.opt.main()) V3EmitCMain::emit();
|
|
|
|
|
if (v3Global.opt.cmake()) V3EmitCMake::emit();
|
|
|
|
|
if (v3Global.opt.gmake()) V3EmitMk::emitmk();
|
2007-04-18 20:26:38 +02:00
|
|
|
}
|
2010-01-17 02:14:52 +01:00
|
|
|
|
|
|
|
|
// Note early return above when opt.cdc()
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-15 23:44:21 +02:00
|
|
|
static void verilate(const string& argString) {
|
|
|
|
|
UINFO(1, "Option --verilate: Start Verilation\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Can we skip doing everything if times are ok?
|
2022-09-18 16:32:43 +02:00
|
|
|
V3File::addSrcDepend(v3Global.opt.buildDepBin());
|
2019-11-01 01:59:52 +01:00
|
|
|
if (v3Global.opt.skipIdentical().isTrue()
|
2020-08-15 15:43:53 +02:00
|
|
|
&& V3File::checkTimes(v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
|
|
|
|
|
+ "__verFiles.dat",
|
|
|
|
|
argString)) {
|
2020-04-15 01:55:00 +02:00
|
|
|
UINFO(1, "--skip-identical: No change to any source files, exiting\n");
|
2020-04-15 23:44:21 +02:00
|
|
|
return;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-12 02:22:57 +02:00
|
|
|
// Undocumented debugging - cannot be a switch as then command line
|
|
|
|
|
// would mismatch forcing non-identicalness when we set it
|
2020-10-14 03:13:52 +02:00
|
|
|
if (!V3Os::getenvStr("VERILATOR_DEBUG_SKIP_IDENTICAL", "").empty()) { // LCOV_EXCL_START
|
2020-04-12 02:22:57 +02:00
|
|
|
v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n");
|
2020-10-14 03:13:52 +02:00
|
|
|
} // LCOV_EXCL_STOP
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-01-08 18:01:39 +01:00
|
|
|
// --FRONTEND------------------
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Cleanup
|
2020-08-15 15:43:53 +02:00
|
|
|
V3Os::unlinkRegexp(v3Global.opt.hierTopDataDir(), v3Global.opt.prefix() + "_*.tree");
|
|
|
|
|
V3Os::unlinkRegexp(v3Global.opt.hierTopDataDir(), v3Global.opt.prefix() + "_*.dot");
|
|
|
|
|
V3Os::unlinkRegexp(v3Global.opt.hierTopDataDir(), v3Global.opt.prefix() + "_*.txt");
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-06-18 03:06:11 +02:00
|
|
|
// Internal tests (after option parsing as need debug() setting,
|
|
|
|
|
// and after removing files as may make debug output)
|
2022-01-02 19:56:40 +01:00
|
|
|
VBasicDTypeKwd::selfTest();
|
2018-07-23 02:54:28 +02:00
|
|
|
if (v3Global.opt.debugSelfTest()) {
|
2019-09-28 19:32:28 +02:00
|
|
|
VHashSha256::selfTest();
|
2019-07-14 02:30:32 +02:00
|
|
|
VSpellCheck::selfTest();
|
2019-06-30 23:36:58 +02:00
|
|
|
V3Graph::selfTest();
|
2018-07-23 02:54:28 +02:00
|
|
|
V3TSP::selfTest();
|
|
|
|
|
V3ScoreboardBase::selfTest();
|
|
|
|
|
V3Partition::selfTest();
|
2021-09-27 04:51:11 +02:00
|
|
|
V3Partition::selfTestNormalizeCosts();
|
2020-12-08 05:15:29 +01:00
|
|
|
V3Broken::selfTest();
|
2018-07-23 02:54:28 +02:00
|
|
|
}
|
2018-06-18 03:06:11 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Read first filename
|
|
|
|
|
v3Global.readFiles();
|
|
|
|
|
|
|
|
|
|
// Link, etc, if needed
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!v3Global.opt.preprocOnly()) { //
|
2019-05-19 22:13:13 +02:00
|
|
|
process();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Final steps
|
2022-09-18 21:53:42 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("final", 990, dumpTree() >= 3);
|
2020-05-26 20:38:14 +02:00
|
|
|
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.isWaiverOutput()) {
|
|
|
|
|
// Create waiver output, must be just before we exit on warnings
|
|
|
|
|
V3Waiver::write(v3Global.opt.waiverOutput());
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-12 21:39:10 +02:00
|
|
|
V3Error::abortIfWarnings();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
if (v3Global.hierPlanp()) { // This run is for just write a makefile
|
|
|
|
|
UASSERT(v3Global.opt.hierarchical(), "hierarchical must be set");
|
|
|
|
|
UASSERT(!v3Global.opt.hierChild(), "This must not be a hierarhcical-child run");
|
|
|
|
|
UASSERT(v3Global.opt.hierBlocks().empty(), "hierarchical-block must not be set");
|
|
|
|
|
if (v3Global.opt.gmake()) {
|
|
|
|
|
v3Global.hierPlanp()->writeCommandArgsFiles(false);
|
|
|
|
|
V3EmitMk::emitHierVerilation(v3Global.hierPlanp());
|
|
|
|
|
}
|
|
|
|
|
if (v3Global.opt.cmake()) {
|
|
|
|
|
v3Global.hierPlanp()->writeCommandArgsFiles(true);
|
|
|
|
|
V3EmitCMake::emit();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-01 01:59:52 +01:00
|
|
|
if (v3Global.opt.makeDepend().isTrue()) {
|
2020-08-15 15:43:53 +02:00
|
|
|
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix();
|
|
|
|
|
filename += v3Global.opt.hierTop() ? "__hierVer.d" : "__ver.d";
|
|
|
|
|
V3File::writeDepend(filename);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-06 19:24:21 +02:00
|
|
|
if (v3Global.opt.protectIds()) {
|
2020-08-15 15:43:53 +02:00
|
|
|
VIdProtect::writeMapFile(v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
|
2020-04-15 01:55:00 +02:00
|
|
|
+ "__idmap.xml");
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
2020-08-15 15:43:53 +02:00
|
|
|
|
2020-04-12 02:22:57 +02:00
|
|
|
if (v3Global.opt.skipIdentical().isTrue() || v3Global.opt.makeDepend().isTrue()) {
|
2020-08-15 15:43:53 +02:00
|
|
|
V3File::writeTimes(v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
|
|
|
|
|
+ "__verFiles.dat",
|
2020-04-12 02:22:57 +02:00
|
|
|
argString);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2011-03-22 23:09:39 +01:00
|
|
|
// Final writing shouldn't throw warnings, but...
|
|
|
|
|
V3Error::abortIfWarnings();
|
2020-04-15 23:44:21 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-02 13:30:40 +02:00
|
|
|
static string buildMakeCmd(const string& makefile, const string& target) {
|
2020-04-15 23:44:21 +02:00
|
|
|
const V3StringList& makeFlags = v3Global.opt.makeFlags();
|
|
|
|
|
const int jobs = v3Global.opt.buildJobs();
|
|
|
|
|
UASSERT(jobs >= 0, "-j option parser in V3Options.cpp filters out negative value");
|
2020-04-30 13:54:50 +02:00
|
|
|
|
2020-07-02 13:30:40 +02:00
|
|
|
std::ostringstream cmd;
|
2020-04-30 13:54:50 +02:00
|
|
|
cmd << v3Global.opt.getenvMAKE();
|
|
|
|
|
cmd << " -C " << v3Global.opt.makeDir();
|
2020-07-02 13:30:40 +02:00
|
|
|
cmd << " -f " << makefile;
|
2022-12-11 20:19:40 +01:00
|
|
|
// Unless using make's jobserver, do a -j
|
|
|
|
|
if (v3Global.opt.getenvMAKEFLAGS().find("-jobserver-auth") == string::npos) {
|
|
|
|
|
if (jobs > 0) cmd << " -j " << jobs;
|
|
|
|
|
}
|
2020-08-16 18:54:32 +02:00
|
|
|
for (const string& flag : makeFlags) cmd << ' ' << flag;
|
|
|
|
|
if (!target.empty()) cmd << ' ' << target;
|
2020-07-02 13:30:40 +02:00
|
|
|
|
|
|
|
|
return cmd.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void execBuildJob() {
|
|
|
|
|
UASSERT(v3Global.opt.build(), "--build is not specified.");
|
|
|
|
|
UASSERT(v3Global.opt.gmake(), "--build requires GNU Make.");
|
|
|
|
|
UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake.");
|
|
|
|
|
UINFO(1, "Start Build\n");
|
2020-04-15 23:44:21 +02:00
|
|
|
|
2020-07-02 13:30:40 +02:00
|
|
|
const string cmdStr = buildMakeCmd(v3Global.opt.prefix() + ".mk", "");
|
2020-04-15 23:44:21 +02:00
|
|
|
const int exit_code = V3Os::system(cmdStr);
|
|
|
|
|
if (exit_code != 0) {
|
2020-11-09 03:55:33 +01:00
|
|
|
v3error(cmdStr << " exited with " << exit_code << std::endl);
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(exit_code);
|
2020-04-15 23:44:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
static void execHierVerilation() {
|
|
|
|
|
UASSERT(v3Global.hierPlanp(), "must be called only when plan exists");
|
|
|
|
|
const string makefile = v3Global.opt.prefix() + "_hier.mk ";
|
|
|
|
|
const string target = v3Global.opt.build() ? " hier_build" : " hier_verilation";
|
|
|
|
|
const string cmdStr = buildMakeCmd(makefile, target);
|
|
|
|
|
const int exit_code = V3Os::system(cmdStr);
|
|
|
|
|
if (exit_code != 0) {
|
2020-11-09 03:55:33 +01:00
|
|
|
v3error(cmdStr << " exited with " << exit_code << std::endl);
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(exit_code);
|
2020-08-15 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 23:44:21 +02:00
|
|
|
//######################################################################
|
|
|
|
|
|
2022-11-24 00:50:31 +01:00
|
|
|
int main(int argc, char** argv) {
|
2020-04-15 23:44:21 +02:00
|
|
|
// General initialization
|
|
|
|
|
std::ios::sync_with_stdio();
|
|
|
|
|
|
|
|
|
|
time_t randseed;
|
|
|
|
|
time(&randseed);
|
|
|
|
|
srand(static_cast<int>(randseed));
|
|
|
|
|
|
|
|
|
|
// Post-constructor initialization of netlists
|
|
|
|
|
v3Global.boot();
|
|
|
|
|
|
|
|
|
|
// Preprocessor
|
|
|
|
|
// Before command parsing so we can handle -Ds on command line.
|
2022-07-13 19:24:48 +02:00
|
|
|
V3PreShell::boot();
|
2020-04-15 23:44:21 +02:00
|
|
|
|
|
|
|
|
// Command option parsing
|
2022-11-20 16:25:41 +01:00
|
|
|
v3Global.opt.buildDepBin(VString::escapeStringForPath(argv[0]));
|
2021-06-21 00:32:57 +02:00
|
|
|
const string argString = V3Options::argString(argc - 1, argv + 1);
|
2022-09-15 14:54:04 +02:00
|
|
|
v3Global.opt.parseOpts(new FileLine{FileLine::commandLineFilename()}, argc - 1, argv + 1);
|
2020-04-15 23:44:21 +02:00
|
|
|
|
|
|
|
|
// Validate settings (aka Boost.Program_options)
|
|
|
|
|
v3Global.opt.notify();
|
2020-04-16 01:39:03 +02:00
|
|
|
v3Global.rootp()->timeInit();
|
2020-04-15 23:44:21 +02:00
|
|
|
|
|
|
|
|
V3Error::abortIfErrors();
|
|
|
|
|
|
|
|
|
|
if (v3Global.opt.verilate()) {
|
|
|
|
|
verilate(argString);
|
|
|
|
|
} else {
|
|
|
|
|
UINFO(1, "Option --no-verilate: Skip Verilation\n");
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
if (v3Global.hierPlanp() && v3Global.opt.gmake()) {
|
|
|
|
|
execHierVerilation(); // execHierVerilation() takes care of --build too
|
|
|
|
|
} else if (v3Global.opt.build()) {
|
|
|
|
|
execBuildJob();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Explicitly release resources
|
2023-01-01 15:22:13 +01:00
|
|
|
V3PreShell::shutdown();
|
2020-08-15 15:43:53 +02:00
|
|
|
v3Global.shutdown();
|
2023-01-01 15:22:13 +01:00
|
|
|
FileLine::deleteAllRemaining();
|
2008-06-10 03:25:10 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
UINFO(1, "Done, Exiting...\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|