Optimize input combinational logic by change detection
When a lot of combinational logic is driven from top level inputs, work can be wasted evaluating that logic if the top level inputs don't change. This change adds an optimization by performing a change detect on the top level inputs, and evaluate 'ico' logic only if the top level input actually changed. This especially helps with --hierarchical/--lib-create which runs the 'ico' of each sub-model in the eval settle loop. This was observed to yield 40%+ run-time speedup on some partitioned designs. The added change detection is cheap, so it is emitted even if the 'ico' region is small, and is on by default. The optimization is only sound if the model itself does not write to the top level inputs (otherwise the 'previous value' variables would be out of sync, which are not updated by internal writes.). If we can detect a top level input is written within the design, then for that input, we fall back on always running the relevant logic. With --vpi we cannot prove safety statically, so --vpi will disable this optimisation unless explicitly enabled. (In which case it's the user's responsibility to not write to top level inputs via the VPI.)
This commit is contained in:
parent
77e6a21224
commit
13111d0a28
|
|
@ -737,6 +737,21 @@ Summary:
|
|||
this is not recommended as may cause additional warnings and ordering
|
||||
issues.
|
||||
|
||||
.. option:: -fno-ico-change-detect
|
||||
|
||||
Rarely needed. Disable input change detection in the input combinational
|
||||
('ico') region. With change detection enabled (the default, unless
|
||||
:vlopt:`--vpi` is passed), the input combinational logic is evaluated only
|
||||
when a top level input has actually changed, rather than unconditionally on
|
||||
the first scheduling iteration.
|
||||
|
||||
The change detection logic assumes a top level input only ever changes
|
||||
externally between evaluations. The optimization is automatically disabled
|
||||
for top level input signals that are written within the design. Accesses via
|
||||
the VPI cannot be analyzed at compile time, therefore :vlopt:`--vpi`
|
||||
disables this optimization. It can be turned back on by explicitly passing
|
||||
:vlopt:`-fico-change-detect`.
|
||||
|
||||
.. option:: -fno-inline
|
||||
|
||||
.. option:: -fno-inline-funcs
|
||||
|
|
|
|||
|
|
@ -2151,6 +2151,7 @@ class AstVar final : public AstNode {
|
|||
bool m_isDpiOpenArray : 1; // DPI import open array
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
bool m_maybeWritten : 1; // Design might write to this signal (not very accurate)
|
||||
bool m_noCReset : 1; // Do not do automated CReset creation
|
||||
bool m_noReset : 1; // Do not do automated reset/randomization
|
||||
bool m_noSubst : 1; // Do not substitute out references
|
||||
|
|
@ -2213,6 +2214,7 @@ class AstVar final : public AstNode {
|
|||
m_isDpiOpenArray = false;
|
||||
m_isHideLocal = false;
|
||||
m_isHideProtected = false;
|
||||
m_maybeWritten = false;
|
||||
m_noCReset = false;
|
||||
m_noReset = false;
|
||||
m_noSubst = false;
|
||||
|
|
@ -2385,6 +2387,8 @@ public:
|
|||
void isHideLocal(bool flag) { m_isHideLocal = flag; }
|
||||
bool isHideProtected() const { return m_isHideProtected; }
|
||||
void isHideProtected(bool flag) { m_isHideProtected = flag; }
|
||||
void maybeWritten(bool flag) { m_maybeWritten = flag; }
|
||||
bool maybeWritten() const { return m_maybeWritten; }
|
||||
bool noCReset() const { return m_noCReset; }
|
||||
void noCReset(bool flag) { m_noCReset = flag; }
|
||||
bool noReset() const { return m_noReset; }
|
||||
|
|
|
|||
|
|
@ -291,6 +291,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|||
varp->sigPublic(true); // User needs to be able to get to it...
|
||||
oldvarp->primaryIO(false);
|
||||
varp->primaryIO(true);
|
||||
varp->maybeWritten(oldvarp->maybeWritten());
|
||||
if (varp->isRef() || varp->isConstRef()) {
|
||||
varp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: ref/const ref as primary input/output: "
|
||||
|
|
|
|||
|
|
@ -1077,6 +1077,9 @@ void V3Options::notify() VL_MT_DISABLED {
|
|||
// Preprocessor defines based on options used
|
||||
if (timing().isSetTrue()) V3PreShell::defineCmdLine("VERILATOR_TIMING", "1");
|
||||
|
||||
// If VPI is used, and no explicit ico change detect option was passed, disable it by default
|
||||
if (m_vpi && m_fIcoChangeDetect.isDefault()) m_fIcoChangeDetect.setTrueOrFalse(false);
|
||||
|
||||
// === Leave last
|
||||
// Mark options as available
|
||||
m_available = true;
|
||||
|
|
@ -1483,6 +1486,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-ffunc-opt-balance-cat", FOnOff, &m_fFuncBalanceCat);
|
||||
DECL_OPTION("-ffunc-opt-split-cat", FOnOff, &m_fFuncSplitCat);
|
||||
DECL_OPTION("-fgate", FOnOff, &m_fGate);
|
||||
DECL_OPTION("-fico-change-detect", CbFOnOff, [this](bool flag) { //
|
||||
m_fIcoChangeDetect.setTrueOrFalse(flag);
|
||||
});
|
||||
DECL_OPTION("-finline", FOnOff, &m_fInline);
|
||||
DECL_OPTION("-finline-funcs", FOnOff, &m_fInlineFuncs);
|
||||
DECL_OPTION("-finline-funcs-eager", FOnOff, &m_fInlineFuncsEager);
|
||||
|
|
|
|||
|
|
@ -410,6 +410,8 @@ private:
|
|||
bool m_fFuncBalanceCat = true; // main switch: -fno-func-balance-cat: expansion of C macros
|
||||
bool m_fFuncSplitCat = true; // main switch: -fno-func-split-cat: expansion of C macros
|
||||
bool m_fGate; // main switch: -fno-gate: gate wire elimination
|
||||
// main switch: -fno-ico-change-detect: input change detection optimization
|
||||
VOptionBool m_fIcoChangeDetect{VOptionBool::OPT_DEFAULT_TRUE};
|
||||
bool m_fInline; // main switch: -fno-inline: module inlining
|
||||
bool m_fInlineFuncs = true; // main switch: -fno-inline-funcs: function inlining
|
||||
bool m_fInlineFuncsEager = true; // main switch: -fno-inline-funcs-eager: don't inline eagerly
|
||||
|
|
@ -745,6 +747,7 @@ public:
|
|||
bool fFuncSplitCat() const { return m_fFuncSplitCat; }
|
||||
bool fFunc() const { return fFuncSplitCat() || fFuncBalanceCat(); }
|
||||
bool fGate() const { return m_fGate; }
|
||||
VOptionBool fIcoChangeDetect() const { return m_fIcoChangeDetect; }
|
||||
bool fInline() const { return m_fInline; }
|
||||
bool fInlineFuncs() const { return m_fInlineFuncs; }
|
||||
bool fInlineFuncsEager() const { return m_fInlineFuncsEager; }
|
||||
|
|
|
|||
|
|
@ -529,8 +529,46 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
+ entry.m_memberp->name());
|
||||
}
|
||||
|
||||
// Create the input change detect SenTrees.
|
||||
// If there is a lot of combinationallogic hanging of the top level inputs, we can save
|
||||
// a lot of work by only evaluating it if an input has actually changed. This in
|
||||
// paticular helps hierarchical models partitioned across combinaitonal boundaries.
|
||||
// The change detect itself should be fairly cheap otherwise so alway do it.
|
||||
// For correctness, don't create a change detect for top level inputs also written
|
||||
// by the design, as the change detect 'previous value' would get out of sync.
|
||||
// Also omit a SenTree for types that don't have the required '!=' operator.
|
||||
// Any signal that does not have an explicit change detect trigger will fall back to
|
||||
// using the 'first iteration' trigger, same as if this optimization was disabled.
|
||||
std::unordered_map<const AstVarScope*, AstSenTree*> inp2changedp;
|
||||
std::vector<AstSenTree*> icoChangeSenTreeps;
|
||||
if (v3Global.opt.fIcoChangeDetect().isTrue()) {
|
||||
FileLine* const flp = netlistp->fileline();
|
||||
AstScope* const scopep = netlistp->topScopep()->scopep();
|
||||
for (AstVarScope* vscp = scopep->varsp(); vscp; vscp = VN_AS(vscp->nextp(), VarScope)) {
|
||||
// Only for top level ports, assume outputs don't change externally
|
||||
if (!vscp->varp()->isPrimaryInish()) continue;
|
||||
// Don't do if written by the design - wouldn't update the change detect 'prev' value
|
||||
if (vscp->varp()->maybeWritten()) continue;
|
||||
// Don't do if forceable, as we can't see the actual value - this is belt and braces
|
||||
if (vscp->varp()->isForced()) continue;
|
||||
// Can't handle unpacked arrays (they have special types when primary input)
|
||||
if (VN_IS(vscp->dtypep()->skipRefp(), UnpackArrayDType)) continue;
|
||||
// Similarly to arrays, can't handle SystemC types
|
||||
if (vscp->varp()->isSc()) continue;
|
||||
// Create a sen tree triggered when this input changes
|
||||
AstSenTree*& senTreepr = inp2changedp[vscp];
|
||||
UASSERT_OBJ(!senTreepr, vscp, "Duplicate input change detect trigger");
|
||||
AstVarRef* const refp = new AstVarRef{flp, vscp, VAccess::READ};
|
||||
AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_CHANGED, refp};
|
||||
senTreepr = new AstSenTree{flp, senItemp};
|
||||
icoChangeSenTreeps.push_back(senTreepr);
|
||||
}
|
||||
}
|
||||
V3Stats::addStat("Scheduling, 'ico' change detect triggers", icoChangeSenTreeps.size());
|
||||
|
||||
// Gather the relevant sensitivity expressions and create the trigger kit
|
||||
const auto& senTreeps = getSenTreesUsedBy({&logic});
|
||||
std::vector<const AstSenTree*> senTreeps = getSenTreesUsedBy({&logic});
|
||||
senTreeps.insert(senTreeps.end(), icoChangeSenTreeps.begin(), icoChangeSenTreeps.end());
|
||||
const TriggerKit trigKit = TriggerKit::create(netlistp, initFuncp, senExprBuilder, {},
|
||||
senTreeps, "ico", extraTriggers, false, false);
|
||||
std::ignore = senExprBuilder.getAndClearResults();
|
||||
|
|
@ -543,14 +581,14 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
|
||||
// Remap sensitivities
|
||||
remapSensitivities(logic, trigKit.mapVec());
|
||||
for (auto& pair : inp2changedp) pair.second = trigKit.mapVec().at(pair.second);
|
||||
|
||||
// Create the inverse map from trigger ref AstSenTree to original AstSenTree
|
||||
V3Order::TrigToSenMap trigToSen;
|
||||
invertAndMergeSenTreeMap(trigToSen, trigKit.mapVec());
|
||||
|
||||
// The trigger top level inputs (first iteration)
|
||||
AstSenTree* const inputChanged
|
||||
= trigKit.newExtraTriggerSenTree(trigKit.vscp(), firstIterationTrigger);
|
||||
// The 'first iteration' trigger for top level inputs - lazy constructed only if needed
|
||||
AstSenTree* firstIterTriggerp = nullptr;
|
||||
|
||||
// The DPI Export trigger
|
||||
AstSenTree* const dpiExportTriggered
|
||||
|
|
@ -565,9 +603,19 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
netlistp, {&logic}, trigToSen, "ico", false, false,
|
||||
[&](const AstVarScope* vscp, std::vector<AstSenTree*>& out) {
|
||||
AstVar* const varp = vscp->varp();
|
||||
if (varp->isPrimaryInish() || varp->isSigUserRWPublic()) {
|
||||
out.push_back(inputChanged);
|
||||
// If it has an explicit change detect trigger, use that,
|
||||
// otherwise fall back to using the 'first iteration' trigger
|
||||
auto it = inp2changedp.find(vscp);
|
||||
if (it != inp2changedp.end()) {
|
||||
out.push_back(it->second);
|
||||
} else if (varp->isPrimaryInish() || varp->isSigUserRWPublic()) {
|
||||
if (!firstIterTriggerp) {
|
||||
firstIterTriggerp
|
||||
= trigKit.newExtraTriggerSenTree(trigKit.vscp(), firstIterationTrigger);
|
||||
}
|
||||
out.push_back(firstIterTriggerp);
|
||||
}
|
||||
// Add other triggers
|
||||
if (varp->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
||||
if (vscp->varp()->sensIfacep() || vscp->varp()->isVirtIface()) {
|
||||
const auto& ifaceTriggered
|
||||
|
|
@ -593,8 +641,14 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
// Work statements: Invoke the 'ico' function
|
||||
util::callVoidFunc(icoFuncp));
|
||||
|
||||
// Add the first iteration trigger to the trigger computation function
|
||||
trigKit.addExtraTriggerAssignment(icoLoop.firstIterp, firstIterationTrigger, false);
|
||||
// Add the first iteration trigger to the trigger computation function - if used
|
||||
if (firstIterTriggerp) {
|
||||
trigKit.addExtraTriggerAssignment(icoLoop.firstIterp, firstIterationTrigger, false);
|
||||
}
|
||||
|
||||
// Release temporary input change detect SenTrees
|
||||
for (AstSenTree* const senTreep : icoChangeSenTreeps) senTreep->deleteTree();
|
||||
icoChangeSenTreeps.clear();
|
||||
|
||||
return icoLoop.stmtsp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3073,6 +3073,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed");
|
||||
}
|
||||
// UINFOTREE(9, nodep, "", "VRout");
|
||||
if (nodep->access().isWriteOrRW()) nodep->varp()->maybeWritten(true);
|
||||
if (nodep->access().isWriteOrRW() && nodep->varp()->direction() == VDirection::CONSTREF) {
|
||||
nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ());
|
||||
} else if (nodep->access().isWriteOrRW() && nodep->varp()->isInput()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ test.scenarios('vlt')
|
|||
|
||||
test.compile(verilator_flags2=['--expand-limit 1 --stats -fno-dfg'])
|
||||
|
||||
test.file_grep(test.stats, r'Optimizations, expand limited\s+(\d+)', 7)
|
||||
test.file_grep(test.stats, r'Optimizations, expand limited\s+(\d+)', 29)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ test.scenarios('vlt')
|
|||
test.compile(
|
||||
verilator_flags2=["--stats", "--build", "--gate-stmts", "10000", "--expand-limit", "128"])
|
||||
|
||||
test.file_grep(test.stats, r'Optimizations, FuncOpt concat trees balanced\s+(\d+)', 2)
|
||||
test.file_grep(test.stats, r'Optimizations, FuncOpt concat trees balanced\s+(\d+)', 3)
|
||||
test.file_grep(test.stats, r'Optimizations, FuncOpt concat splits\s+(\d+)', 67)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#include <verilated.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include VM_PREFIX_INCLUDE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
contextp->threads(1);
|
||||
contextp->commandArgs(argc, argv);
|
||||
|
||||
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(), "top"}};
|
||||
topp->clk = 0;
|
||||
topp->i = 0;
|
||||
topp->eval();
|
||||
|
||||
while ((contextp->time() < 10000) && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->clk = !topp->clk;
|
||||
// Always set to the same constant value, so change detection will think it's not changing
|
||||
topp->i = 500000;
|
||||
topp->eval();
|
||||
if (topp->o != topp->i + 10) {
|
||||
const std::string msg = "%Error: incorrect output, got: " + std::to_string(topp->o)
|
||||
+ " expected: " + std::to_string(topp->i + 10);
|
||||
vl_fatal(__FILE__, __LINE__, "main", msg.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.top_filename = "t/t_sched_ico_change_detect_input_assigned.v"
|
||||
|
||||
test.compile(make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=[
|
||||
"--exe", "--stats", "-Wno-ASSIGNIN",
|
||||
"t/t_sched_ico_change_detect_input_assigned.cpp"
|
||||
])
|
||||
|
||||
test.execute()
|
||||
|
||||
# There should be a change detect for 'clk', but not for 'i'
|
||||
test.file_grep(test.stats, r"Scheduling, 'ico' change detect triggers\s+(\d+)", 1)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t(
|
||||
clk, i, o, cyc
|
||||
);
|
||||
|
||||
input clk, i;
|
||||
output o, cyc;
|
||||
|
||||
logic clk;
|
||||
int i; // Primary input that the design also drives
|
||||
int o;
|
||||
int cyc = 0;
|
||||
|
||||
// Logic dependent on primary input 'i'
|
||||
always_comb o = i + 10;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
// On even cycles, assign 'i'
|
||||
if (cyc % 2 == 0) i = cyc + 1000;
|
||||
if (cyc == 99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.top_filename = "t/t_sched_ico_change_detect_input_assigned.v"
|
||||
|
||||
test.compile(make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=[
|
||||
"--exe", "--stats", "-Wno-ASSIGNIN",
|
||||
"t/t_sched_ico_change_detect_input_assigned.cpp", "-fno-ico-change-detect"
|
||||
])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats, r"Scheduling, 'ico' change detect triggers\s+(\d+)", 0)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.top_filename = "t/t_sched_ico_change_detect_input_assigned.v"
|
||||
|
||||
test.compile(make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=[
|
||||
"--exe", "--stats", "-Wno-ASSIGNIN",
|
||||
"t/t_sched_ico_change_detect_input_assigned.cpp", "--vpi"
|
||||
])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats, r"Scheduling, 'ico' change detect triggers\s+(\d+)", 0)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.top_filename = "t/t_sched_ico_change_detect_input_assigned.v"
|
||||
|
||||
test.compile(make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=[
|
||||
"--exe", "--stats", "-Wno-ASSIGNIN",
|
||||
"t/t_sched_ico_change_detect_input_assigned.cpp", "-fico-change-detect", "--vpi"
|
||||
])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats, r"Scheduling, 'ico' change detect triggers\s+(\d+)", 1)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -139,12 +139,12 @@ C 'ft/t_wrapper_context.vl21n3tlinepagev_line/topoblockS21-24,28,3
|
|||
C 'ft/t_wrapper_context.vl35n3tlinepagev_line/topoblockS35htop0.top' 11
|
||||
C 'ft/t_wrapper_context.vl36n5tbranchpagev_branch/topoifS36htop0.top' 1
|
||||
C 'ft/t_wrapper_context.vl36n6tbranchpagev_branch/topoelseS37htop0.top' 10
|
||||
C 'ft/t_wrapper_context.vl39n3tlinepagev_line/topoblockS39-40htop0.top' 34
|
||||
C 'ft/t_wrapper_context.vl39n3tlinepagev_line/topoblockS39-40htop0.top' 13
|
||||
C 'ft/t_wrapper_context.vl41n5tbranchpagev_branch/topoifS41htop0.top' 0
|
||||
C 'ft/t_wrapper_context.vl41n6tbranchpagev_branch/topoelseS47htop0.top' 34
|
||||
C 'ft/t_wrapper_context.vl41n6tbranchpagev_branch/topoelseS47htop0.top' 13
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo((counter >= 32'sh5)==0) => 0htop0.top' 0
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo((counter >= 32'sh5)==1 && stop==1) => 1htop0.top' 0
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo(stop==0) => 0htop0.top' 0
|
||||
C 'ft/t_wrapper_context.vl42n8tlinepagev_line/topoelsehtop0.top' 0
|
||||
C 'ft/t_wrapper_context.vl48n7tbranchpagev_branch/topoifS48-50htop0.top' 1
|
||||
C 'ft/t_wrapper_context.vl48n8tbranchpagev_branch/topoelsehtop0.top' 33
|
||||
C 'ft/t_wrapper_context.vl48n8tbranchpagev_branch/topoelsehtop0.top' 12
|
||||
|
|
|
|||
|
|
@ -139,12 +139,12 @@ C 'ft/t_wrapper_context.vl21n3tlinepagev_line/topoblockS21-24,28,3
|
|||
C 'ft/t_wrapper_context.vl35n3tlinepagev_line/topoblockS35htop1.top' 6
|
||||
C 'ft/t_wrapper_context.vl36n5tbranchpagev_branch/topoifS36htop1.top' 1
|
||||
C 'ft/t_wrapper_context.vl36n6tbranchpagev_branch/topoelseS37htop1.top' 5
|
||||
C 'ft/t_wrapper_context.vl39n3tlinepagev_line/topoblockS39-40htop1.top' 19
|
||||
C 'ft/t_wrapper_context.vl41n5tbranchpagev_branch/topoifS41htop1.top' 19
|
||||
C 'ft/t_wrapper_context.vl39n3tlinepagev_line/topoblockS39-40htop1.top' 8
|
||||
C 'ft/t_wrapper_context.vl41n5tbranchpagev_branch/topoifS41htop1.top' 8
|
||||
C 'ft/t_wrapper_context.vl41n6tbranchpagev_branch/topoelseS47htop1.top' 0
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo((counter >= 32'sh5)==0) => 0htop1.top' 18
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo((counter >= 32'sh5)==0) => 0htop1.top' 7
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo((counter >= 32'sh5)==1 && stop==1) => 1htop1.top' 1
|
||||
C 'ft/t_wrapper_context.vl42n24texprpagev_expr/topo(stop==0) => 0htop1.top' 0
|
||||
C 'ft/t_wrapper_context.vl42n8tlinepagev_line/topoelsehtop1.top' 18
|
||||
C 'ft/t_wrapper_context.vl42n8tlinepagev_line/topoelsehtop1.top' 7
|
||||
C 'ft/t_wrapper_context.vl48n7tbranchpagev_branch/topoifS48-50htop1.top' 0
|
||||
C 'ft/t_wrapper_context.vl48n8tbranchpagev_branch/topoelsehtop1.top' 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue