This is a small post about one of the cool Yosys features: plugins. Basically, we can implement commands to be called from Yosys scripts. The plugins use the RTLIL APIs to iterate, process, modify or add elements.

Calling: yosys.ys Link to heading

Starting with the Yosys script, this is an example of the count_cells command called after proc and opt.

read_verilog example.v

hierarchy -top top

proc
opt

count_cells

Building: Makefile Link to heading

To build the command, we will use yosys-config to get the options needed to build the shared object with the plugin.

CXX = $(shell yosys-config --cxx)
CXXFLAGS = $(shell yosys-config --cxxflags)
LDFLAGS = $(shell yosys-config --ldflags)
LDLIBS = $(shell yosys-config --ldlibs)

count_cells.so: count_cells.cc
	$(CXX) $(CXXFLAGS) -shared -o $@ $< $(LDFLAGS) $(LDLIBS)

clean:
	rm -fr count_cells.so count_cells.d count_cells.so.dSYM

test: count_cells.so
	yosys -m ./count_cells.so test.ys

Plugin: C++ Link to heading

count_cells is really simple. It just iterates over modules and counts cells. It extends the Pass class from the Yosys API. It gets the list of modules and loops over them to get the cells in each module.

#include "kernel/yosys.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct CountCellsPass : public Pass {
    CountCellsPass() : Pass("count_cells", "count cells in design") { }
    
    void help() override
    {
        log("\n");
        log("    count_cells [selection]\n");
        log("\n");
        log("This pass counts the number of cells in the current design.\n");
        log("\n");
    }
    
    void execute(std::vector<std::string> args, RTLIL::Design *design) override
    {
        log_header(design, "Executing COUNT_CELLS pass.\n");
        
        // Process arguments
        size_t argidx;
        for (argidx = 1; argidx < args.size(); argidx++) {
            break;
        }
        extra_args(args, argidx, design);
        
        // Iterate through all modules in the design
        std::map<RTLIL::IdString, int> cell_types;
        
        for (auto module : design->selected_modules()) {
            log("Module: %s\n", log_id(module->name));
            
            int module_cells = 0;
            
            // Iterate through all cells in the module
            for (auto cell : module->selected_cells()) {
                cell_types[cell->type]++;
                module_cells++;
            }
            
            log("  Cells in module: %d\n", module_cells);
        }
        
        log("\n");
        log("Cell type statistics:\n");
        log("---------------------\n");
        
        for (auto &it : cell_types) {
            log("  %-30s : %5d\n", log_id(it.first), it.second);
        }
    }
} CountCellsPass;

PRIVATE_NAMESPACE_END

And hooray!

5. Executing COUNT_CELLS pass.
Module: adder
  Cells in module: 2
Module: counter
  Cells in module: 2
Module: top
  Cells in module: 3

Cell type statistics:
---------------------
  $add                           :     3
  $adffe                         :     1
  $reduce_or                     :     1
  adder                          :     1
  counter                        :     1
---------------------