Skip to content

Custom Plugins

oleeng edited this page Mar 24, 2024 · 4 revisions

Creating a Standard Plugin

To use the full capabilities of HAL, you can develop plugins yourself. Although we can use scripts to use the HAL API, sometimes the speed of C++ is necessary to achieve the desired performance. Here we show you how to develop your own plugins. Furthermore, we show how to include python bindings to the code.

A bare bone Plugin

This plugin contains the minimal amount of code to run and be used in HAL. This plugin just outputs "Hello World!" to the console and the python binding just returns the string "Hello World Py".

Quick Start

One can ether create all the necessary files from scratch or use the plugin-set-up-script provided with HAL. Just cd into your working directory for the plugin located at <Path to HAL>/plugins/<plugin name> and run <pathToHAL>/tools/new_plugin.py <name>. In the following documentation the plugin name is barebone. This script creates the following directories and files in the current working directory.

├── CMakeLists.txt
├── include/barebone
│   └── barebone.h
├── python
│   └── python_bindings.cpp
└── src
    └── barebone.cpp

The Plugin Class

So let's start by implementing the code necessary to produce the a basic HAL plugin. Let us create both the header and source file.

// include/barebone/barebone.h
#pragma  once
#include  "hal_core/defines.h"
#include  "hal_core/plugin_system/plugin_interface_base.h"
#include  "hal_core/utilities/result.h"
#include  "hal_core/netlist/netlist.h"

namespace  hal
{
	class  PLUGIN_API  BarebonePlugin : public  BasePluginInterface
	{
	public:
		std::string  get_name() const  override;
		std::string  get_version() const  override;
		void  initialize() override;
		
		// this is a custom function used for the py binding
		static  void  barebone_test();
	};
} // namespace hal

All methods except barebone_test() are necessary functions of the provided BasePluginInterface.

The actual functionality is implemented in the barebone.cpp file.

// src/barebone.cpp
#include "barebone/barebone.h"

#include "boost/functional/hash.hpp"
#include "hal_core/netlist/gate.h"
#include "hal_core/netlist/module.h"

#include <deque>

namespace hal
{
    extern std::unique_ptr<BasePluginInterface> create_plugin_instance()
    {
        return std::make_unique<BarebonePlugin>();
    }

    std::string BarebonePlugin::get_name() const
    {
        return std::string("barebone");
    }

    std::string BarebonePlugin::get_version() const
    {
        return std::string("0.1");
    }

    void BarebonePlugin::initialize()
    {
    }

    void BarebonePlugin::barebone_test() {
        std::cout << "Hello World!" << std::endl;
    }

} // namespace hal

Adding python bindings

As HAL also brings a python shell for scripted analysis with it, you might want to expose your plugin to this environment. For this purpose, we use pybind11. The actual mapping is done in the python/python_bindings.cpp file.

// python/python_bindings.cpp
#include "hal_core/python_bindings/python_bindings.h"

#include "barebone/barebone.h"
#include "pybind11/operators.h"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
#include "pybind11/stl_bind.h"

namespace py = pybind11;

namespace hal
{
    // the name in PYBIND11_MODULE/PYBIND11_PLUGIN *MUST* match the filename of the output library (without extension),
    // otherwise you will get "ImportError: dynamic module does not define module export function" when importing the module

	#ifdef PYBIND11_MODULE
		PYBIND11_MODULE(barebone, m)
		{
			m.doc() = "hal barebone python bindings";
	#else
		PYBIND11_PLUGIN(barebone)
		{
			py::module m("barebone", "hal barebone python bindings");
	#endif
	
	// define all exposed functions
	py::class_<BarebonePlugin, RawPtrWrapper<BarebonePlugin>, BasePluginInterface>(m, "BarebonePlugin")
            .def_property_readonly("name", &BarebonePlugin::get_name)
            .def("get_name", &BarebonePlugin::get_name)
            .def_property_readonly("version", &BarebonePlugin::get_version)
            .def("get_version", &BarebonePlugin::get_version)
            // this is an example function
            .def_static(
                "barebone_test",
                []() -> std::string {
		                // we can call for example functions of the plugin here
                    BarebonePlugin::barebone_test();
                    
                    return "Hello World Py";
                });

	#ifndef PYBIND11_MODULE
		return m.ptr();
	#endif
	}
} // namespace hal

CMakeLists.txt

To build this plugin using HAL, we use the CMakeLists.txt file. The file should look something like this.

# CMakeLists.txt
option(PL_BAREBONE "PL_BAREBONE" OFF)

if(PL_BAREBONE OR BUILD_ALL_PLUGINS)
    file(GLOB_RECURSE BAREBONE_INC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
    file(GLOB_RECURSE BAREBONE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
    file(GLOB_RECURSE BAREBONE_PYTHON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/python/*.cpp)

    hal_add_plugin(barebone
        SHARED
        HEADER ${BAREBONE_INC}
        SOURCES ${BAREBONE_SRC} ${BAREBONE_PYTHON_SRC}
        PYDOC SPHINX_DOC_INDEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/documentation/barebone.rst
    )
endif()

We are done

Now you can build HAL using cmake .. -DBUILD_ALL_PLUGINS=1 to automatically build your newly created plugin. You can also call it using python as followed:

from hal_plugins.barebone import BarebonePlugin

output = BarebonePlugin.barebone_test()

print(output) # this prints the string "Hello World Py"

Clone this wiki locally