mirror of https://github.com/YosysHQ/yosys.git
cxxrtl: detect buffered comb wires, not just feedback wires.
Any buffered combinatorial wires (including, as a subset, feedback wires) will prevent the design from always converging in one delta cycle. Before this commit, only feedback wires were detected. After this commit, any buffered combinatorial wires, including feedback wires, are detected. Co-authored-by: Jean-François Nguyen <jf@lambdaconcept.com>
This commit is contained in:
parent
abc8f1fcb6
commit
f24fb4ae82
|
@ -415,6 +415,7 @@ struct CxxrtlWorker {
|
||||||
bool localize_internal = false;
|
bool localize_internal = false;
|
||||||
bool localize_public = false;
|
bool localize_public = false;
|
||||||
bool run_splitnets = false;
|
bool run_splitnets = false;
|
||||||
|
bool max_opt_level = false;
|
||||||
|
|
||||||
std::ostringstream f;
|
std::ostringstream f;
|
||||||
std::string indent;
|
std::string indent;
|
||||||
|
@ -1648,6 +1649,8 @@ struct CxxrtlWorker {
|
||||||
void analyze_design(RTLIL::Design *design)
|
void analyze_design(RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
bool has_feedback_arcs = false;
|
bool has_feedback_arcs = false;
|
||||||
|
bool has_buffered_wires = false;
|
||||||
|
|
||||||
for (auto module : design->modules()) {
|
for (auto module : design->modules()) {
|
||||||
if (!design->selected_module(module))
|
if (!design->selected_module(module))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1844,10 +1847,9 @@ struct CxxrtlWorker {
|
||||||
if (!feedback_wires.empty()) {
|
if (!feedback_wires.empty()) {
|
||||||
has_feedback_arcs = true;
|
has_feedback_arcs = true;
|
||||||
log("Module `%s' contains feedback arcs through wires:\n", module->name.c_str());
|
log("Module `%s' contains feedback arcs through wires:\n", module->name.c_str());
|
||||||
for (auto wire : feedback_wires) {
|
for (auto wire : feedback_wires)
|
||||||
log(" %s\n", wire->name.c_str());
|
log(" %s\n", wire->name.c_str());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (auto wire : module->wires()) {
|
for (auto wire : module->wires()) {
|
||||||
if (feedback_wires[wire]) continue;
|
if (feedback_wires[wire]) continue;
|
||||||
|
@ -1856,13 +1858,45 @@ struct CxxrtlWorker {
|
||||||
if (wire->name.begins_with("$") && !localize_internal) continue;
|
if (wire->name.begins_with("$") && !localize_internal) continue;
|
||||||
if (wire->name.begins_with("\\") && !localize_public) continue;
|
if (wire->name.begins_with("\\") && !localize_public) continue;
|
||||||
if (sync_wires[wire]) continue;
|
if (sync_wires[wire]) continue;
|
||||||
// Outputs of FF/$memrd cells and LHS of sync actions do not end up in defs.
|
// Wires connected to synchronous outputs do not introduce defs.
|
||||||
if (flow.wire_defs[wire].size() != 1) continue;
|
if (flow.wire_defs[wire].size() != 1) continue;
|
||||||
localized_wires.insert(wire);
|
localized_wires.insert(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For maximum performance, the state of the simulation (which is the same as the set of its double buffered
|
||||||
|
// wires, since using a singly buffered wire for any kind of state introduces a race condition) should contain
|
||||||
|
// no wires attached to combinatorial outputs. Feedback wires, by definition, make that impossible. However,
|
||||||
|
// it is possible that a design with no feedback arcs would end up with doubly buffered wires in such cases
|
||||||
|
// as a wire with multiple drivers where one of them is combinatorial and the other is synchronous. Such designs
|
||||||
|
// also require more than one delta cycle to converge.
|
||||||
|
pool<RTLIL::Wire*> buffered_wires;
|
||||||
|
for (auto wire : module->wires()) {
|
||||||
|
// Only wires connected to combinatorial outputs introduce defs.
|
||||||
|
if (flow.wire_defs[wire].size() > 0 && !elided_wires.count(wire) && !localized_wires[wire]) {
|
||||||
|
if (!feedback_wires[wire])
|
||||||
|
buffered_wires.insert(wire);
|
||||||
}
|
}
|
||||||
if (has_feedback_arcs) {
|
}
|
||||||
log("Feedback arcs require delta cycles during evaluation.\n");
|
if (!buffered_wires.empty()) {
|
||||||
|
has_buffered_wires = true;
|
||||||
|
log("Module `%s' contains buffered combinatorial wires:\n", module->name.c_str());
|
||||||
|
for (auto wire : buffered_wires)
|
||||||
|
log(" %s\n", wire->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_feedback_arcs || has_buffered_wires) {
|
||||||
|
// Although both non-feedback buffered combinatorial wires and apparent feedback wires may be eliminated
|
||||||
|
// by optimizing the design, if after `opt_clean -purge` there are any feedback wires remaining, it is very
|
||||||
|
// likely that these feedback wires are indicative of a true logic loop, so they get emphasized in the message.
|
||||||
|
const char *why_pessimistic = nullptr;
|
||||||
|
if (has_feedback_arcs)
|
||||||
|
why_pessimistic = "feedback wires";
|
||||||
|
else if (has_buffered_wires)
|
||||||
|
why_pessimistic = "buffered combinatorial wires";
|
||||||
|
log("\n");
|
||||||
|
log_warning("Design contains %s, which require delta cycles during evaluation.\n", why_pessimistic);
|
||||||
|
if (!max_opt_level)
|
||||||
|
log("Increasing the optimization level may eliminate %s from the design.\n", why_pessimistic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2135,6 +2169,7 @@ struct CxxrtlBackend : public Backend {
|
||||||
|
|
||||||
switch (opt_level) {
|
switch (opt_level) {
|
||||||
case 5:
|
case 5:
|
||||||
|
worker.max_opt_level = true;
|
||||||
worker.run_splitnets = true;
|
worker.run_splitnets = true;
|
||||||
case 4:
|
case 4:
|
||||||
worker.localize_public = true;
|
worker.localize_public = true;
|
||||||
|
|
Loading…
Reference in New Issue