An object counting plugin Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
diff --git a/Makefile b/Makefile index 0427c0d..6e74158 100644 --- a/Makefile +++ b/Makefile
@@ -1,4 +1,4 @@ -PLUGIN_LIST := fasm xdc params selection sdc +PLUGIN_LIST := fasm xdc params selection sdc get_count 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/get_count-plugin/Makefile b/get_count-plugin/Makefile new file mode 100644 index 0000000..cc0119d --- /dev/null +++ b/get_count-plugin/Makefile
@@ -0,0 +1,24 @@ +CXX = $(shell yosys-config --cxx) +CXXFLAGS = $(shell yosys-config --cxxflags) +LDFLAGS = $(shell yosys-config --ldflags) +LDLIBS = $(shell yosys-config --ldlibs) +PLUGINS_DIR = $(shell yosys-config --datdir)/plugins + +NAME = get_count +OBJS = $(NAME).o + +$(NAME).so: $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) + +.PHONY: install test + +install: test + mkdir -p $(PLUGINS_DIR) + cp $(NAME).so $(PLUGINS_DIR)/$(NAME).so + +test: $(NAME).so + $(MAKE) -C tests all + +clean: + rm -f *.d *.o *.so + $(MAKE) -C tests clean
diff --git a/get_count-plugin/get_count.cc b/get_count-plugin/get_count.cc new file mode 100644 index 0000000..8a4a0ee --- /dev/null +++ b/get_count-plugin/get_count.cc
@@ -0,0 +1,133 @@ +/* + * 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 "kernel/register.h" +#include "kernel/rtlil.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void register_in_tcl_interpreter(const std::string& command) { + Tcl_Interp* interp = yosys_get_tcl_interp(); + std::string tcl_script = stringf("proc %s args { return [yosys %s {*}$args] }", command.c_str(), command.c_str()); + Tcl_Eval(interp, tcl_script.c_str()); +} + +struct GetCount : public Pass { + + enum class ObjectType { + NONE, + MODULE, + CELL, + WIRE + }; + + GetCount () : + Pass("get_count", "Returns count of various selected object types to the TCL interpreter") { + register_in_tcl_interpreter(pass_name); + } + + void help() YS_OVERRIDE { + log("\n"); + log(" get_count <options> [selection]"); + log("\n"); + log("When used from inside the TCL interpreter returns count of selected objects.\n"); + log("The object type to count may be given as an argument. Only one at a time.\n"); + log("If none is given then the total count of all selected objects is returned.\n"); + log("\n"); + log(" -modules\n"); + log(" Returns the count of modules in selection\n"); + log("\n"); + log(" -cells\n"); + log(" Returns the count of cells in selection\n"); + log("\n"); + log(" -wires\n"); + log(" Returns the count of wires in selection\n"); + log("\n"); + } + + void execute(std::vector<std::string> a_Args, RTLIL::Design* a_Design) YS_OVERRIDE { + + // Parse args + ObjectType type = ObjectType::NONE; + if (a_Args.size() < 2) { + log_error("Invalid argument!\n"); + } + + if (a_Args[1] == "-modules") { + type = ObjectType::MODULE; + } + else if (a_Args[1] == "-cells") { + type = ObjectType::CELL; + } + else if (a_Args[1] == "-wires") { + type = ObjectType::WIRE; + } + else if (a_Args[1][0] == '-') { + log_error("Invalid argument '%s'!\n", a_Args[1].c_str()); + } + else { + log_error("Object type not specified!\n"); + } + + extra_args(a_Args, 2, a_Design); + + // Get the TCL interpreter + Tcl_Interp* tclInterp = yosys_get_tcl_interp(); + Tcl_Obj* tclList = Tcl_NewListObj(0, NULL); + + // Count objects + size_t moduleCount = 0; + size_t cellCount = 0; + size_t wireCount = 0; + + moduleCount += a_Design->selected_modules().size(); + for (auto module : a_Design->selected_modules()) { + cellCount += module->selected_cells().size(); + wireCount += module->selected_wires().size(); + } + + size_t count = 0; + switch (type) + { + case ObjectType::MODULE: + count = moduleCount; + break; + case ObjectType::CELL: + count = cellCount; + break; + case ObjectType::WIRE: + count = wireCount; + break; + default: + log_assert(false); + } + + // Return the value as string to the TCL interpreter + std::string value = std::to_string(count); + + Tcl_Obj* tclStr = Tcl_NewStringObj(value.c_str(), value.size()); + Tcl_ListObjAppendElement(tclInterp, tclList, tclStr); + Tcl_SetObjResult(tclInterp, tclList); + } + +} GetCount; + +PRIVATE_NAMESPACE_END
diff --git a/get_count-plugin/tests/Makefile b/get_count-plugin/tests/Makefile new file mode 100644 index 0000000..487e07e --- /dev/null +++ b/get_count-plugin/tests/Makefile
@@ -0,0 +1,15 @@ +TESTS = $(subst /, ,$(wildcard */)) + +all: $(addsuffix /ok,$(TESTS)) + +clean: + @find . -name "ok" | xargs rm -rf + +define maketest = +$1/ok: + cd $1 && $(MAKE) test +endef + +$(foreach _,${TESTS},$(eval $(call maketest,$_))) + +.PHONY: all clean
diff --git a/get_count-plugin/tests/simple/Makefile b/get_count-plugin/tests/simple/Makefile new file mode 100644 index 0000000..1632151 --- /dev/null +++ b/get_count-plugin/tests/simple/Makefile
@@ -0,0 +1,8 @@ +test: + yosys -p "tcl script.tcl" + touch ok + +clean: + rm -rf ok + +.PHONY: test clean
diff --git a/get_count-plugin/tests/simple/design.v b/get_count-plugin/tests/simple/design.v new file mode 100644 index 0000000..935a0c1 --- /dev/null +++ b/get_count-plugin/tests/simple/design.v
@@ -0,0 +1,23 @@ +module my_gate ( + input wire A, + output wire Y +); + + assign Y = ~A; +endmodule + +module top ( + input wire [7:0] di, + output wire [7:0] do +); + + my_gate c0 (.A(di[0]), .Y(do[0])); + \$_BUF_ c1 (.A(di[1]), .Y(do[1])); + \$_BUF_ c2 (.A(di[2]), .Y(do[2])); + \$_BUF_ c3 (.A(di[3]), .Y(do[3])); + \$_BUF_ c4 (.A(di[4]), .Y(do[4])); + \$_NOT_ c5 (.A(di[5]), .Y(do[5])); + \$_NOT_ c6 (.A(di[6]), .Y(do[6])); + \$_NOT_ c7 (.A(di[7]), .Y(do[7])); + +endmodule
diff --git a/get_count-plugin/tests/simple/script.tcl b/get_count-plugin/tests/simple/script.tcl new file mode 100644 index 0000000..6e8cdf0 --- /dev/null +++ b/get_count-plugin/tests/simple/script.tcl
@@ -0,0 +1,30 @@ +yosys plugin -i ../../get_count.so +yosys -import + +read_verilog -icells design.v +hierarchy -auto-top + +set n [get_count -modules my_gate] +puts "Module count: $n" +if {$n != "1"} { + error "Invalid count" +} + +set n [get_count -cells t:\$_BUF_] +puts "BUF count: $n" +if {$n != "4"} { + error "Invalid count" +} + +set n [get_count -cells t:\$_NOT_] +puts "NOT count: $n" +if {$n != "3"} { + error "Invalid count" +} + +set n [get_count -wires w:*] +puts "Wire count: $n" +if {$n != "5"} { + error "Invalid count" +} +