Merge pull request #46 from antmicro/set_clock_groups

SDC: Add set_clock_groups command
diff --git a/Makefile b/Makefile
index 72611b4..c397859 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-PLUGIN_LIST := fasm xdc params selection sdc get_count ql-iob
+PLUGIN_LIST := fasm xdc params selection sdc get_count ql-iob design_introspection
 PLUGINS := $(foreach plugin,$(PLUGIN_LIST),$(plugin).so)
 PLUGINS_INSTALL := $(foreach plugin,$(PLUGIN_LIST),install_$(plugin))
 PLUGINS_CLEAN := $(foreach plugin,$(PLUGIN_LIST),clean_$(plugin))
diff --git a/design_introspection-plugin/Makefile b/design_introspection-plugin/Makefile
new file mode 100644
index 0000000..85a605a
--- /dev/null
+++ b/design_introspection-plugin/Makefile
@@ -0,0 +1,9 @@
+NAME = design_introspection
+SOURCES = design_introspection.cc \
+	  get_cmd.cc \
+	  get_nets.cc \
+	  get_ports.cc \
+	  get_cells.cc \
+	  get_pins.cc
+
+include ../Makefile_plugin.common
diff --git a/design_introspection-plugin/design_introspection.cc b/design_introspection-plugin/design_introspection.cc
new file mode 100644
index 0000000..64fdbbc
--- /dev/null
+++ b/design_introspection-plugin/design_introspection.cc
@@ -0,0 +1,39 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+
+#include "get_nets.h"
+#include "get_ports.h"
+#include "get_cells.h"
+#include "get_pins.h"
+
+USING_YOSYS_NAMESPACE
+
+PRIVATE_NAMESPACE_BEGIN
+
+struct DesignIntrospection {
+    DesignIntrospection(){}
+    GetNets get_nets_cmd;
+    GetPorts get_ports_cmd;
+    GetCells get_cells_cmd;
+    GetPins get_pins_cmd;
+} DesignIntrospection;
+
+
+PRIVATE_NAMESPACE_END
diff --git a/design_introspection-plugin/get_cells.cc b/design_introspection-plugin/get_cells.cc
new file mode 100644
index 0000000..937545d
--- /dev/null
+++ b/design_introspection-plugin/get_cells.cc
@@ -0,0 +1,48 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#include "get_cells.h"
+
+USING_YOSYS_NAMESPACE
+
+std::string GetCells::TypeName() { return "cell"; }
+
+std::string GetCells::SelectionType() { return "c"; }
+
+GetCells::SelectionObjects GetCells::ExtractSelection(RTLIL::Design* design, const CommandArgs& args) {
+    SelectionObjects selected_objects;
+    for (auto module : design->selected_modules()) {
+	for (auto cell : module->selected_cells()) {
+	    if (args.filters.size() > 0) {
+		Filter filter = args.filters.at(0);
+		std::string attr_value = cell->get_string_attribute(
+		    RTLIL::IdString(RTLIL::escape_id(filter.first)));
+		if (attr_value.compare(filter.second)) {
+		    continue;
+		}
+	    }
+	    std::string object_name(RTLIL::unescape_id(cell->name));
+	    selected_objects.push_back(object_name);
+	}
+    }
+    if (selected_objects.size() == 0 and !args.is_quiet) {
+	log_warning("Couldn't find matching cell.\n");
+    }
+    return selected_objects;
+}
diff --git a/design_introspection-plugin/get_cells.h b/design_introspection-plugin/get_cells.h
new file mode 100644
index 0000000..205d50b
--- /dev/null
+++ b/design_introspection-plugin/get_cells.h
@@ -0,0 +1,36 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#ifndef _GET_CELLS_H_
+#define _GET_CELLS_H_
+
+#include "get_cmd.h"
+
+USING_YOSYS_NAMESPACE
+
+struct GetCells : public GetCmd {
+    GetCells() : GetCmd("get_cells", "Print matching cells") {}
+
+    std::string TypeName() override;
+    std::string SelectionType() override;
+    SelectionObjects ExtractSelection(RTLIL::Design* design,
+                          const CommandArgs& args) override;
+};
+
+#endif  // GET_CELLS_H_
diff --git a/design_introspection-plugin/get_cmd.cc b/design_introspection-plugin/get_cmd.cc
new file mode 100644
index 0000000..4b54ded
--- /dev/null
+++ b/design_introspection-plugin/get_cmd.cc
@@ -0,0 +1,138 @@
+#include "get_cmd.h"
+
+USING_YOSYS_NAMESPACE
+
+void GetCmd::help() {
+    //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+    log("\n");
+    log("   get_%ss [-quiet] [-filter filter_expression] "
+        "<%s_selection> \n",
+        TypeName().c_str(), TypeName().c_str());
+    log("\n");
+    log("Get matching %ss\n", TypeName().c_str());
+    log("\n");
+    log("Print the output to stdout too. This is useful when all Yosys "
+        "is "
+        "executed.\n");
+    log("\n");
+    log("    -filter\n");
+    log("        Name and value of attribute to be taken into "
+        "account.\n");
+    log("        e.g. -filter { attr == \"true\" }\n");
+    log("\n");
+    log("    -quiet\n");
+    log("        Don't print the result of the execution to stdout.\n");
+    log("\n");
+    log("    <selection_pattern>\n");
+    log("        Selection of %s names. Default are all %ss in the "
+        "design.\n",
+        TypeName().c_str(), TypeName().c_str());
+    log("\n");
+}
+
+void GetCmd::ExecuteSelection(RTLIL::Design* design, const CommandArgs& args) {
+    std::vector<std::string> selection_args;
+    // Add name of top module to selection string
+    std::transform(args.selection_objects.begin(), args.selection_objects.end(),
+                   std::back_inserter(selection_args),
+                   [&](const std::string& obj) {
+	               return RTLIL::unescape_id(design->top_module()->name) +
+	                      "/" + SelectionType() + ":" + obj;
+                   });
+    extra_args(selection_args, 0, design);
+    if (design->selected_modules().empty()) {
+	if (!args.is_quiet) {
+	    log_warning("Specified %s not found in design\n",
+	                TypeName().c_str());
+	}
+    }
+}
+
+void GetCmd::PackToTcl(const SelectionObjects& objects) {
+    Tcl_Obj* tcl_result;
+    if (objects.size() == 1) {
+	tcl_result = Tcl_NewStringObj(objects.at(0).c_str(), -1);
+    } else {
+	tcl_result = Tcl_NewListObj(0, NULL);
+	for (const auto& object : objects) {
+	    Tcl_Obj* value_obj = Tcl_NewStringObj(object.c_str(), -1);
+	    Tcl_ListObjAppendElement(yosys_get_tcl_interp(), tcl_result,
+	                             value_obj);
+	}
+    }
+    Tcl_SetObjResult(yosys_get_tcl_interp(), tcl_result);
+}
+
+GetCmd::CommandArgs GetCmd::ParseCommand(const std::vector<std::string>& args) {
+    CommandArgs parsed_args{.filters = Filters(),
+                            .is_quiet = false,
+                            .selection_objects = SelectionObjects()};
+    size_t argidx(0);
+    for (argidx = 1; argidx < args.size(); argidx++) {
+	std::string arg = args[argidx];
+	if (arg == "-quiet") {
+	    parsed_args.is_quiet = true;
+	    continue;
+	}
+
+	if (arg == "-filter" and argidx + 1 < args.size()) {
+	    std::string filter_arg = args[++argidx];
+
+	    // Remove spaces
+	    filter_arg.erase(
+	        std::remove_if(filter_arg.begin(), filter_arg.end(), isspace),
+	        filter_arg.end());
+
+	    // Parse filters
+	    // TODO Add support for multiple condition expression
+	    // Currently only a single == is supported
+	    std::regex filter_attr_regex("(\\w+\\s?==\\s?\\w+)([(||)(&&)]*)");
+	    std::regex_token_iterator<std::string::iterator> regex_end;
+	    std::regex_token_iterator<std::string::iterator> matches(
+	        filter_arg.begin(), filter_arg.end(), filter_attr_regex, 1);
+	    if (matches == regex_end) {
+		log_warning(
+		    "Currently -filter switch supports only a single "
+		    "'equal(==)' condition expression, the rest will be "
+		    "ignored\n");
+	    }
+
+	    while (matches != regex_end) {
+		std::string filter(*matches++);
+		auto separator = filter.find("==");
+		if (separator == std::string::npos) {
+		    log_cmd_error("Incorrect filter expression: %s\n",
+		                  args[argidx].c_str());
+		}
+		parsed_args.filters.emplace_back(filter.substr(0, separator),
+		                                 filter.substr(separator + 2));
+	    }
+	    if (parsed_args.filters.size() > 1) {
+		log_warning(
+		    "Currently -filter switch supports only a single "
+		    "'equal(==)' condition expression, the rest will be "
+		    "ignored\n");
+	    }
+	    continue;
+	}
+
+	if (arg.size() > 0 and arg[0] == '-') {
+	    log_cmd_error("Unknown option %s.\n", arg.c_str());
+	}
+
+	break;
+    }
+    std::copy(args.begin() + argidx, args.end(),
+              std::back_inserter(parsed_args.selection_objects));
+    return parsed_args;
+}
+
+void GetCmd::execute(std::vector<std::string> args, RTLIL::Design* design) {
+    if (design->top_module() == nullptr) {
+	log_cmd_error("No top module detected\n");
+    }
+
+    CommandArgs parsed_args(ParseCommand(args));
+    ExecuteSelection(design, parsed_args);
+    PackToTcl(ExtractSelection(design, parsed_args));
+}
diff --git a/design_introspection-plugin/get_cmd.h b/design_introspection-plugin/get_cmd.h
new file mode 100644
index 0000000..983a50d
--- /dev/null
+++ b/design_introspection-plugin/get_cmd.h
@@ -0,0 +1,55 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#ifndef _GET_CMD_H_
+#define _GET_CMD_H_
+
+#include "kernel/register.h"
+
+USING_YOSYS_NAMESPACE
+
+struct GetCmd : public Pass {
+    using Filter = std::pair<std::string, std::string>;
+    using Filters = std::vector<Filter>;
+    using SelectionObjects = std::vector<std::string>;
+    struct CommandArgs {
+	Filters filters;
+	bool is_quiet;
+	SelectionObjects selection_objects;
+    };
+
+    GetCmd(const std::string& name, const std::string& description)
+        : Pass(name, description) {}
+
+    void help() override;
+    void execute(std::vector<std::string> args, RTLIL::Design* design) override;
+
+   protected:
+    CommandArgs ParseCommand(const std::vector<std::string>& args);
+    void PackToTcl(const SelectionObjects& objects);
+
+   private:
+    virtual std::string TypeName() = 0;
+    virtual std::string SelectionType() = 0;
+    virtual SelectionObjects ExtractSelection(RTLIL::Design* design, const CommandArgs& args) = 0;
+    virtual void ExecuteSelection(RTLIL::Design* design,
+                                  const CommandArgs& args);
+};
+
+#endif  // GET_CMD_H_
diff --git a/design_introspection-plugin/get_nets.cc b/design_introspection-plugin/get_nets.cc
new file mode 100644
index 0000000..db5d375
--- /dev/null
+++ b/design_introspection-plugin/get_nets.cc
@@ -0,0 +1,49 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#include "get_nets.h"
+
+USING_YOSYS_NAMESPACE
+
+std::string GetNets::TypeName() { return "net"; }
+
+std::string GetNets::SelectionType() { return "w"; }
+
+GetNets::SelectionObjects GetNets::ExtractSelection(RTLIL::Design* design,
+                                                    const CommandArgs& args) {
+    SelectionObjects selected_objects;
+    for (auto module : design->selected_modules()) {
+	for (auto wire : module->selected_wires()) {
+	    if (args.filters.size() > 0) {
+		Filter filter = args.filters.at(0);
+		std::string attr_value = wire->get_string_attribute(
+		    RTLIL::IdString(RTLIL::escape_id(filter.first)));
+		if (attr_value.compare(filter.second)) {
+		    continue;
+		}
+	    }
+	    std::string object_name(RTLIL::unescape_id(wire->name));
+	    selected_objects.push_back(object_name);
+	}
+    }
+    if (selected_objects.size() == 0 and !args.is_quiet) {
+	log_warning("Couldn't find matching net.\n");
+    }
+    return selected_objects;
+}
diff --git a/design_introspection-plugin/get_nets.h b/design_introspection-plugin/get_nets.h
new file mode 100644
index 0000000..11f7502
--- /dev/null
+++ b/design_introspection-plugin/get_nets.h
@@ -0,0 +1,36 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#ifndef _GET_NETS_H_
+#define _GET_NETS_H_
+
+#include "get_cmd.h"
+
+USING_YOSYS_NAMESPACE
+
+struct GetNets : public GetCmd {
+    GetNets() : GetCmd("get_nets", "Print matching nets") {}
+
+    std::string TypeName() override;
+    std::string SelectionType() override;
+    SelectionObjects ExtractSelection(RTLIL::Design* design,
+                                      const CommandArgs& args) override;
+};
+
+#endif  // GET_NETS_H_
diff --git a/design_introspection-plugin/get_pins.cc b/design_introspection-plugin/get_pins.cc
new file mode 100644
index 0000000..d39f6bc
--- /dev/null
+++ b/design_introspection-plugin/get_pins.cc
@@ -0,0 +1,81 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#include "get_pins.h"
+
+USING_YOSYS_NAMESPACE
+
+std::string GetPins::TypeName() { return "pin"; }
+
+std::string GetPins::SelectionType() { return "c"; }
+
+void GetPins::ExecuteSelection(RTLIL::Design* design, const CommandArgs& args) {
+    (void)design;
+    (void)args;
+}
+
+GetPins::SelectionObjects GetPins::ExtractSelection(RTLIL::Design* design,
+                                                    const CommandArgs& args) {
+    SelectionObjects selected_objects;
+    for (auto obj : args.selection_objects) {
+	size_t port_separator = obj.find_last_of("/");
+	std::string cell = obj.substr(0, port_separator);
+	std::string port = obj.substr(port_separator + 1);
+	SelectionObjects selection{
+	    RTLIL::unescape_id(design->top_module()->name) + "/" +
+	    SelectionType() + ":" + cell};
+	extra_args(selection, 0, design);
+	ExtractSingleSelection(selected_objects, design, port, args);
+    }
+    if (selected_objects.size() == 0 and !args.is_quiet) {
+	log_warning("Couldn't find matching pin.\n");
+    }
+    return selected_objects;
+}
+
+void GetPins::ExtractSingleSelection(SelectionObjects& objects,
+                                     RTLIL::Design* design,
+                                     const std::string& port_name,
+                                     const CommandArgs& args) {
+    if (design->selected_modules().empty()) {
+	if (!args.is_quiet) {
+	    log_warning("Specified %s not found in design\n",
+	                TypeName().c_str());
+	}
+    }
+    for (auto module : design->selected_modules()) {
+	for (auto cell : module->selected_cells()) {
+	    if (!cell->hasPort(RTLIL::escape_id(port_name))) {
+		continue;
+	    }
+	    if (args.filters.size() > 0) {
+		Filter filter = args.filters.at(0);
+		std::string attr_value = cell->get_string_attribute(
+		    RTLIL::IdString(RTLIL::escape_id(filter.first)));
+		if (attr_value.compare(filter.second)) {
+		    continue;
+		}
+	    }
+	    std::string pin_name(RTLIL::unescape_id(cell->name) + "/" +
+	                         port_name);
+	    objects.push_back(pin_name);
+	}
+    }
+}
+
diff --git a/design_introspection-plugin/get_pins.h b/design_introspection-plugin/get_pins.h
new file mode 100644
index 0000000..f7ebe14
--- /dev/null
+++ b/design_introspection-plugin/get_pins.h
@@ -0,0 +1,43 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#ifndef _GET_PINS_H_
+#define _GET_PINS_H_
+
+#include "get_cmd.h"
+
+USING_YOSYS_NAMESPACE
+
+struct GetPins : public GetCmd {
+    GetPins() : GetCmd("get_pins", "Print matching pins") {}
+
+   private:
+    std::string TypeName() override;
+    std::string SelectionType() override;
+    SelectionObjects ExtractSelection(RTLIL::Design* design,
+                                      const CommandArgs& args) override;
+    void ExecuteSelection(RTLIL::Design* design,
+                          const CommandArgs& args) override;
+    void ExtractSingleSelection(SelectionObjects& objects,
+                                RTLIL::Design* design,
+                                const std::string& port_name,
+                                const CommandArgs& args);
+};
+
+#endif  // GET_PINS_H_
diff --git a/design_introspection-plugin/get_ports.cc b/design_introspection-plugin/get_ports.cc
new file mode 100644
index 0000000..ef29b95
--- /dev/null
+++ b/design_introspection-plugin/get_ports.cc
@@ -0,0 +1,57 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#include "get_ports.h"
+
+USING_YOSYS_NAMESPACE
+
+std::string GetPorts::TypeName() { return "port"; }
+
+std::string GetPorts::SelectionType() { return "x"; }
+
+void GetPorts::ExecuteSelection([[gnu::unused]] RTLIL::Design* design,
+                               [[gnu::unused]] const CommandArgs& args) {
+}
+
+GetPorts::SelectionObjects GetPorts::ExtractSelection(RTLIL::Design* design,
+                                                      const CommandArgs& args) {
+    std::string port_name = args.selection_objects.at(0);
+    std::string port_str(port_name.size(), '\0');
+    int bit(0);
+    if (!sscanf(port_name.c_str(), "%[^[][%d]", &port_str[0], &bit)) {
+	log_error("Couldn't find port %s\n", port_name.c_str());
+    }
+
+    port_str.resize(strlen(port_str.c_str()));
+    RTLIL::IdString port_id(RTLIL::escape_id(port_str));
+    SelectionObjects objects;
+    if (auto wire = design->top_module()->wire(port_id)) {
+	if (wire->port_input || wire->port_output) {
+	    if (bit >= wire->start_offset &&
+	        bit < wire->start_offset + wire->width) {
+		objects.push_back(port_name);
+	    }
+	}
+    }
+    if (objects.size() == 0 and !args.is_quiet) {
+	log_warning("Couldn't find port matching %s\n", port_name.c_str());
+    }
+    return objects;
+}
+
diff --git a/design_introspection-plugin/get_ports.h b/design_introspection-plugin/get_ports.h
new file mode 100644
index 0000000..89ba49a
--- /dev/null
+++ b/design_introspection-plugin/get_ports.h
@@ -0,0 +1,40 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2020  The Symbiflow Authors
+ *
+ *  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.
+ *
+ */
+#ifndef _GET_PORTS_H_
+#define _GET_PORTS_H_
+
+#include "get_cmd.h"
+
+USING_YOSYS_NAMESPACE
+
+struct GetPorts : public GetCmd {
+    GetPorts() : GetCmd("get_ports", "Print matching ports") {}
+
+   private:
+    std::string TypeName() override;
+    std::string SelectionType() override;
+    /* void execute(std::vector<std::string> args, RTLIL::Design* design) override; */
+    SelectionObjects ExtractSelection(RTLIL::Design* design,
+                                      const CommandArgs& args) override;
+    void ExecuteSelection(RTLIL::Design* design,
+                          const CommandArgs& args) override;
+};
+
+#endif  // GET_PORTS_H_
diff --git a/design_introspection-plugin/tests/Makefile b/design_introspection-plugin/tests/Makefile
new file mode 100644
index 0000000..fcca1e9
--- /dev/null
+++ b/design_introspection-plugin/tests/Makefile
@@ -0,0 +1,11 @@
+TESTS = get_nets \
+	get_ports \
+	get_cells \
+	get_pins
+
+include $(shell pwd)/../../Makefile_test.common
+
+get_nets_verify = $(call diff_test,get_nets,txt)
+get_ports_verify = $(call diff_test,get_ports,txt)
+get_cells_verify = $(call diff_test,get_cells,txt)
+get_pins_verify = $(call diff_test,get_pins,txt)
diff --git a/design_introspection-plugin/tests/get_cells/get_cells.golden.txt b/design_introspection-plugin/tests/get_cells/get_cells.golden.txt
new file mode 100644
index 0000000..d33818d
--- /dev/null
+++ b/design_introspection-plugin/tests/get_cells/get_cells.golden.txt
@@ -0,0 +1,15 @@
+
+*inter* cells quiet
+bottom_intermediate_inst.OBUF_8
+
+*inter* cells
+bottom_intermediate_inst.OBUF_8
+
+*inter* cells with invalid filter expression
+bottom_intermediate_inst.OBUF_8
+
+Filtered cells
+OBUFTDS_2
+
+All cells
+{$abc$2135$lut$not$aiger2134$1} {$auto$alumacc.cc:485:replace_alu$1469.slice[0].carry4_1st_full} {$auto$alumacc.cc:485:replace_alu$1469.slice[0].plug} {$auto$alumacc.cc:485:replace_alu$1469.slice[1].carry4_full} {$auto$alumacc.cc:485:replace_alu$1469.slice[1].plug} {$auto$alumacc.cc:485:replace_alu$1469.slice[2].carry4_full} {$auto$alumacc.cc:485:replace_alu$1469.slice[2].plug} {$auto$alumacc.cc:485:replace_alu$1469.slice[3].carry4_full} {$auto$alumacc.cc:485:replace_alu$1469.slice[3].plug} {$auto$alumacc.cc:485:replace_alu$1469.slice[4].carry4_full} {$auto$alumacc.cc:485:replace_alu$1469.slice[4].plug} {$auto$alumacc.cc:485:replace_alu$1469.slice[5].carry4_full} {$auto$alumacc.cc:485:replace_alu$1469.slice[5].plug} {$auto$alumacc.cc:485:replace_alu$1469.slice[6].carry4_part} {$auto$simplemap.cc:420:simplemap_dff$1476} {$auto$simplemap.cc:420:simplemap_dff$1477} {$auto$simplemap.cc:420:simplemap_dff$1478} {$auto$simplemap.cc:420:simplemap_dff$1479} {$auto$simplemap.cc:420:simplemap_dff$1480} {$auto$simplemap.cc:420:simplemap_dff$1481} {$auto$simplemap.cc:420:simplemap_dff$1482} {$auto$simplemap.cc:420:simplemap_dff$1483} {$auto$simplemap.cc:420:simplemap_dff$1484} {$auto$simplemap.cc:420:simplemap_dff$1485} {$auto$simplemap.cc:420:simplemap_dff$1486} {$auto$simplemap.cc:420:simplemap_dff$1487} {$auto$simplemap.cc:420:simplemap_dff$1488} {$auto$simplemap.cc:420:simplemap_dff$1489} {$auto$simplemap.cc:420:simplemap_dff$1490} {$auto$simplemap.cc:420:simplemap_dff$1491} {$auto$simplemap.cc:420:simplemap_dff$1492} {$auto$simplemap.cc:420:simplemap_dff$1493} {$auto$simplemap.cc:420:simplemap_dff$1494} {$auto$simplemap.cc:420:simplemap_dff$1495} {$auto$simplemap.cc:420:simplemap_dff$1496} {$auto$simplemap.cc:420:simplemap_dff$1497} {$auto$simplemap.cc:420:simplemap_dff$1498} {$auto$simplemap.cc:420:simplemap_dff$1499} {$auto$simplemap.cc:420:simplemap_dff$1500} {$auto$simplemap.cc:420:simplemap_dff$1501} {$iopadmap$top.clk} OBUFTDS_2 OBUF_6 OBUF_7 OBUF_OUT bottom_inst.OBUF_10 bottom_inst.OBUF_11 bottom_inst.OBUF_9 bottom_intermediate_inst.OBUF_8
diff --git a/design_introspection-plugin/tests/get_cells/get_cells.tcl b/design_introspection-plugin/tests/get_cells/get_cells.tcl
new file mode 100644
index 0000000..861e6a9
--- /dev/null
+++ b/design_introspection-plugin/tests/get_cells/get_cells.tcl
@@ -0,0 +1,33 @@
+yosys -import
+plugin -i design_introspection
+#Import the commands from the plugins to the tcl interpreter
+yosys -import
+
+read_verilog get_cells.v
+# Some of symbiflow expects eblifs with only one module.
+synth_xilinx -vpr -flatten -abc9 -nosrl -noclkbuf -nodsp
+
+
+set fp [open "get_cells.txt" "w"]
+
+puts "\n*inter* cells quiet"
+puts $fp "\n*inter* cells quiet"
+puts $fp [get_cells -quiet *inter*]
+
+puts "\n*inter* cells"
+puts $fp "\n*inter* cells"
+puts $fp [get_cells *inter*]
+
+puts "\n*inter* cells with invalid filter expression"
+puts $fp "\n*inter* cells with invalid filter expression"
+puts $fp [get_cells -filter {mr_ff != true} *inter* ]
+
+puts "\nFiltered cells"
+puts $fp "\nFiltered cells"
+puts $fp [get_cells -filter {mr_ff == true || async_reg == true && dont_touch == true} ]
+
+puts "\nAll cells"
+puts $fp "\nAll cells"
+puts $fp [get_cells]
+
+close $fp
diff --git a/design_introspection-plugin/tests/get_cells/get_cells.v b/design_introspection-plugin/tests/get_cells/get_cells.v
new file mode 100644
index 0000000..e2af7fc
--- /dev/null
+++ b/design_introspection-plugin/tests/get_cells/get_cells.v
@@ -0,0 +1,77 @@
+module top (
+	(* async_reg = "true", mr_ff = "true", dont_touch = "true" *) input  clk,
+	output [3:0] led,
+	inout out_a,
+	output [1:0] out_b,
+	output signal_p,
+	output signal_n
+);
+
+	wire LD6, LD7, LD8, LD9;
+	wire inter_wire, inter_wire_2;
+	localparam BITS = 1;
+	localparam LOG2DELAY = 25;
+
+	reg [BITS+LOG2DELAY-1:0] counter = 0;
+
+	always @(posedge clk) begin
+		counter <= counter + 1;
+	end
+	assign led[1] = inter_wire;
+	assign inter_wire = inter_wire_2;
+	assign {LD9, LD8, LD7, LD6} = counter >> LOG2DELAY;
+	(* async_reg = "true", mr_ff = "true", dont_touch = "true" *)
+	OBUFTDS OBUFTDS_2(
+		.I(LD6),
+		.O(signal_p),
+		.OB(signal_n),
+		.T(1'b1)
+	);
+	(* async_reg = "false", mr_ff = "false", dont_touch = "true" *)
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_6(.I(LD6), .O(led[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_7(.I(LD7), .O(inter_wire_2));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_OUT(.I(LD7), .O(out_a));
+	bottom bottom_inst(.I(LD8), .O(led[2]), .OB(out_b));
+	bottom_intermediate bottom_intermediate_inst(.I(LD9), .O(led[3]));
+endmodule
+
+module bottom_intermediate (
+	input I,
+	output O
+);
+	wire bottom_intermediate_wire;
+	assign O = bottom_intermediate_wire;
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_8(.I(I), .O(bottom_intermediate_wire));
+endmodule
+
+module bottom (
+	input I,
+	output [1:0] OB,
+	output O
+);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_9(.I(I), .O(O));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_10(.I(I), .O(OB[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_11(.I(I), .O(OB[1]));
+endmodule
+
diff --git a/design_introspection-plugin/tests/get_nets/get_nets.golden.txt b/design_introspection-plugin/tests/get_nets/get_nets.golden.txt
new file mode 100644
index 0000000..24c2e2f
--- /dev/null
+++ b/design_introspection-plugin/tests/get_nets/get_nets.golden.txt
@@ -0,0 +1,10 @@
+*inter* nets quiet
+bottom_intermediate_inst.I bottom_intermediate_inst.O bottom_intermediate_inst.bottom_intermediate_wire inter_wire inter_wire_2
+*inter* nets
+bottom_intermediate_inst.I bottom_intermediate_inst.O bottom_intermediate_inst.bottom_intermediate_wire inter_wire inter_wire_2
+*inter* nets with invalid filter expression
+bottom_intermediate_inst.I bottom_intermediate_inst.O bottom_intermediate_inst.bottom_intermediate_wire inter_wire inter_wire_2
+Filtered nets
+clk
+All nets
+{$abc$2135$aiger2134$38} {$abc$2135$aiger2134$42} {$abc$2135$aiger2134$43} {$abc$2135$aiger2134$48} {$abc$2135$aiger2134$49} {$abc$2135$aiger2134$54} {$abc$2135$aiger2134$55} {$abc$2135$aiger2134$60} {$abc$2135$aiger2134$61} {$abc$2135$aiger2134$66} {$abc$2135$aiger2134$67} {$abc$2135$aiger2134$72} {$abc$2135$aiger2134$73} {$abc$2135$aiger2134$76} {$abc$2135$aiger2134$77} {$abc$2135$aiger2134$78} {$abc$2135$iopadmap$clk} {$auto$alumacc.cc:485:replace_alu$1469.O} LD6 LD7 LD8 LD9 bottom_inst.I bottom_inst.O bottom_inst.OB bottom_intermediate_inst.I bottom_intermediate_inst.O bottom_intermediate_inst.bottom_intermediate_wire clk counter inter_wire inter_wire_2 led out_a out_b signal_n signal_p
diff --git a/design_introspection-plugin/tests/get_nets/get_nets.tcl b/design_introspection-plugin/tests/get_nets/get_nets.tcl
new file mode 100644
index 0000000..c4fe329
--- /dev/null
+++ b/design_introspection-plugin/tests/get_nets/get_nets.tcl
@@ -0,0 +1,33 @@
+yosys -import
+plugin -i design_introspection
+#Import the commands from the plugins to the tcl interpreter
+yosys -import
+
+read_verilog get_nets.v
+# Some of symbiflow expects eblifs with only one module.
+synth_xilinx -vpr -flatten -abc9 -nosrl -noclkbuf -nodsp
+
+
+set fp [open "get_nets.txt" "w"]
+
+puts "\n*inter* nets quiet"
+puts $fp "*inter* nets quiet"
+puts $fp [get_nets -quiet *inter*]
+
+puts "\n*inter* nets"
+puts $fp "*inter* nets"
+puts $fp [get_nets *inter*]
+
+puts "\n*inter* nets with invalid filter expression"
+puts $fp "*inter* nets with invalid filter expression"
+puts $fp [get_nets -filter {mr_ff != true} *inter* ]
+
+puts "\nFiltered nets"
+puts $fp "Filtered nets"
+puts $fp [get_nets -filter {mr_ff == true || async_reg == true && dont_touch == true} ]
+
+puts "\nAll nets"
+puts $fp "All nets"
+puts $fp [get_nets]
+
+close $fp
diff --git a/design_introspection-plugin/tests/get_nets/get_nets.v b/design_introspection-plugin/tests/get_nets/get_nets.v
new file mode 100644
index 0000000..d40055b
--- /dev/null
+++ b/design_introspection-plugin/tests/get_nets/get_nets.v
@@ -0,0 +1,75 @@
+module top (
+	(* async_reg = "true", mr_ff = "true", dont_touch = "true" *) input  clk,
+	output [3:0] led,
+	inout out_a,
+	output [1:0] out_b,
+	output signal_p,
+	output signal_n
+);
+
+	wire LD6, LD7, LD8, LD9;
+	wire inter_wire, inter_wire_2;
+	localparam BITS = 1;
+	localparam LOG2DELAY = 25;
+
+	reg [BITS+LOG2DELAY-1:0] counter = 0;
+
+	always @(posedge clk) begin
+		counter <= counter + 1;
+	end
+	assign led[1] = inter_wire;
+	assign inter_wire = inter_wire_2;
+	assign {LD9, LD8, LD7, LD6} = counter >> LOG2DELAY;
+	OBUFTDS OBUFTDS_2(
+		.I(LD6),
+		.O(signal_p),
+		.OB(signal_n),
+		.T(1'b1)
+	);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_6(.I(LD6), .O(led[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_7(.I(LD7), .O(inter_wire_2));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_OUT(.I(LD7), .O(out_a));
+	bottom bottom_inst(.I(LD8), .O(led[2]), .OB(out_b));
+	bottom_intermediate bottom_intermediate_inst(.I(LD9), .O(led[3]));
+endmodule
+
+module bottom_intermediate (
+	input I,
+	output O
+);
+	wire bottom_intermediate_wire;
+	assign O = bottom_intermediate_wire;
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_8(.I(I), .O(bottom_intermediate_wire));
+endmodule
+
+module bottom (
+	input I,
+	output [1:0] OB,
+	output O
+);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_9(.I(I), .O(O));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_10(.I(I), .O(OB[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_11(.I(I), .O(OB[1]));
+endmodule
+
diff --git a/design_introspection-plugin/tests/get_pins/get_pins.golden.txt b/design_introspection-plugin/tests/get_pins/get_pins.golden.txt
new file mode 100644
index 0000000..b92d21a
--- /dev/null
+++ b/design_introspection-plugin/tests/get_pins/get_pins.golden.txt
@@ -0,0 +1,12 @@
+
+*inter* pins quiet
+OBUF_6/I
+
+*inter* pins
+OBUF_6/I
+
+*inter* pins with invalid filter expression
+bottom_intermediate_inst.OBUF_8/I
+
+Filtered pins
+OBUF_7/I OBUF_OUT/I
diff --git a/design_introspection-plugin/tests/get_pins/get_pins.tcl b/design_introspection-plugin/tests/get_pins/get_pins.tcl
new file mode 100644
index 0000000..144d453
--- /dev/null
+++ b/design_introspection-plugin/tests/get_pins/get_pins.tcl
@@ -0,0 +1,29 @@
+yosys -import
+plugin -i design_introspection
+#Import the commands from the plugins to the tcl interpreter
+yosys -import
+
+read_verilog get_pins.v
+# Some of symbiflow expects eblifs with only one module.
+synth_xilinx -vpr -flatten -abc9 -nosrl -noclkbuf -nodsp
+
+
+set fp [open "get_pins.txt" "w"]
+
+puts "\n*inter* pins quiet"
+puts $fp "\n*inter* pins quiet"
+puts $fp [get_pins -quiet OBUF_6/I]
+
+puts "\n*inter* pins"
+puts $fp "\n*inter* pins"
+puts $fp [get_pins OBUF_6/I]
+
+puts "\n*inter* pins with invalid filter expression"
+puts $fp "\n*inter* pins with invalid filter expression"
+puts $fp [get_pins -filter {mr_ff != true} *inter*/I ]
+
+puts "\nFiltered pins"
+puts $fp "\nFiltered pins"
+puts $fp [get_pins -filter {dont_touch == true || async_reg == true && mr_ff == true} *OBUF*/I ]
+
+close $fp
diff --git a/design_introspection-plugin/tests/get_pins/get_pins.v b/design_introspection-plugin/tests/get_pins/get_pins.v
new file mode 100644
index 0000000..bf08129
--- /dev/null
+++ b/design_introspection-plugin/tests/get_pins/get_pins.v
@@ -0,0 +1,76 @@
+module top (
+	(* async_reg = "true", mr_ff = "true", dont_touch = "true" *) input  clk,
+	output [3:0] led,
+	inout out_a,
+	output [1:0] out_b,
+	output signal_p,
+	output signal_n
+);
+
+	wire LD6, LD7, LD8, LD9;
+	wire inter_wire, inter_wire_2;
+	localparam BITS = 1;
+	localparam LOG2DELAY = 25;
+
+	reg [BITS+LOG2DELAY-1:0] counter = 0;
+
+	always @(posedge clk) begin
+		counter <= counter + 1;
+	end
+	assign led[1] = inter_wire;
+	assign inter_wire = inter_wire_2;
+	assign {LD9, LD8, LD7, LD6} = counter >> LOG2DELAY;
+	OBUFTDS OBUFTDS_2(
+		.I(LD6),
+		.O(signal_p),
+		.OB(signal_n),
+		.T(1'b1)
+	);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_6((* test_attr = "true" *) .I(LD6), .O(led[0]));
+	(* dont_touch = "true" *) OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_7(.I(LD7), .O(inter_wire_2));
+	(* dont_touch = "true" *) OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_OUT(.I(LD7), .O(out_a));
+	bottom bottom_inst(.I(LD8), .O(led[2]), .OB(out_b));
+	bottom_intermediate bottom_intermediate_inst(.I(LD9), .O(led[3]));
+endmodule
+
+(* async_reg = "true", mr_ff = "false", dont_touch = "true" *)
+module bottom_intermediate (
+	input I,
+	output O
+);
+	wire bottom_intermediate_wire;
+	assign O = bottom_intermediate_wire;
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_8(.I(I), .O(bottom_intermediate_wire));
+endmodule
+
+module bottom (
+	input I,
+	output [1:0] OB,
+	output O
+);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_9(.I(I), .O(O));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_10(.I(I), .O(OB[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_11(.I(I), .O(OB[1]));
+endmodule
+
diff --git a/design_introspection-plugin/tests/get_ports/get_ports.golden.txt b/design_introspection-plugin/tests/get_ports/get_ports.golden.txt
new file mode 100644
index 0000000..d87ba55
--- /dev/null
+++ b/design_introspection-plugin/tests/get_ports/get_ports.golden.txt
@@ -0,0 +1,6 @@
+signal_p port
+signal_p
+clk port
+clk
+led[0] port
+led[0]
diff --git a/design_introspection-plugin/tests/get_ports/get_ports.tcl b/design_introspection-plugin/tests/get_ports/get_ports.tcl
new file mode 100644
index 0000000..1ac5903
--- /dev/null
+++ b/design_introspection-plugin/tests/get_ports/get_ports.tcl
@@ -0,0 +1,45 @@
+yosys -import
+plugin -i design_introspection
+#Import the commands from the plugins to the tcl interpreter
+yosys -import
+
+read_verilog get_ports.v
+# Some of symbiflow expects eblifs with only one module.
+synth_xilinx -vpr -flatten -abc9 -nosrl -noclkbuf -nodsp
+help get_ports
+
+set fp [open "get_ports.txt" "w"]
+
+puts "\nsignal_p port"
+puts $fp "signal_p port"
+puts $fp [get_ports signal_p]
+
+puts "\nclk port"
+puts $fp "clk port"
+puts $fp [get_ports clk]
+
+puts {\nled[0] port}
+puts $fp {led[0] port}
+puts $fp [get_ports {led[0]}]
+
+#puts "\nsignal_* ports quiet"
+#puts $fp "signal_* ports quiet"
+#puts $fp [get_ports -quiet signal_*]
+#
+#puts "\nsignal_* ports"
+#puts $fp "signal_* ports"
+#puts $fp [get_ports signal_*]
+#
+#puts "\nled ports with filter expression"
+#puts $fp "led ports with filter expression"
+#puts $fp [get_ports -filter {mr_ff != true} led]
+#
+#puts "\nFiltered ports"
+#puts $fp "Filtered ports"
+#puts $fp [get_ports -filter {mr_ff == true || async_reg == true && dont_touch == true} ]
+#
+#puts "\nAll ports"
+#puts $fp "All ports"
+#puts $fp [get_ports]
+
+close $fp
diff --git a/design_introspection-plugin/tests/get_ports/get_ports.v b/design_introspection-plugin/tests/get_ports/get_ports.v
new file mode 100644
index 0000000..d40055b
--- /dev/null
+++ b/design_introspection-plugin/tests/get_ports/get_ports.v
@@ -0,0 +1,75 @@
+module top (
+	(* async_reg = "true", mr_ff = "true", dont_touch = "true" *) input  clk,
+	output [3:0] led,
+	inout out_a,
+	output [1:0] out_b,
+	output signal_p,
+	output signal_n
+);
+
+	wire LD6, LD7, LD8, LD9;
+	wire inter_wire, inter_wire_2;
+	localparam BITS = 1;
+	localparam LOG2DELAY = 25;
+
+	reg [BITS+LOG2DELAY-1:0] counter = 0;
+
+	always @(posedge clk) begin
+		counter <= counter + 1;
+	end
+	assign led[1] = inter_wire;
+	assign inter_wire = inter_wire_2;
+	assign {LD9, LD8, LD7, LD6} = counter >> LOG2DELAY;
+	OBUFTDS OBUFTDS_2(
+		.I(LD6),
+		.O(signal_p),
+		.OB(signal_n),
+		.T(1'b1)
+	);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_6(.I(LD6), .O(led[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_7(.I(LD7), .O(inter_wire_2));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_OUT(.I(LD7), .O(out_a));
+	bottom bottom_inst(.I(LD8), .O(led[2]), .OB(out_b));
+	bottom_intermediate bottom_intermediate_inst(.I(LD9), .O(led[3]));
+endmodule
+
+module bottom_intermediate (
+	input I,
+	output O
+);
+	wire bottom_intermediate_wire;
+	assign O = bottom_intermediate_wire;
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_8(.I(I), .O(bottom_intermediate_wire));
+endmodule
+
+module bottom (
+	input I,
+	output [1:0] OB,
+	output O
+);
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_9(.I(I), .O(O));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_10(.I(I), .O(OB[0]));
+	OBUF #(
+		.IOSTANDARD("LVCMOS33"),
+		.SLEW("SLOW")
+	) OBUF_11(.I(I), .O(OB[1]));
+endmodule
+
diff --git a/xdc-plugin/tests/counter/counter.tcl b/xdc-plugin/tests/counter/counter.tcl
index b7090c8..be26dde 100644
--- a/xdc-plugin/tests/counter/counter.tcl
+++ b/xdc-plugin/tests/counter/counter.tcl
@@ -1,4 +1,5 @@
 yosys -import
+plugin -i design_introspection
 plugin -i xdc
 #Import the commands from the plugins to the tcl interpreter
 yosys -import
diff --git a/xdc-plugin/tests/io_loc_pairs/io_loc_pairs.tcl b/xdc-plugin/tests/io_loc_pairs/io_loc_pairs.tcl
index b7090c8..be26dde 100644
--- a/xdc-plugin/tests/io_loc_pairs/io_loc_pairs.tcl
+++ b/xdc-plugin/tests/io_loc_pairs/io_loc_pairs.tcl
@@ -1,4 +1,5 @@
 yosys -import
+plugin -i design_introspection
 plugin -i xdc
 #Import the commands from the plugins to the tcl interpreter
 yosys -import
diff --git a/xdc-plugin/tests/minilitex_ddr_arty/minilitex_ddr_arty.tcl b/xdc-plugin/tests/minilitex_ddr_arty/minilitex_ddr_arty.tcl
index af91ce6..34d7947 100644
--- a/xdc-plugin/tests/minilitex_ddr_arty/minilitex_ddr_arty.tcl
+++ b/xdc-plugin/tests/minilitex_ddr_arty/minilitex_ddr_arty.tcl
@@ -1,4 +1,5 @@
 yosys -import
+plugin -i design_introspection
 plugin -i xdc
 #Import the commands from the plugins to the tcl interpreter
 yosys -import
diff --git a/xdc-plugin/tests/package_pins/package_pins.tcl b/xdc-plugin/tests/package_pins/package_pins.tcl
index 66bd21d..2df419a 100644
--- a/xdc-plugin/tests/package_pins/package_pins.tcl
+++ b/xdc-plugin/tests/package_pins/package_pins.tcl
@@ -1,4 +1,5 @@
 yosys -import
+plugin -i design_introspection
 plugin -i xdc
 #Import the commands from the plugins to the tcl interpreter
 yosys -import
diff --git a/xdc-plugin/tests/port_indexes/port_indexes.tcl b/xdc-plugin/tests/port_indexes/port_indexes.tcl
index ed35c69..283cce5 100644
--- a/xdc-plugin/tests/port_indexes/port_indexes.tcl
+++ b/xdc-plugin/tests/port_indexes/port_indexes.tcl
@@ -1,4 +1,5 @@
 yosys -import
+plugin -i design_introspection
 plugin -i xdc
 #Import the commands from the plugins to the tcl interpreter
 yosys -import
diff --git a/xdc-plugin/xdc.cc b/xdc-plugin/xdc.cc
index 9a8e5e7..a27bdf7 100644
--- a/xdc-plugin/xdc.cc
+++ b/xdc-plugin/xdc.cc
@@ -61,7 +61,8 @@
 	{"OBUFDS", {"IO_LOC_PAIRS", "IOSTANDARD", "SLEW", "IN_TERM"}},
 	{"OBUFTDS", {"IO_LOC_PAIRS", "IOSTANDARD", "SLEW", "IN_TERM"}},
 	{"IBUF", {"IO_LOC_PAIRS", "IOSTANDARD"}},
-	{"IOBUF", {"IO_LOC_PAIRS", "IOSTANDARD", "DRIVE", "SLEW", "IN_TERM"}}
+	{"IOBUF", {"IO_LOC_PAIRS", "IOSTANDARD", "DRIVE", "SLEW", "IN_TERM"}},
+	{"IOBUFDS", {"IO_LOC_PAIRS", "IOSTANDARD", "SLEW", "IN_TERM"}}
 };
 
 void register_in_tcl_interpreter(const std::string& command) {
@@ -70,57 +71,6 @@
 	Tcl_Eval(interp, tcl_script.c_str());
 }
 
-struct GetPorts : public Pass {
-	GetPorts() : Pass("get_ports", "Print matching ports") {
-		register_in_tcl_interpreter(pass_name);
-	}
-
-	void help() override
-	{
-		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-		log("\n");
-		log("   get_ports <port_name> \n");
-		log("\n");
-		log("Get matching ports\n");
-		log("\n");
-		log("Print the output to stdout too. This is useful when all Yosys is executed\n");
-		log("\n");
-	}
-
-	void execute(std::vector<std::string> args, RTLIL::Design* design) override
-	{
-		if (args.size() < 2) {
-			log_cmd_error("No port specified.\n");
-		}
-		RTLIL::Module* top_module = design->top_module();
-		if (top_module == nullptr) {
-			log_cmd_error("No top module detected\n");
-		}
-		// TODO handle more than one port
-		port_name = args.at(1);
-		std::string port_str(port_name.size(), '\0');
-		int bit(0);
-		if (!sscanf(port_name.c_str(), "%[^[][%d]", &port_str[0], &bit)) {
-			log_error("Couldn't find port %s\n", port_name.c_str());
-		}
-
-		port_str.resize(strlen(port_str.c_str()));
-		RTLIL::IdString port_id(RTLIL::escape_id(port_str));
-		if (auto wire = top_module->wire(port_id)) {
-			if (isInputPort(wire) || isOutputPort(wire)) {
-				if (bit >= wire->start_offset && bit < wire->start_offset + wire->width) {
-					Tcl_Interp *interp = yosys_get_tcl_interp();
-					Tcl_SetResult(interp, const_cast<char*>(port_name.c_str()), NULL);
-					log("Found port %s\n", port_name.c_str());
-					return;
-				}
-			}
-		}
-		log_error("Couldn't find port %s\n", port_name.c_str());
-	}
-	std::string port_name;
-};
-
 struct GetIOBanks : public Pass {
 	GetIOBanks(std::function<const BankTilesMap&()> get_bank_tiles)
 		: Pass("get_iobanks", "Set IO Bank number")
@@ -434,7 +384,6 @@
 	}
 
 	BankTilesMap bank_tiles;
-	struct GetPorts GetPorts;
 	struct GetIOBanks GetIOBanks;
 	struct SetProperty SetProperty;
 } ReadXdc;