Introspection: Add get_pins command

Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/design_introspection-plugin/Makefile b/design_introspection-plugin/Makefile
index 181effb..296f5cd 100644
--- a/design_introspection-plugin/Makefile
+++ b/design_introspection-plugin/Makefile
@@ -5,7 +5,7 @@
 PLUGINS_DIR = $(shell yosys-config --datdir)/plugins
 
 NAME = design_introspection
-OBJS = $(NAME).o get_cmd.o get_nets.o get_ports.o get_cells.o
+OBJS = $(NAME).o get_cmd.o get_nets.o get_ports.o get_cells.o get_pins.o
 
 $(NAME).so: $(OBJS)
 	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS)
diff --git a/design_introspection-plugin/design_introspection.cc b/design_introspection-plugin/design_introspection.cc
index c14ca80..5982a99 100644
--- a/design_introspection-plugin/design_introspection.cc
+++ b/design_introspection-plugin/design_introspection.cc
@@ -21,6 +21,7 @@
 #include "get_nets.h"
 #include "get_ports.h"
 #include "get_cells.h"
+#include "get_pins.h"
 
 USING_YOSYS_NAMESPACE
 
@@ -31,6 +32,7 @@
     GetNets get_nets_cmd;
     GetPorts get_ports_cmd;
     GetCells get_cells_cmd;
+    GetPins get_pins_cmd;
 } DesignIntrospection;
 
 
diff --git a/design_introspection-plugin/get_pins.cc b/design_introspection-plugin/get_pins.cc
new file mode 100644
index 0000000..ef6e887
--- /dev/null
+++ b/design_introspection-plugin/get_pins.cc
@@ -0,0 +1,63 @@
+#include "get_pins.h"
+
+USING_YOSYS_NAMESPACE
+
+std::string GetPins::TypeName() { return "pin"; }
+
+std::string GetPins::SelectionType() { return "c"; }
+
+void GetPins::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));
+    Tcl_Obj* tcl_list = Tcl_NewListObj(0, NULL);
+    for (auto obj : parsed_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(tcl_list, design, port, parsed_args);
+    }
+    if (!parsed_args.is_quiet) {
+	log("\n");
+    }
+    Tcl_SetObjResult(yosys_get_tcl_interp(), tcl_list);
+}
+
+void GetPins::ExtractSingleSelection(Tcl_Obj* tcl_list, 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);
+	    if (!args.is_quiet) {
+		log("%s ", pin_name.c_str());
+	    }
+	    Tcl_Obj* value_obj = Tcl_NewStringObj(pin_name.c_str(), -1);
+	    Tcl_ListObjAppendElement(yosys_get_tcl_interp(), tcl_list,
+	                             value_obj);
+	}
+    }
+}
+
diff --git a/design_introspection-plugin/get_pins.h b/design_introspection-plugin/get_pins.h
new file mode 100644
index 0000000..0a7e90e
--- /dev/null
+++ b/design_introspection-plugin/get_pins.h
@@ -0,0 +1,21 @@
+#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") {}
+
+    std::string TypeName() override;
+    std::string SelectionType() override;
+    void execute(std::vector<std::string> args, RTLIL::Design* design) override;
+
+   private:
+    void ExtractSingleSelection(Tcl_Obj* tcl_list, RTLIL::Design* design,
+                                const std::string& port_name,
+                                const CommandArgs& args);
+};
+
+#endif  // GET_PINS_H_