Internals: Add stats/dump of circular logic in scheduling (#6953)
This commit is contained in:
parent
5b84635bde
commit
7875552354
|
|
@ -614,6 +614,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
putfs(nodep, "$_EXPRSTMT(\n");
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
putbs(", ");
|
||||
iterateAndNextConstNull(nodep->resultp());
|
||||
puts(");\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,14 +35,17 @@
|
|||
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3Sched.h"
|
||||
#include "V3SenTree.h"
|
||||
#include "V3SplitVar.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -222,13 +225,31 @@ bool isCut(const SchedAcyclicVarVertex* vtxp) {
|
|||
}
|
||||
|
||||
std::vector<SchedAcyclicVarVertex*> findCutVertices(Graph* graphp) {
|
||||
// List of cut vertices being computed here
|
||||
std::vector<SchedAcyclicVarVertex*> result;
|
||||
const VNUser1InUse user1InUse; // bool: already added to result
|
||||
|
||||
// Statistics
|
||||
size_t nCyclicVtxs = 0; // Number of vertices that are part of an SCC (cycle)
|
||||
size_t nCyclicVars = 0; // Number of variables that are part of an SCC (cycle)
|
||||
std::unordered_set<uint32_t> sccs; // Unique SCC colors
|
||||
|
||||
for (V3GraphVertex& vtx : graphp->vertices()) {
|
||||
if (!vtx.color()) continue; // Not part of an SCC (cycle), can ignore
|
||||
++nCyclicVtxs;
|
||||
if (SchedAcyclicVarVertex* const vvtxp = vtx.cast<SchedAcyclicVarVertex>()) {
|
||||
++nCyclicVars;
|
||||
if (!vvtxp->vscp()->user1SetOnce() && isCut(vvtxp)) result.push_back(vvtxp);
|
||||
}
|
||||
// Don't bother counting if not dumping statistics
|
||||
if (v3Global.opt.stats()) sccs.insert(vtx.color());
|
||||
}
|
||||
|
||||
V3Stats::addStat("Scheduling, Cycles, cyclic variables", nCyclicVars);
|
||||
V3Stats::addStat("Scheduling, Cycles, cyclic logic blocks", nCyclicVtxs - nCyclicVars);
|
||||
V3Stats::addStat("Scheduling, Cycles, unique SCCs", sccs.size());
|
||||
V3Stats::addStat("Scheduling, Cycles, cut variables", result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -367,6 +388,61 @@ void reportCycles(Graph* graphp, const std::vector<SchedAcyclicVarVertex*>& cutV
|
|||
}
|
||||
}
|
||||
|
||||
void dumpSccs(V3Graph* graphp) {
|
||||
// Map from SCC color to vertices in that SCC
|
||||
std::map<uint32_t, std::vector<V3GraphVertex*>> scc2Vtxps;
|
||||
|
||||
// Gather all vertices in each SCC
|
||||
for (V3GraphVertex& vtx : graphp->vertices()) {
|
||||
if (!vtx.color()) continue;
|
||||
scc2Vtxps[vtx.color()].push_back(&vtx);
|
||||
}
|
||||
|
||||
// Dump Verilog for each SCC into separate files
|
||||
for (const auto& pair : scc2Vtxps) {
|
||||
const uint32_t color = pair.first;
|
||||
const std::vector<V3GraphVertex*>& vtxps = pair.second;
|
||||
|
||||
// Open dump file
|
||||
const std::string fname
|
||||
= v3Global.debugFilename("sched_scc_" + std::to_string(color) + ".v");
|
||||
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(fname)};
|
||||
if (ofp->fail()) v3fatal("Can't write file: " << fname);
|
||||
|
||||
// Write header
|
||||
*ofp << "// SCC " << color << ", size: " << vtxps.size() << "\n\n";
|
||||
|
||||
// Dump variables
|
||||
*ofp << "//////////////////////////////////////////////////////////////////////\n";
|
||||
*ofp << "// Variables\n";
|
||||
*ofp << "//////////////////////////////////////////////////////////////////////\n";
|
||||
*ofp << "\n";
|
||||
for (V3GraphVertex* vtxp : vtxps) {
|
||||
const SchedAcyclicVarVertex* const vvtxp = vtxp->cast<SchedAcyclicVarVertex>();
|
||||
if (!vvtxp) continue;
|
||||
AstVarScope* const vscp = vvtxp->vscp();
|
||||
*ofp << "// " << vscp->fileline()->ascii() << "\n";
|
||||
*ofp << "// " << vscp->prettyName() << "\n";
|
||||
V3EmitV::debugVerilogForTree(vscp->varp(), *ofp);
|
||||
*ofp << "\n";
|
||||
}
|
||||
|
||||
// Dump logic
|
||||
*ofp << "\n";
|
||||
*ofp << "//////////////////////////////////////////////////////////////////////\n";
|
||||
*ofp << "// Logic\n";
|
||||
*ofp << "//////////////////////////////////////////////////////////////////////\n";
|
||||
*ofp << "\n";
|
||||
for (V3GraphVertex* vtxp : vtxps) {
|
||||
const SchedAcyclicLogicVertex* const lvtxp = vtxp->cast<SchedAcyclicLogicVertex>();
|
||||
if (!lvtxp) continue;
|
||||
*ofp << "// " << lvtxp->logicp()->fileline()->ascii() << "\n";
|
||||
V3EmitV::debugVerilogForTree(lvtxp->logicp(), *ofp);
|
||||
*ofp << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogicByScope fixCuts(AstNetlist* netlistp,
|
||||
const std::vector<SchedAcyclicVarVertex*>& cutVertices) {
|
||||
// For all logic that reads a cut vertex, build a map from logic -> list of cut AstVarScope
|
||||
|
|
@ -439,6 +515,9 @@ LogicByScope breakCycles(AstNetlist* netlistp, const LogicByScope& combinational
|
|||
// Report warnings/diagnostics
|
||||
reportCycles(graphp.get(), cutVertices);
|
||||
|
||||
// Debug dump
|
||||
if (dumpLevel() >= 6) dumpSccs(graphp.get());
|
||||
|
||||
// Fix cuts by converting dependent logic to use hybrid sensitivities
|
||||
return fixCuts(netlistp, cutVertices);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -653,7 +653,7 @@ module Vt_debug_emitv_t;
|
|||
begin : assert_intrinsic
|
||||
assert ((| $_EXPRSTMT(
|
||||
ao = (a);
|
||||
, );
|
||||
, 32'h1);
|
||||
)) begin
|
||||
end
|
||||
else begin
|
||||
|
|
|
|||
|
|
@ -1215,7 +1215,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_1__0
|
||||
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||
-V{t#,#} Suspending process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_0__25____VforkParent.(t.__Vtask_status__26__Vfuncout); , ); )) at t/t_timing_class.v:224
|
||||
-V{t#,#} Suspending process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_0__25____VforkParent.(t.__Vtask_status__26__Vfuncout); , t.__Vtask_status__26__Vfuncout); )) at t/t_timing_class.v:224
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76
|
||||
-V{t#,#} Process forked at t/t_timing_class.v:76 finished
|
||||
|
|
@ -1231,7 +1231,7 @@
|
|||
-V{t#,#} Process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 awaiting resumption
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224
|
||||
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||
-V{t#,#} Process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_0__25____VforkParent.(t.__Vtask_status__26__Vfuncout); , ); )) at t/t_timing_class.v:224 awaiting resumption
|
||||
-V{t#,#} Process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_0__25____VforkParent.(t.__Vtask_status__26__Vfuncout); , t.__Vtask_status__26__Vfuncout); )) at t/t_timing_class.v:224 awaiting resumption
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
|
|
@ -1347,7 +1347,7 @@
|
|||
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_2__0
|
||||
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||
-V{t#,#} Suspending process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_1__29____VforkParent.(t.__Vtask_status__30__Vfuncout); , ); )) at t/t_timing_class.v:229
|
||||
-V{t#,#} Suspending process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_1__29____VforkParent.(t.__Vtask_status__30__Vfuncout); , t.__Vtask_status__30__Vfuncout); )) at t/t_timing_class.v:229
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
||||
|
|
@ -1356,7 +1356,7 @@
|
|||
-V{t#,#} - Process waiting at t/t_timing_class.v:229
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:229
|
||||
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||
-V{t#,#} Process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_1__29____VforkParent.(t.__Vtask_status__30__Vfuncout); , ); )) at t/t_timing_class.v:229 awaiting resumption
|
||||
-V{t#,#} Process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_1__29____VforkParent.(t.__Vtask_status__30__Vfuncout); , t.__Vtask_status__30__Vfuncout); )) at t/t_timing_class.v:229 awaiting resumption
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ test.top_filename = "t/t_unoptflat_simple_2.v"
|
|||
|
||||
# Compile only
|
||||
test.compile(verilator_flags3=[],
|
||||
verilator_flags2=["--report-unoptflat", "-fno-dfg"],
|
||||
verilator_flags2=["--report-unoptflat", "-fno-dfg", "--dumpi-V3SchedAcyclic", "6"],
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue