From 9b39c6f7442a525c8dbfd94f1af65a0b606e648b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jun 2020 16:22:30 +0000 Subject: [PATCH] cxxrtl: emit debug information for alias wires. Alias wires can represent a significant chunk of the design in highly hierarchical designs; in Minerva SRAM, there are 273 member wires and 527 alias wires. Showing them in every hierarchy level significantly improves usability. --- backends/cxxrtl/cxxrtl_backend.cc | 58 +++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index a43a23d04..01caa3793 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -539,6 +539,7 @@ struct CxxrtlWorker { dict elided_wires; dict> schedule; pool localized_wires; + dict debug_alias_wires; dict> blackbox_specializations; dict eval_converges; @@ -1606,15 +1607,29 @@ struct CxxrtlWorker { void dump_debug_info_method(RTLIL::Module *module) { + size_t count_member_wires = 0; + size_t count_alias_wires = 0; + size_t count_skipped_wires = 0; inc_indent(); f << indent << "assert(path.empty() || path[path.size() - 1] == ' ');\n"; for (auto wire : module->wires()) { if (wire->name[0] != '\\') continue; - if (localized_wires.count(wire)) + if (debug_alias_wires.count(wire)) { + // Alias of a member wire + f << indent << "items.emplace(path + " << escape_cxx_string(get_hdl_name(wire)); + f << ", debug_item(" << mangle(debug_alias_wires[wire]) << "));\n"; + count_alias_wires++; continue; - f << indent << "items.emplace(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(" << mangle(wire) << "));\n"; + } + if (!localized_wires.count(wire)) { + // Member wire + f << indent << "items.emplace(path + " << escape_cxx_string(get_hdl_name(wire)); + f << ", debug_item(" << mangle(wire) << "));\n"; + count_member_wires++; + continue; + } + count_skipped_wires++; } for (auto &memory_it : module->memories) { if (memory_it.first[0] != '\\') @@ -1630,6 +1645,11 @@ struct CxxrtlWorker { f << "path + " << escape_cxx_string(get_hdl_name(cell) + ' ') << ");\n"; } dec_indent(); + + log_debug("Debug information statistics for module %s:\n", log_id(module)); + log_debug(" Member wires: %zu\n", count_member_wires); + log_debug(" Alias wires: %zu\n", count_alias_wires); + log_debug(" Other wires: %zu (no debug information)\n", count_skipped_wires); } void dump_metadata_map(const dict &metadata_map) @@ -2141,6 +2161,38 @@ struct CxxrtlWorker { } eval_converges[module] = feedback_wires.empty() && buffered_wires.empty(); + + if (debug_info) { + // Find wires that alias other wires; debug information can be enriched with these at essentially zero + // additional cost. + // + // Note that the information collected here can't be used for optimizing the netlist: debug information queries + // are pure and run on a design in a stable state, which allows assumptions that do not otherwise hold. + for (auto wire : module->wires()) { + if (wire->name[0] != '\\') + continue; + if (!localized_wires[wire]) + continue; + const RTLIL::Wire *wire_it = wire; + while (1) { + if (!(flow.wire_def_elidable.count(wire_it) && flow.wire_def_elidable[wire_it])) + break; // not an alias: complex def + log_assert(flow.wire_comb_defs[wire_it].size() == 1); + FlowGraph::Node *node = *flow.wire_comb_defs[wire_it].begin(); + if (node->connect.second.is_wire()) { + RTLIL::Wire *rhs_wire = node->connect.second.as_wire(); + if (localized_wires[rhs_wire]) { + wire_it = rhs_wire; // maybe an alias + } else { + debug_alias_wires[wire] = rhs_wire; // is an alias + break; + } + } else { + break; // not an alias: complex rhs + } + } + } + } } if (has_feedback_arcs || has_buffered_wires) { // Although both non-feedback buffered combinatorial wires and apparent feedback wires may be eliminated -- 2.30.2