cxxrtl: emit debug information for alias wires.
authorwhitequark <whitequark@whitequark.org>
Mon, 8 Jun 2020 16:22:30 +0000 (16:22 +0000)
committerwhitequark <whitequark@whitequark.org>
Mon, 8 Jun 2020 17:09:49 +0000 (17:09 +0000)
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

index a43a23d04071eb0d05c55ea4df4ea3e944bbe057..01caa3793b21795c157a5b6769d86f673558d5f1 100644 (file)
@@ -539,6 +539,7 @@ struct CxxrtlWorker {
        dict<const RTLIL::Wire*, FlowGraph::Node> elided_wires;
        dict<const RTLIL::Module*, std::vector<FlowGraph::Node>> schedule;
        pool<const RTLIL::Wire*> localized_wires;
+       dict<const RTLIL::Wire*, const RTLIL::Wire*> debug_alias_wires;
        dict<const RTLIL::Module*, pool<std::string>> blackbox_specializations;
        dict<const RTLIL::Module*, bool> 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<RTLIL::IdString, RTLIL::Const> &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