diff --git a/CHANGELOG.md b/CHANGELOG.md index af275325fdd..a40ced36e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. * added comprehensive simplification logic that is able to simplify `z3::expr` using an extended rule set as the simplification of `hal::BooleanFunction` * added `module_identification` plugin * allows a user to automatically search for arithmetic structures in the netlist + * added first rudimentary version of `genlib_writer` that allows to write the combinational gates of a gate library in genlib format which is required for resynthesis. * core * decorators * added `NetlistModificationDecorator::add_vcc/gnd_nets()` to create ground and power nets for netlists that do not have a ground/power net already diff --git a/plugins/.gitignore b/plugins/.gitignore index 7202e4b5e42..802f8379dea 100644 --- a/plugins/.gitignore +++ b/plugins/.gitignore @@ -7,6 +7,8 @@ !dataflow_analysis/**/* !gate_libraries* !gate_libraries/**/* +!genlib_writer* +!genlib_writer/**/* !gexf_writer* !gexf_writer/**/* !graph_algorithm* diff --git a/plugins/genlib_writer/CMakeLists.txt b/plugins/genlib_writer/CMakeLists.txt new file mode 100644 index 00000000000..955637dccfb --- /dev/null +++ b/plugins/genlib_writer/CMakeLists.txt @@ -0,0 +1,12 @@ +option(PL_GENLIB_WRITER "PL_GENLIB_WRITER" OFF) +if(PL_GENLIB_WRITER OR BUILD_ALL_PLUGINS) + file(GLOB_RECURSE GENLIB_WRITER_INC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) + file(GLOB_RECURSE GENLIB_WRITER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + file(GLOB_RECURSE GENLIB_WRITER_PYTHON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/python/*.cpp) + + hal_add_plugin(genlib_writer + SHARED + HEADER ${GENLIB_WRITER_INC} + SOURCES ${GENLIB_WRITER_SRC} ${GENLIB_WRITER_PYTHON_SRC} + ) +endif() diff --git a/plugins/genlib_writer/include/genlib_writer/genlib_writer.h b/plugins/genlib_writer/include/genlib_writer/genlib_writer.h new file mode 100644 index 00000000000..2f0b670e621 --- /dev/null +++ b/plugins/genlib_writer/include/genlib_writer/genlib_writer.h @@ -0,0 +1,55 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" +#include "hal_core/netlist/gate_library/gate_library_writer/gate_library_writer.h" + +namespace hal +{ + /** + * @ingroup netlist + */ + class NETLIST_API GenlibWriter : public GateLibraryWriter + { + public: + GenlibWriter() = default; + ~GenlibWriter() = default; + + /** + * @brief Write all single output combinational gate types of the gate library to a genlib file at the provided location. + * + * The area for the gate types is currently estimated by their input pin count and reduced in the case of multiplexers to motivate a possible resynthesis to use MUX gates when possible. + * + * @param[in] gate_lib - The gate library. + * @param[in] file_path - The output path. + * @returns True on success, false otherwise. + */ + bool write(const GateLibrary* gate_lib, const std::filesystem::path& file_path) override; + + private: + }; +} // namespace hal \ No newline at end of file diff --git a/plugins/genlib_writer/include/genlib_writer/plugin_genlib_writer.h b/plugins/genlib_writer/include/genlib_writer/plugin_genlib_writer.h new file mode 100644 index 00000000000..f460303f8a3 --- /dev/null +++ b/plugins/genlib_writer/include/genlib_writer/plugin_genlib_writer.h @@ -0,0 +1,16 @@ +#pragma once + +#include "hal_core/plugin_system/plugin_interface_base.h" + +namespace hal +{ + class PLUGIN_API GenlibWriterPlugin : public BasePluginInterface + { + public: + std::string get_name() const override; + std::string get_version() const override; + + void on_load() override; + void on_unload() override; + }; +} // namespace hal diff --git a/plugins/genlib_writer/python/python_bindings.cpp b/plugins/genlib_writer/python/python_bindings.cpp new file mode 100644 index 00000000000..8c64a722db1 --- /dev/null +++ b/plugins/genlib_writer/python/python_bindings.cpp @@ -0,0 +1,38 @@ +#include "pybind11/operators.h" +#include "pybind11/pybind11.h" +#include "pybind11/stl.h" +#include "pybind11/stl_bind.h" +#include "hal_core/python_bindings/python_bindings.h" + +#include "genlib_writer/plugin_genlib_writer.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(genlib_writer, m) + { + m.doc() = "hal GenlibWriterPlugin python bindings"; + #else + PYBIND11_PLUGIN(genlib_writer) + { + py::module m("genlib_writer", "hal GenlibWriterPlugin python bindings"); + #endif // ifdef PYBIND11_MODULE + + py::class_, BasePluginInterface>(m, "GenlibWriterPlugin") + .def_property_readonly("name", &GenlibWriterPlugin::get_name) + .def("get_name", &GenlibWriterPlugin::get_name) + .def_property_readonly("version", &GenlibWriterPlugin::get_version) + .def("get_version", &GenlibWriterPlugin::get_version) + ; + + #ifndef PYBIND11_MODULE + return m.ptr(); + #endif // PYBIND11_MODULE + } +} diff --git a/plugins/genlib_writer/src/genlib_writer.cpp b/plugins/genlib_writer/src/genlib_writer.cpp new file mode 100644 index 00000000000..11bbc12d878 --- /dev/null +++ b/plugins/genlib_writer/src/genlib_writer.cpp @@ -0,0 +1,91 @@ +#include "genlib_writer/genlib_writer.h" + +#include "hal_core/netlist/gate_library/gate_library.h" +#include "hal_core/utilities/log.h" + +#include +#include + +namespace hal +{ + namespace + { + std::string double_to_string(double d) + { + std::ostringstream oss; + oss << std::fixed << std::setprecision(4) << d; + return oss.str(); + } + } // namespace + + bool GenlibWriter::write(const GateLibrary* gate_lib, const std::filesystem::path& file_path) + { + std::setlocale(LC_NUMERIC, "en_US"); + + // set name + std::string file_str = "#" + gate_lib->get_name() + "\n"; + + // TODO since we are using the standard gate library writer interface we can not pass any other parameters, + // in the future it would be nice if we could for example pass a list of gate types that are being written. + + // process combinational gates + for (const auto& [name, gt] : gate_lib->get_gate_types([](const GateType* gt) { return gt->has_property(GateTypeProperty::combinational); })) + { + if (gt->get_boolean_functions().empty()) + { + log_warning("GenlibWriter", "Skipping gate type {} because eventhough it is marked as combinational it does not have any boolean functions.", name); + continue; + } + + if (gt->get_boolean_functions().size() > 1) + { + log_warning("GenlibWriter", + "Skipping gate type {} because it contains {} Boolean functions, but the genlib format only supports single output cells.", + name, + gt->get_boolean_functions().size()); + continue; + } + + // TODO make this read out the area from the gate library (currently not implemented) + u32 base_value = gt->get_input_pins().size(); + u32 mux_value = (base_value - 1) * 0.15 + 1; + u32 other_values = base_value * 0.3 + 1; + const double gate_area = gt->has_property(GateTypeProperty::c_mux) ? mux_value : other_values; + auto [output_pin, bf] = *(gt->get_boolean_functions().begin()); + + // simplify to get rid of XOR which we currently cannot translate to genlib + bf = bf.simplify(); + auto bf_str = bf.is_constant() ? (bf.has_constant_value(0) ? "CONST0" : "CONST1") : bf.to_string(); + + // TODO: this is the stupid way, but i do not care at the moment + bf_str = utils::replace(bf_str, std::string("|"), std::string("+")); + bf_str = utils::replace(bf_str, std::string("&"), std::string("*")); + + std::string gate_str = "GATE " + name + " " + double_to_string(gate_area) + " " + output_pin + "=" + bf_str + ";\n"; + + for (const auto& pin : gt->get_input_pins()) + { + const std::string phase = (bf.get_top_level_node().is_operation() && (bf.get_top_level_node().type == BooleanFunction::NodeType::Not)) ? "INV" : "NONINV"; + const std::string pin_str = "PIN " + pin->get_name() + " " + phase + " 1 999 1 0 1 0"; + gate_str += pin_str + "\n"; + } + + file_str += gate_str; + } + + // process sequential gates + for (const auto& [name, gt] : gate_lib->get_gate_types([](const GateType* gt) { return gt->has_property(GateTypeProperty::sequential); })) + { + log_warning("GenlibWriter", "Skipping gate type {} because sequential gates are currently not supported", name); + continue; + } + + // write generated string to file + std::ofstream file(file_path); + file << file_str; + file.close(); + + return true; + } + +} // namespace hal diff --git a/plugins/genlib_writer/src/plugin_genlib_writer.cpp b/plugins/genlib_writer/src/plugin_genlib_writer.cpp new file mode 100644 index 00000000000..bd5370b22fa --- /dev/null +++ b/plugins/genlib_writer/src/plugin_genlib_writer.cpp @@ -0,0 +1,34 @@ +#include "genlib_writer/plugin_genlib_writer.h" + +#include "genlib_writer/genlib_writer.h" +#include "hal_core/netlist/gate_library/gate_library_writer/gate_library_writer_manager.h" + +namespace hal +{ + + extern std::unique_ptr create_plugin_instance() + { + return std::make_unique(); + } + + std::string GenlibWriterPlugin::get_name() const + { + return std::string("genlib_writer"); + } + + std::string GenlibWriterPlugin::get_version() const + { + return std::string("0.1"); + } + + void GenlibWriterPlugin::on_load() + { + gate_library_writer_manager::register_writer("Default Genlib Writer", []() { return std::make_unique(); }, {".genlib"}); + } + + void GenlibWriterPlugin::on_unload() + { + gate_library_writer_manager::unregister_writer("Default Genlib Writer"); + } + +} // namespace hal diff --git a/plugins/resynthesis/CMakeLists.txt b/plugins/resynthesis/CMakeLists.txt index 801ed9193ca..9fde507b982 100644 --- a/plugins/resynthesis/CMakeLists.txt +++ b/plugins/resynthesis/CMakeLists.txt @@ -11,5 +11,6 @@ if(PL_RESYNTHESIS OR BUILD_ALL_PLUGINS) HEADER ${RESYNTHESIS_INC} SOURCES ${RESYNTHESIS_SRC} ${RESYNTHESIS_PYTHON_SRC} PYDOC SPHINX_DOC_INDEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/documentation/resynthesis.rst + LINK_LIBRARIES genlib_writer ) endif()