diff --git a/examples/cxx-api/scopeinfo_example.cc b/examples/cxx-api/scopeinfo_example.cc new file mode 100644 index 000000000..f163dff9e --- /dev/null +++ b/examples/cxx-api/scopeinfo_example.cc @@ -0,0 +1,144 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2023 Jannis Harder + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +// build: yosys-config --build scopeinfo_example.so scopeinfo_example.cc +// use: yosys -m scopeinfo_example.so + +#include "backends/rtlil/rtlil_backend.h" +#include "kernel/scopeinfo.h" +#include "kernel/yosys.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ScopeinfoExamplePass : public Pass { + ScopeinfoExamplePass() : Pass("scopeinfo_example", "dump scopeinfo") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" scopeinfo_example [options] [selection]\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing SCOPEINFO_EXAMPLE pass.\n"); + + bool do_wires = false; + bool do_common = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-wires") { + do_wires = true; + continue; + } + if (args[argidx] == "-common") { + do_common = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + + if (do_wires) { + for (auto module : design->selected_modules()) { + log("Source hierarchy for all selected wires within %s:\n", log_id(module)); + ModuleHdlnameIndex index(module); + + index.index_scopeinfo_cells(); + + for (auto wire : module->selected_wires()) { + if (!wire->name.isPublic()) + continue; + + auto wire_scope = index.containing_scope(wire); + + if (!wire_scope.first.valid()) { + log_warning("Couldn't find containing scope for %s in index\n", log_id(wire)); + continue; + } + + log("%s %s\n", wire_scope.first.path_str().c_str(), log_id(wire_scope.second)); + for (auto src : index.sources(wire)) + log(" - %s\n", src.c_str()); + } + } + } + + if (do_common) { + for (auto module : design->selected_modules()) { + std::vector wires = module->selected_wires(); + + // Shuffle wires so this example produces more interesting outputs + std::sort(wires.begin(), wires.end(), [](Wire *a, Wire *b) { + return mkhash_xorshift(a->name.hash() * 0x2c9277b5) < mkhash_xorshift(b->name.hash() * 0x2c9277b5); + }); + + ModuleHdlnameIndex index(module); + + index.index_scopeinfo_cells(); + + for (auto wire_i = wires.begin(), wire_end = wires.end(); wire_i != wire_end; ++wire_i) { + if (!(*wire_i)->name.isPublic()) + continue; + + std::pair scope_i = index.containing_scope(*wire_i); + if (!scope_i.first.valid()) + continue; + + int limit = 0; + + for (auto wire_j = wire_i + 1; wire_j != wire_end; ++wire_j) { + if (!(*wire_j)->name.isPublic()) + continue; + + std::pair scope_j = index.containing_scope(*wire_j); + if (!scope_j.first.valid()) + continue; + + // Skip wires in the same hierarchy level + if (scope_i.first == scope_j.first) + continue; + + + ModuleHdlnameIndex::Cursor common = scope_i.first.common_ancestor(scope_j.first); + + // Try to show at least some non-root common ancestors + if (common.is_root() && limit > 5) + continue; + + log("common_ancestor(%s %s%s%s, %s %s%s%s) = %s %s\n", + log_id(module), scope_i.first.path_str().c_str(), scope_i.first.is_root() ? "" : " ", log_id(scope_i.second), + log_id(module), scope_j.first.path_str().c_str(), scope_j.first.is_root() ? "" : " ", log_id(scope_j.second), + log_id(module), common.path_str().c_str() + ); + + if (++limit == 10) + break; + } + } + } + } + } +} ScopeinfoExamplePass; + +PRIVATE_NAMESPACE_END