Skip to content

Commit

Permalink
Merge pull request #586 from emsec/feature/genlib_writer
Browse files Browse the repository at this point in the history
Feature/genlib writer
  • Loading branch information
SimonKlx authored Jul 17, 2024
2 parents 02a1176 + ba8ba02 commit 2267596
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions plugins/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
!dataflow_analysis/**/*
!gate_libraries*
!gate_libraries/**/*
!genlib_writer*
!genlib_writer/**/*
!gexf_writer*
!gexf_writer/**/*
!graph_algorithm*
Expand Down
12 changes: 12 additions & 0 deletions plugins/genlib_writer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
55 changes: 55 additions & 0 deletions plugins/genlib_writer/include/genlib_writer/genlib_writer.h
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions plugins/genlib_writer/include/genlib_writer/plugin_genlib_writer.h
Original file line number Diff line number Diff line change
@@ -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
38 changes: 38 additions & 0 deletions plugins/genlib_writer/python/python_bindings.cpp
Original file line number Diff line number Diff line change
@@ -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_<GenlibWriterPlugin, RawPtrWrapper<GenlibWriterPlugin>, 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
}
}
91 changes: 91 additions & 0 deletions plugins/genlib_writer/src/genlib_writer.cpp
Original file line number Diff line number Diff line change
@@ -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 <clocale>
#include <fstream>

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
34 changes: 34 additions & 0 deletions plugins/genlib_writer/src/plugin_genlib_writer.cpp
Original file line number Diff line number Diff line change
@@ -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<BasePluginInterface> create_plugin_instance()
{
return std::make_unique<GenlibWriterPlugin>();
}

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<GenlibWriter>(); }, {".genlib"});
}

void GenlibWriterPlugin::on_unload()
{
gate_library_writer_manager::unregister_writer("Default Genlib Writer");
}

} // namespace hal
1 change: 1 addition & 0 deletions plugins/resynthesis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit 2267596

Please sign in to comment.