diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b0be59b563..bd8da86d07f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +* **WARNING:** this release breaks the API of the `bitorder_propagation` plugin +* plugins + * changed `bitorder_propagation` plugin + * changed API so that no instance of the plugin needs to be created anymore to apply its algorithms + * changed propagation logic for better results +* miscellaneous + * added backward compatibility for view management +* bugfixes + * fixed incompatibility between shipped zlib and QuaZip libraries + * fixed layout bug which occured when leftmost node had no inputs ## [4.3.0](v4.3.0) - 2024-07-02 13:42:55+02:00 (urgency: medium) * **WARNING:** this release breaks compatibility with Ubuntu 20.04 LTS diff --git a/deps/abc/src/misc/zlib/crc32.c b/deps/abc/src/misc/zlib/crc32.c index 46c9700871c..74b8c755681 100644 --- a/deps/abc/src/misc/zlib/crc32.c +++ b/deps/abc/src/misc/zlib/crc32.c @@ -213,13 +213,13 @@ ABC_NAMESPACE_IMPL_START /* ========================================================================= * This function can be used by asm versions of crc32() */ -const unsigned long FAR * ZEXPORT get_crc_table() +const unsigned FAR * ZEXPORT get_crc_table() /* changed long -> unsigned (see crc32.h) */ { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; + return (const unsigned FAR *)crc_table; } /* ========================================================================= */ diff --git a/deps/abc/src/misc/zlib/crc32.h b/deps/abc/src/misc/zlib/crc32.h index d023439aa52..3818d7c6e85 100644 --- a/deps/abc/src/misc/zlib/crc32.h +++ b/deps/abc/src/misc/zlib/crc32.h @@ -4,7 +4,15 @@ ABC_NAMESPACE_HEADER_START -local const unsigned long FAR crc_table[TBLS][256] = +/* changed long -> unsigned + + The curse of having a library frozen at an rather old version. In recent + versions the variable bit size gets adjusted according to system and + compile flags. By now we need unsigned (32 bit) since that is what + QuaZip expects. +*/ + +local const unsigned FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, diff --git a/deps/abc/src/misc/zlib/zlib.h b/deps/abc/src/misc/zlib/zlib.h index 46c1a1aecb7..b3d4533b669 100644 --- a/deps/abc/src/misc/zlib/zlib.h +++ b/deps/abc/src/misc/zlib/zlib.h @@ -1611,7 +1611,7 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN const unsigned * ZEXPORT get_crc_table OF((void)); /* changed long -> unsigned (see crc32.h) */ ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ABC_NAMESPACE_HEADER_END diff --git a/include/hal_core/netlist/pins/pin_group.h b/include/hal_core/netlist/pins/pin_group.h index 9696aa2fa88..0dec626d05d 100644 --- a/include/hal_core/netlist/pins/pin_group.h +++ b/include/hal_core/netlist/pins/pin_group.h @@ -26,6 +26,8 @@ #pragma once #include "hal_core/defines.h" +#include "hal_core/netlist/gate_library/enums/pin_direction.h" +#include "hal_core/netlist/gate_library/enums/pin_type.h" #include "hal_core/utilities/log.h" #include "hal_core/utilities/result.h" diff --git a/plugins/bitorder_propagation/documentation/bitorder_propagation.rst b/plugins/bitorder_propagation/documentation/bitorder_propagation.rst index c92babdb3b2..61f82fe9846 100644 --- a/plugins/bitorder_propagation/documentation/bitorder_propagation.rst +++ b/plugins/bitorder_propagation/documentation/bitorder_propagation.rst @@ -1,5 +1,8 @@ -Bitorder Propagation +Bit-Order Propagation ========================== +.. automodule:: bitorder_propagation + :members: reorder_module_pin_groups, propagate_bitorder + .. autoclass:: bitorder_propagation.BitorderPropagationPlugin :members: diff --git a/plugins/bitorder_propagation/include/bitorder_propagation/bitorder_propagation.h b/plugins/bitorder_propagation/include/bitorder_propagation/bitorder_propagation.h new file mode 100644 index 00000000000..6dc3e24710f --- /dev/null +++ b/plugins/bitorder_propagation/include/bitorder_propagation/bitorder_propagation.h @@ -0,0 +1,124 @@ +// 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. + +/** + * @file bitorder_propagation.h + * @brief This file contains functions for bit-order propagation from pin groups of known bit order to pin groups of unknown bit order. + */ + +#pragma once + +#include "hal_core/defines.h" +#include "hal_core/netlist/pins/pin_group.h" +#include "hal_core/utilities/result.h" + +#include + +namespace hal +{ + class Net; + class Netlist; + class Module; + class ModulePin; + + namespace bitorder_propagation + { + /** + * Propagate known bit-order information from the given module pin groups to module pin groups of unknown bit order. + * The known bit-order information is taken from the map from net to index given for each pair of module and pin group in `src`. + * After propagation, the algorithm tries to reconstruct valid bit orders from the propagated information. + * + * @param[in] src - The known indices for the nets belonging to the given module pin groups. + * @param[in] dst - The pairs of module ID and pin group name with unknown bit order. + * @param[in] enforce_continuous_bitorders - Set `true` to only allow for continuous bit orders, `false` to also allow bit orders that are not continuous. Defaults to `true`. + * @returns OK and a map containing all known bit orders (including new and already known ones) on success, an error otherwise. + */ + Result*>, std::map>> + propagate_module_pingroup_bitorder(const std::map*>, std::map>& src, + const std::set*>>& dst, + const bool enforce_continuous_bitorders = true); + + /** + * Reorder and rename the pins of the pin groups according to the provided bit-order information. + * + * @param[in] ordered_module_pin_groups - A mapping from pairs of modules and their pin groups to known bit-order information given as a mapping from nets to their index. + * @returns OK on success, an error otherwise. + */ + Result reorder_module_pin_groups(const std::map*>, std::map>& ordered_module_pin_groups); + + /** + * Propagate known bit-order information from one module pin group to another module pin group of unknown bit order. + * The known bit-order information is taken from the order of pins in the pin group of `src`. + * After propagation, the algorithm tries to reconstruct a valid bit order from the propagated information. + * The valid bit order is then annotated to the module pin group, i.e., the pins of the respective pin group are renamed and reordered. + * + * @param[in] nl - The netlist containing the module. + * @param[in] src - The pair of module ID and pin group name with known bit order. + * @param[in] dst - The pair of module ID and pin group name with unknown bit order. + * @returns OK and a map containing all known bit orders (including new and already known ones) on success, an error otherwise. + */ + Result*>, std::map>> propagate_bitorder(Netlist* nl, const std::pair& src, const std::pair& dst); + + /** + * Propagate known bit-order information from one module pin group to another module pin group of unknown bit order. + * The known bit-order information is taken from the order of pins in the pin group of `src`. + * After propagation, the algorithm tries to reconstruct a valid bit order from the propagated information. + * The valid bit order is then annotated to the module pin group, i.e., the pins of the respective pin group are renamed and reordered. + * + * @param[in] src - The pair of module and pin group with known bit order. + * @param[in] dst - The pair of module and pin group with unknown bit order. + * @returns OK and a map containing all known bit orders (including new and already known ones) on success, an error otherwise. + */ + Result*>, std::map>> propagate_bitorder(const std::pair*>& src, + const std::pair*>& dst); + + /** + * Propagate known bit-order information from the given module pin groups to module pin groups of unknown bit order. + * The known bit-order information is taken from the order of pins in the pin groups of `src`. + * After propagation, the algorithm tries to reconstruct valid bit orders from the propagated information. + * The valid bit orders are then annotated to the module pin groups, i.e., the pins of the respective pin groups are renamed and reordered. + * + * @param[in] nl - The netlist containing the modules. + * @param[in] src - The pairs of module ID and pin group name with known bit order. + * @param[in] dst - The pairs of module ID and pin group name with unknown bit order. + * @returns OK and a map containing all known bit orders (including new and already known ones) on success, an error otherwise. + */ + Result*>, std::map>> + propagate_bitorder(Netlist* nl, const std::vector>& src, const std::vector>& dst); + + /** + * Propagate known bit-order information from the given module pin groups to module pin groups of unknown bit order. + * The known bit-order information is taken from the order of pins in the pin groups of `src`. + * After propagation, the algorithm tries to reconstruct valid bit orders from the propagated information. + * The valid bit orders are then annotated to the module pin groups, i.e., the pins of the respective pin groups are renamed and reordered. + * + * @param[in] src - The pairs of module and pin group with known bit order. + * @param[in] dst - The pairs of module and pin group with unknown bit order. + * @returns OK and a map containing all known bit orders (including new and already known ones) on success, an error otherwise. + */ + Result*>, std::map>> propagate_bitorder(const std::vector*>>& src, + const std::vector*>>& dst); + } // namespace bitorder_propagation +} // namespace hal \ No newline at end of file diff --git a/plugins/bitorder_propagation/include/bitorder_propagation/plugin_bitorder_propagation.h b/plugins/bitorder_propagation/include/bitorder_propagation/plugin_bitorder_propagation.h index 32cba311232..460e6697c15 100644 --- a/plugins/bitorder_propagation/include/bitorder_propagation/plugin_bitorder_propagation.h +++ b/plugins/bitorder_propagation/include/bitorder_propagation/plugin_bitorder_propagation.h @@ -1,92 +1,80 @@ +// 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. + +/** + * @file plugin_bitorder_propagation.h + * @brief This file contains all functions related to the HAL plugin API. + */ + #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 ModulePin; + /** + * @class BitorderPropagationPlugin + * @brief Plugin interface for bit order propoagation. + * + * This class provides an interface to integrate the bit-order propagation as a plugin within the HAL framework. + */ class PLUGIN_API BitorderPropagationPlugin : public BasePluginInterface { public: - std::string get_name() const override; - std::string get_version() const override; - - void initialize() override; - - /** - * Propagates known bit order information to module pin groups with unknown bit order. - * Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - * - * @param[in] known_bitorders - The known indices for the nets belonging to module pin groups. - * @param[in] unknown_bitorders - The module pin groups with yet unknown bit order. - * @param[in] strict_consens_finding - When set to true this option only allows for complete and continous bitorders, while false would allow for bit orders to be formed that are either not complete or not continous. - * @returns OK and a mapping of all the known bit orders consisting of the new and already known. + /** + * @brief Default constructor for `BitorderPropagationPlugin`. */ - static Result*>, std::map>> - propagate_module_pingroup_bitorder(const std::map*>, std::map>& known_bitorders, - const std::set*>>& unknown_bitorders, - const bool strict_consens_finding = true); + BitorderPropagationPlugin() = default; - /** - * This function reorders and renames the pins of the pin groups according to the corresponding bit order information. - * - * @param[in] ordered_module_pin_groups - A mapping from all the modules and pin groups with known bit order information to the knonw bit order information mapping every net to its corresponding index. - * @returns OK if everything worked, Error otherwise. - */ - static Result reorder_module_pin_groups(const std::map*>, std::map>& ordered_module_pin_groups); - - /** - * Propagates known bit order information to module pin groups with unknown bit order. - * Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - * The valid bit orders are then annotated to the module pin groups. - * - * @param[in] nl - The netlist containing the modules. - * @param[in] src - The module id / pin group name pair with known bit order. (The pins of the pin group have to be in the right order already) - * @param[in] dst - The module / pin group pair with unknown bit order. - * @returns OK and a map containing all known bitorders consisting of the new and already known ones or an Error. + /** + * @brief Default destructor for `BitorderPropagationPlugin`. */ - static Result*>, std::map>> - propagate_bitorder(Netlist* nl, const std::pair& src, const std::pair& dst); + ~BitorderPropagationPlugin() = default; /** - * Propagates known bit order information to module pin groups with unknown bit order. - * Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - * The valid bit orders are then annotated to the module pin groups. + * @brief Get the name of the plugin. * - * @param[in] src - The module / pin group pair with known bit order. (The pins of the pin group have to be in the right order already) - * @param[in] dst - The module / pin group pair with unknown bit order. - * @returns OK and a map containing all known bitorders consisting of the new and already known ones or an Error. + * @returns The name of the plugin. */ - static Result*>, std::map>> propagate_bitorder(const std::pair*>& src, - const std::pair*>& dst); + std::string get_name() const override; /** - * Propagates known bit order information to module pin groups with unknown bit order. - * Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - * The valid bit orders are then annotated to the module pin groups. + * @brief Get the version of the plugin. * - * @param[in] nl - The netlist containing the modules. - * @param[in] src - The module id / pin group name pairs with known bit order. (The pins of the pin group have to be in the right order already) - * @param[in] dst - The module / pin group pairs with unknown bit order. - * @returns OK and a map containing all known bitorders consisting of the new and already known ones or an Error. + * @returns The version of the plugin. */ - static Result*>, std::map>> - propagate_bitorder(Netlist* nl, const std::vector>& src, const std::vector>& dst); + std::string get_version() const override; /** - * Propagates known bit order information to module pin groups with unknown bit order. - * Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - * The valid bit orders are then annotated to the module pin groups. + * @brief Get a short description of the plugin. * - * @param[in] src - The module / pin group pairs with known bit order. (The pins of the pin group have to be in the right order already) - * @param[in] dst - The module / pin group pairs with unknown bit order. - * @returns OK and a map containing all known bitorders consisting of the new and already known ones or an Error. + * @returns The short description of the plugin. */ - static Result*>, std::map>> propagate_bitorder(const std::vector*>>& src, - const std::vector*>>& dst); + std::string get_description() const override; }; } // namespace hal diff --git a/plugins/bitorder_propagation/python/python_bindings.cpp b/plugins/bitorder_propagation/python/python_bindings.cpp index ae0dea2febc..fd1036731e1 100644 --- a/plugins/bitorder_propagation/python/python_bindings.cpp +++ b/plugins/bitorder_propagation/python/python_bindings.cpp @@ -1,5 +1,6 @@ #include "hal_core/python_bindings/python_bindings.h" +#include "bitorder_propagation/bitorder_propagation.h" #include "bitorder_propagation/plugin_bitorder_propagation.h" #include "pybind11/operators.h" #include "pybind11/pybind11.h" @@ -17,183 +18,226 @@ namespace hal #ifdef PYBIND11_MODULE PYBIND11_MODULE(bitorder_propagation, m) { - m.doc() = "hal BitorderPropagationPlugin python bindings"; + m.doc() = "Tool to automatically propagate known bit orders to module pin groups of unknown bit order."; #else PYBIND11_PLUGIN(bitorder_propagation) { - py::module m("bitorder_propagation", "hal BitorderPropagationPlugin python bindings"); + py::module m("bitorder_propagation", "Tool to automatically propagate known bit orders to module pin groups of unknown bit order."); #endif // ifdef PYBIND11_MODULE - py::class_, BasePluginInterface>(m, "BitorderPropagationPlugin") - .def_property_readonly("name", &BitorderPropagationPlugin::get_name) - .def("get_name", &BitorderPropagationPlugin::get_name) - .def_property_readonly("version", &BitorderPropagationPlugin::get_version) - .def("get_version", &BitorderPropagationPlugin::get_version) - .def_static( - "propagate_module_pingroup_bitorder", - [](const std::map*>, std::map>& known_bitorders, - const std::set*>>& unknown_bitorders, - const bool strict_consens_finding = false) -> std::optional*>, std::map>> { - const auto res = BitorderPropagationPlugin::propagate_module_pingroup_bitorder(known_bitorders, unknown_bitorders, strict_consens_finding); - if (res.is_ok()) - { - return res.get(); - } - else - { - log_error("python_context", "{}", res.get_error().get()); - return std::nullopt; - } - }, - py::arg("known_bitorders"), - py::arg("unknown_bitorders"), - py::arg("strict_consens_finding") = false, - R"( - Propagates known bit order information to module pin groups with unknown bit order. - Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - - :param dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] known_bitorders: The known indices for the nets belonging to module pin groups. - :param set[tuple(hal_py.Module,hal_py.ModulePinGroup)] unknown_bitorders: The module pin groups with yet unknown bit order. - :param bool strict_consens_finding: When set to true this option only allows for complete and continous bitorders, while false would allow for bit orders to be formed that are either not complete or not continous. - :returns: A mapping of all the known bit orders consisting of the new and already known ones on success, ``None`` otherwise. + py::class_, BasePluginInterface> py_bitorder_propagation_plugin( + m, "BitorderPropagationPlugin", R"(This class provides an interface to integrate the bit-order propagation as a plugin within the HAL framework.)"); + + py_bitorder_propagation_plugin.def_property_readonly("name", &BitorderPropagationPlugin::get_name, R"( + The name of the plugin. + + :type: str + )"); + + py_bitorder_propagation_plugin.def("get_name", &BitorderPropagationPlugin::get_name, R"( + Get the name of the plugin. + + :returns: The name of the plugin. + :rtype: str + )"); + + py_bitorder_propagation_plugin.def_property_readonly("version", &BitorderPropagationPlugin::get_version, R"( + The version of the plugin. + + :type: str + )"); + + py_bitorder_propagation_plugin.def("get_version", &BitorderPropagationPlugin::get_version, R"( + Get the version of the plugin. + + :returns: The version of the plugin. + :rtype: str + )"); + + py_bitorder_propagation_plugin.def_property_readonly("description", &BitorderPropagationPlugin::get_description, R"( + The description of the plugin. + + :type: str + )"); + + py_bitorder_propagation_plugin.def("get_description", &BitorderPropagationPlugin::get_description, R"( + Get the description of the plugin. + + :returns: The description of the plugin. + :rtype: str + )"); + + m.def( + "propagate_module_pingroup_bitorder", + [](const std::map*>, std::map>& src, + const std::set*>>& dst, + const bool enforce_continuous_bitorders = true) -> std::optional*>, std::map>> { + const auto res = bitorder_propagation::propagate_module_pingroup_bitorder(src, dst, enforce_continuous_bitorders); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("src"), + py::arg("dst"), + py::arg("enforce_continuous_bitorders") = true, + R"( + Propagate known bit-order information from the given module pin groups to module pin groups of unknown bit order. + The known bit-order information is taken from the map from net to index given for each pair of module and pin group in ``src``. + After propagation, the algorithm tries to reconstruct valid bit orders from the propagated information. + + :param dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] src: The known indices for the nets belonging to the given module pin groups. + :param set[tuple(hal_py.Module,hal_py.ModulePinGroup)] dst: The pairs of module ID and pin group name with unknown bit order. + :param bool enforce_continuous_bitorders: Set ``True`` to only allow for continuous bit orders, ``^`` to also allow bit orders that are not continuous. Defaults to ``True``. + :returns: A dict containing all known bit orders (including new and already known ones) on success, ``None`` otherwise. :rtype: dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] or None - )") - .def_static( - "reorder_module_pin_groups", - [](const std::map*>, std::map>& ordered_module_pin_groups) -> bool { - const auto res = BitorderPropagationPlugin::reorder_module_pin_groups(ordered_module_pin_groups); - if (res.is_ok()) - { - return true; - } - else - { - log_error("python_context", "{}", res.get_error().get()); - return false; - } - }, - py::arg("ordered_module_pin_groups"), - R"( - This funtion tries to propagate the bit order of the src pin groups to the dst pin groups - - :param dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] ordered_module_pin_groups: A mapping from all the modules and pin groups with known bit order information to the knonw bit order information mapping every net to its corresponding index. - :returns: ``True`` on sucess, ``False`` otherwise. + )"); + + m.def( + "reorder_module_pin_groups", + [](const std::map*>, std::map>& ordered_module_pin_groups) -> bool { + const auto res = bitorder_propagation::reorder_module_pin_groups(ordered_module_pin_groups); + if (res.is_ok()) + { + return true; + } + else + { + log_error("python_context", "{}", res.get_error().get()); + return false; + } + }, + py::arg("ordered_module_pin_groups"), + R"( + Reorder and rename the pins of the pin groups according to the provided bit-order information. + + :param dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] ordered_module_pin_groups: A mapping from pairs of modules and their pin groups to known bit-order information given as a mapping from nets to their index. + :returns: ``True`` on success, ``False`` otherwise. :rtype: bool - )") - .def_static( - "propagate_bitorder", - [](Netlist* nl, - const std::pair& src, - const std::pair& dst) -> std::optional*>, std::map>> { - const auto res = BitorderPropagationPlugin::propagate_bitorder(nl, src, dst); - if (res.is_ok()) - { - return res.get(); - } - else - { - log_error("python_context", "{}", res.get_error().get()); - return std::nullopt; - } - }, - py::arg("nl"), - py::arg("src"), - py::arg("dst"), - R"( - Propagates known bit order information to module pin groups with unknown bit order. - Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - The valid bit orders are then annotated to the module pin groups. - - :param hal_py.netlist nl: The netlist. - :param tuple(int,str) src: A pair of module id and pin group name representing the source. - :param tuple(int,str) dst: A pair of module id and pin group name representing the destination. - :returns: All wellformed bitorders on success, ``None`` otherwise. + )"); + + m.def( + "propagate_bitorder", + [](Netlist* nl, const std::pair& src, const std::pair& dst) -> std::optional*>, std::map>> { + const auto res = bitorder_propagation::propagate_bitorder(nl, src, dst); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("nl"), + py::arg("src"), + py::arg("dst"), + R"( + Propagate known bit-order information from one module pin group to another module pin group of unknown bit order. + The known bit-order information is taken from the order of pins in the pin group of ``src``. + After propagation, the algorithm tries to reconstruct a valid bit order from the propagated information. + The valid bit order is then annotated to the module pin group, i.e., the pins of the respective pin group are renamed and reordered. + + :param hal_py.netlist nl: The netlist containing the module. + :param tuple(int,str) src: The pair of module ID and pin group name with known bit order. + :param tuple(int,str) dst: The pair of module ID and pin group name with unknown bit order. + :returns: A dict containing all known bit orders (including new and already known ones) on success, ``None`` otherwise. :rtype: dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] or None - )") - .def_static( - "propagate_bitorder", - [](const std::pair*>& src, - const std::pair*>& dst) -> std::optional*>, std::map>> { - const auto res = BitorderPropagationPlugin::propagate_bitorder(src, dst); - if (res.is_ok()) - { - return res.get(); - } - else - { - log_error("python_context", "{}", res.get_error().get()); - return std::nullopt; - } - }, - py::arg("src"), - py::arg("dst"), - R"( - Propagates known bit order information to module pin groups with unknown bit order. - Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - The valid bit orders are then annotated to the module pin groups. - - :param hal_py.netlist nl: The netlist. - :param tuple(hal_py.Module,hal_py.ModulePinGroup) src: A pair of module and pin group representing the source. - :param tuple(hal_py.Module,hal_py.ModulePinGroup) dst: A pair of module and pin group representing the destination. - :returns: All wellformed bitorders on success, ``None`` otherwise. + )"); + + m.def( + "propagate_bitorder", + [](const std::pair*>& src, + const std::pair*>& dst) -> std::optional*>, std::map>> { + const auto res = bitorder_propagation::propagate_bitorder(src, dst); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("src"), + py::arg("dst"), + R"( + Propagate known bit-order information from one module pin group to another module pin group of unknown bit order. + The known bit-order information is taken from the order of pins in the pin group of ``src``. + After propagation, the algorithm tries to reconstruct a valid bit order from the propagated information. + The valid bit order is then annotated to the module pin group, i.e., the pins of the respective pin group are renamed and reordered. + + :param tuple(hal_py.Module,hal_py.ModulePinGroup) src: The pair of module and pin group with known bit order. + :param tuple(hal_py.Module,hal_py.ModulePinGroup) dst: The pair of module and pin group with unknown bit order. + :returns: A dict containing all known bit orders (including new and already known ones) on success, ``None`` otherwise. :rtype: dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] or None - )") - .def_static( - "propagate_bitorder", - [](Netlist* nl, - const std::vector>& src, - const std::vector>& dst) -> std::optional*>, std::map>> { - const auto res = BitorderPropagationPlugin::propagate_bitorder(nl, src, dst); - if (res.is_ok()) - { - return res.get(); - } - else - { - log_error("python_context", "{}", res.get_error().get()); - return std::nullopt; - } - }, - py::arg("nl"), - py::arg("src"), - py::arg("dst"), - R"( - Propagates known bit order information to module pin groups with unknown bit order. - Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - The valid bit orders are then annotated to the module pin groups. - - :param hal_py.netlist nl: The netlist. - :param list[tuple(int,str)] src: A list of pairs of module id and pin group name representing the sources. - :param list[tuple(int,str)] dst: A list of pairs of module id and pin group name representing the destinations. - :returns: All wellformed bitorders on success, ``None`` otherwise. + )"); + + m.def( + "propagate_bitorder", + [](Netlist* nl, + const std::vector>& src, + const std::vector>& dst) -> std::optional*>, std::map>> { + const auto res = bitorder_propagation::propagate_bitorder(nl, src, dst); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("nl"), + py::arg("src"), + py::arg("dst"), + R"( + Propagate known bit-order information from the given module pin groups to module pin groups of unknown bit order. + The known bit-order information is taken from the order of pins in the pin groups of ``src``. + After propagation, the algorithm tries to reconstruct valid bit orders from the propagated information. + The valid bit orders are then annotated to the module pin groups, i.e., the pins of the respective pin groups are renamed and reordered. + + :param hal_py.netlist nl: The netlist containing the modules. + :param list[tuple(int,str)] src: The pairs of module ID and pin group name with known bit order. + :param list[tuple(int,str)] dst: The pairs of module ID and pin group name with unknown bit order. + :returns: A dict containing all known bit orders (including new and already known ones) on success, ``None`` otherwise. :rtype: dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] or None - )") - .def_static( - "propagate_bitorder", - [](const std::vector*>>& src, - const std::vector*>>& dst) -> std::optional*>, std::map>> { - const auto res = BitorderPropagationPlugin::propagate_bitorder(src, dst); - if (res.is_ok()) - { - return res.get(); - } - else - { - log_error("python_context", "{}", res.get_error().get()); - return std::nullopt; - } - }, - py::arg("src"), - py::arg("dst"), - R"( - Propagates known bit order information to module pin groups with unknown bit order. - Afterwards the algorithm tries to reconstruct valid bit orders from the propagated information. - The valid bit orders are then annotated to the module pin groups. - - :param hal_py.netlist nl: The netlist. - :param list[tuple(hal_py.Module,hal_py.ModulePinGroup)] src: A list of pairs of modules and pin groups representing the sources. - :param list[tuple(hal_py.Module,hal_py.ModulePinGroup)] dst: A list of pairs of modules and pin groups representing the destinations. - :returns: All wellformed bitorders on success, ``None`` otherwise. + )"); + + m.def( + "propagate_bitorder", + [](const std::vector*>>& src, + const std::vector*>>& dst) -> std::optional*>, std::map>> { + const auto res = bitorder_propagation::propagate_bitorder(src, dst); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("src"), + py::arg("dst"), + R"( + Propagate known bit-order information from the given module pin groups to module pin groups of unknown bit order. + The known bit-order information is taken from the order of pins in the pin groups of ``src``. + After propagation, the algorithm tries to reconstruct valid bit orders from the propagated information. + The valid bit orders are then annotated to the module pin groups, i.e., the pins of the respective pin groups are renamed and reordered. + + :param list[tuple(hal_py.Module,hal_py.ModulePinGroup)] src: The pairs of module and pin group with known bit order. + :param list[tuple(hal_py.Module,hal_py.ModulePinGroup)] dst: The pairs of module and pin group with unknown bit order. + :returns: A dict containing all known bit orders (including new and already known ones) on success, ``None`` otherwise. :rtype: dict[tuple(hal_py.Module,hal_py.ModulePinGroup),dict[hal_py.Net,int]] or None )"); diff --git a/plugins/bitorder_propagation/scripts/cli_test_simple_risc_bitorder_propagation.py b/plugins/bitorder_propagation/scripts/cli_test_simple_risc_bitorder_propagation.py index dbd712d9b6d..4fd0adb4977 100644 --- a/plugins/bitorder_propagation/scripts/cli_test_simple_risc_bitorder_propagation.py +++ b/plugins/bitorder_propagation/scripts/cli_test_simple_risc_bitorder_propagation.py @@ -1,29 +1,133 @@ -#!/usr/bin/env python3 -import sys, os +import json -#some necessary configuration: -sys.path.append("/home/simon/projects/hal/build/lib/") #this is where your hal python lib is located -os.environ["HAL_BASE_PATH"] = "/home/simon/projects/hal/build/" # hal base path+ +from hal_plugins import bitorder_propagation +from hal_plugins import netlist_preprocessing -import hal_py -netlist_to_read = "/home/simon/workspaces/2022_12_22/simple_risc_v_bitorder_test/simple_risc_v_bitorder_test.hal" -gate_library_path = "/home/simon/projects/hal/plugins/real_world_reversing/gate_libraries/ice40ultra_iphone.hgl" +min_group_size = 8 -#initialize HAL -hal_py.plugin_manager.load_all_plugins() +# clean up all _ordered_suffixes in the netlist +for m in netlist.get_modules(): + for pg in m.get_pin_groups(): + new_name = pg.name + while new_name.endswith("_ordered"): + new_name = new_name.removesuffix("_ordered") -#read netlist -netlist = hal_py.NetlistFactory.load_netlist(netlist_to_read) + if new_name != pg.name: + m.set_pin_group_name(pg, new_name) + # print(pg.name, new_name) -from hal_plugins import bitorder_propagation +# reconstruct top module pin groups +netlist_preprocessing.NetlistPreprocessingPlugin.reconstruct_top_module_pin_groups( + netlist +) + +unknown_module_pingroups = list() +known_module_pingroups = list() + +use_register_ground_truth = True + +for m in netlist.get_modules(): + if "DANA" in m.name: + for pg in m.get_pin_groups(): + if pg.size() > min_group_size: + unknown_module_pingroups.append((m, pg)) + + continue + + # value checks do not provide a bitorder + if "VALUE_CHECK" in m.name: + continue + + for pg in m.get_pin_groups(): + if pg.name not in ["I", "O"] and (pg.size() > min_group_size): + known_module_pingroups.append((m, pg)) + +# generate ground truth for register modules +bitorder_ground_truth = dict() +if use_register_ground_truth: + for m, pg in unknown_module_pingroups: + net_to_index = dict() + for p in pg.pins: + if p.direction == hal_py.PinDirection.output: + gate = p.net.get_sources()[0].gate + else: + gate = p.net.get_destinations(lambda ep: ep.gate.module == m)[0].gate + + if ( + "preprocessing_information", + "multi_bit_indexed_identifiers", + ) in gate.data: + _, reconstructed_identifiers_str = gate.get_data( + "preprocessing_information", "multi_bit_indexed_identifiers" + ) + + reconstructed_identifiers = json.loads(reconstructed_identifiers_str) + + if len(reconstructed_identifiers) == 0: + group_name = gate.name + index = 0 + else: + identifier = reconstructed_identifiers[0] + group_name = identifier[0] + index = identifier[1] + + # if (identifier[2] != "gate_name"): + # print("Warning, found identifier that stems not from a gate name, this could lead to unwanted behavior") + # print(reconstructed_identifiers) + + net_to_index[p.net] = index + # print("Net {} / {} - Gate {} / {}: {} {}".format(p.net.id, p.net.name, gate.id, gate.name, group_name, index)) + + bitorder_ground_truth[(m, pg)] = net_to_index + +print("KNOWN MODULE BITORDER:") +for mpg in known_module_pingroups: + m, pg = mpg + print("\t{} - {}".format(m.name, pg.name)) + +print("UNKNOWN MODULE BITORDER:") +for mpg in unknown_module_pingroups: + m, pg = mpg + print("\t{} - {}".format(m.name, pg.name)) + +# 1) only registers +bitorder_propagation_result = ( + bitorder_propagation.BitorderPropagationPlugin.propagate_bitorder( + known_module_pingroups, unknown_module_pingroups + ) +) + +relative_unknown = 1.0 +if len(unknown_module_pingroups) != 0: + relative_unknown = ( + len(bitorder_propagation_result) - len(known_module_pingroups) + ) / len(unknown_module_pingroups) -known_bitorders = [(71, "OUT"), (71, "IN"), (5, "3539_RDATA"), (5, "3539_WADDR"), (5, "3539_WDATA"), (5, "3539_RADDR"), (4, "3540_RADDR"), (4, "3540_WADDR"), (4, "3540_MASK"), (4, "3540_WDATA"), (4, "3540_RDATA"), (72, "OUT"), (72, "IN"), (2, "4417_ADDRESS"), (2, "4418_DATAOUT"), (2, "4418_DATAIN"), (2, "4417_DATAIN"), (2, "4417_MASKWREN"), (2, "4417_DATAOUT"), (3, "3541_RDATA"), (3, "3542_RDATA"), (3, "3541_WDATA"), (3, "3541_RADDR"), (3, "3541_WADDR"), (3, "3541_MASK"), (3, "3542_WDATA"), (70, "B"), (70, "A"), (74, "IN"), (74, "OUT"), (73, "OUT"), (73, "IN"), (64, "A"), (64, "OUT"), (64, "B"), (65, "OUT"), (65, "B"), (65, "A"), ] -unknown_bitorders = [(10, "Q"), (10, "D"), (51, "Q"), (51, "D"), (50, "Q"), (50, "D"), (44, "Q"), (44, "D"), (45, "D"), (45, "Q"), (53, "D"), (53, "Q"), (33, "D"), (33, "Q"), (24, "D"), (24, "Q"), (30, "D"), (30, "Q"), (26, "Q"), (26, "D"), (54, "D"), (54, "Q"), (20, "Q"), (20, "D"), (11, "D"), (11, "Q"), (41, "D"), (41, "Q"), (25, "Q"), (25, "D"), (13, "Q"), (13, "D"), (21, "Q"), (21, "D"), (52, "Q"), (52, "D"), (28, "D"), (28, "Q"), (35, "Q"), (35, "D"), (47, "D"), (47, "Q"), (16, "Q"), (16, "D"), (12, "D"), (12, "Q"), (62, "D"), (62, "Q"), (36, "D"), (36, "Q"), (23, "D"), (23, "Q"), (61, "D"), (61, "Q"), (29, "D"), (29, "Q"), (34, "D"), (34, "Q"), (46, "Q"), (46, "D"), (9, "Q"), (9, "D"), (39, "D"), (39, "Q"), (19, "Q"), (19, "D"), (48, "Q"), (48, "D"), (32, "Q"), (32, "D"), (14, "Q"), (14, "D"), (18, "D"), (18, "Q"), (60, "D"), (60, "Q"), (58, "Q"), (58, "D"), (59, "Q"), (59, "D"), (56, "D"), (56, "Q"), (42, "Q"), (42, "D"), (43, "Q"), (43, "D"), (17, "D"), (17, "Q"), (22, "Q"), (22, "D"), (57, "Q"), (57, "D"), (63, "D"), (63, "Q"), (15, "Q"), (15, "D"), (31, "D"), (31, "Q"), (38, "D"), (38, "Q"), (37, "D"), (37, "Q"), (40, "Q"), (40, "D"), (49, "Q"), (49, "D"), (27, "Q"), (27, "D"), (55, "D"), (55, "Q"), ] +relative_total = 1.0 +if (len(unknown_module_pingroups) + len(known_module_pingroups)) != 0: + relative_total = len(bitorder_propagation_result) / ( + len(unknown_module_pingroups) + len(known_module_pingroups) + ) -res_1 = bitorder_propagation.BitorderPropagationPlugin.propagate_bitorder(netlist, known_bitorders, unknown_bitorders) -print("Done") +benchmark_results = dict() +benchmark_results["BITORDER_PROPAGATION"] = dict() +benchmark_results["BITORDER_PROPAGATION"]["register_only"] = dict() +benchmark_results["BITORDER_PROPAGATION"]["register_only"][ + "initial_known_pingroups" +] = len(known_module_pingroups) +benchmark_results["BITORDER_PROPAGATION"]["register_only"]["unknown_pingroups"] = len( + unknown_module_pingroups +) +benchmark_results["BITORDER_PROPAGATION"]["register_only"]["final_known_pingroups"] = ( + len(bitorder_propagation_result) +) +benchmark_results["BITORDER_PROPAGATION"]["register_only"]["relative_unknown"] = ( + "{:.2}".format(relative_unknown) +) +benchmark_results["BITORDER_PROPAGATION"]["register_only"]["relative_total"] = ( + "{:.2}".format(relative_total) +) -#unload everything hal related -hal_py.plugin_manager.unload_all_plugins() +print(benchmark_results) diff --git a/plugins/bitorder_propagation/src/bitorder_propagation.cpp b/plugins/bitorder_propagation/src/bitorder_propagation.cpp new file mode 100644 index 00000000000..4cdf2b7be16 --- /dev/null +++ b/plugins/bitorder_propagation/src/bitorder_propagation.cpp @@ -0,0 +1,1370 @@ +#include "bitorder_propagation/bitorder_propagation.h" + +#include "hal_core/netlist/gate.h" +#include "hal_core/netlist/module.h" +#include "hal_core/netlist/netlist.h" +#include "hal_core/netlist/pins/gate_pin.h" +#include "hal_core/netlist/pins/module_pin.h" + +#include + +// #define PRINT_CONFLICT +// #define PRINT_CONNECTIVITY +// #define PRINT_CONNECTIVITY_BUILDING +// #define PRINT_GENERAL + +namespace hal +{ + namespace bitorder_propagation + { + namespace + { + typedef std::pair*> MPG; + typedef std::map> POSSIBLE_BITINDICES; + + /** + * Build an offset matrix that maps each pair of module and pin group to all the other pairs of module and pin group that overlap by providing an index for the same net. + * Since that index may be different, we calculate an offset and check whether that offset is the same for all nets where the two origins overlap. + * The matrix is populated in a way that the offset at `matrix[org_0][org_1]` allows the user to calculate the `index_1 = index_0 + offset`. + * + * @param[in] reduced_indices - The (already reduced) bit indices. + * @returns The offset matrix. + */ + Result>> build_offset_matrix(const std::map& reduced_indices) + { + // offset at matrix[org_0][org_1] means index_0 + offset = index_1 + std::map> origin_offset_matrix; + + for (const auto& [net, possible_bitindices] : reduced_indices) + { + std::map all_possible_indices; + + // fill all possible indices + for (const auto& [org_mpg, indices] : possible_bitindices) + { + all_possible_indices[org_mpg] = *(indices.begin()); + } + + // check whether all possible indices are just shifted version of each other with a stable offset + for (const auto& [org_mpg, indices] : possible_bitindices) + { + for (const auto& [already_set_org, already_set_index] : all_possible_indices) + { + // there does not yet exist an offset between the already set index and the one to be added next + if (origin_offset_matrix[org_mpg].find(already_set_org) == origin_offset_matrix[org_mpg].end()) + { + i32 new_index = *indices.begin(); + i32 offset = already_set_index - new_index; + + origin_offset_matrix[org_mpg][already_set_org] = offset; + origin_offset_matrix[already_set_org][org_mpg] = -offset; + } + // check wether the already existing offset leads to the same index + else + { + i32 new_index = *indices.begin(); + i32 offset = origin_offset_matrix.at(org_mpg).at(already_set_org); + + if (new_index + offset != i32(already_set_index)) + { + return ERR("unable to build offset matrix: failed to find valid offset between " + std::to_string(org_mpg.first->get_id()) + "-" + org_mpg.second->get_name() + + " and " + std::to_string(already_set_org.first->get_id()) + "-" + already_set_org.second->get_name()); + } + } + } + } + } + + return OK(origin_offset_matrix); + } + + /** + * Attempt to find an offset between two origins (pairs of module and pin group) with the help of a previously generated offset matrix. + * That matrix stores every known offset between two origins. + * By building a chain of known origin-offset pairs, we try to find offsets even for origins that do not share an already known offset. + * During the chain building we populate the matrix along the way whenever we find a valid offset. + * + * @param[in] org1 - First origin as a pair of module and pin group. + * @param[in] org2 - Second origin as a pair of module and pin group. + * @param[in] m - The offset matrix. + * @param[in] v - Set of already visited matrix entries. + * @returns OK and the index offset between `org1` and `org2` on success, an error otherwise. + */ + Result get_offset(const MPG& org1, const MPG& org2, std::map>& m, std::set>& v) + { + if (v.find({org1, org2}) != v.end()) + { + return ERR("already tried to follow that offset."); + } + + v.insert({org1, org2}); + + if (org1 == org2) + { + m[org1][org2] = 0; + return OK(0); + } + + if (m.find(org1) == m.end()) + { + return ERR("no valid offset to other origins."); + } + + if (m.at(org1).find(org2) != m.at(org1).end()) + { + return OK(m.at(org1).at(org2)); + } + + for (auto& [dst_c, first_proxy_offset] : m.at(org1)) + { + auto second_proxy_offset_res = get_offset(dst_c, org2, m, v); + if (second_proxy_offset_res.is_error()) + { + continue; + } + i32 second_proxy_offset = second_proxy_offset_res.get(); + + m[org1][org2] = first_proxy_offset + second_proxy_offset; + + return OK(first_proxy_offset + second_proxy_offset); + } + + return ERR("could not find an valid offset"); + } + + /** + * This function gathers neighboring pingroups for a net by propagating to the neighboring gates and searches for module pin groups. + * + * @param[in] n - TODO + * @param[in] successors - TODO + * @param[in] relevant_pin_groups - TODO + * @param[in] guarantee_propagation - TODO + * @param[in] inwards_module - TODO + * @param[in] visited - TODO + * @param[in] cache - TODO + * @returns TODO + */ + Result>> gather_connected_neighbors(Net* n, + bool successors, + const std::set& relevant_pin_groups, + const bool guarantee_propagation, + const Module* inwards_module, + std::set>& visited, + std::map, std::map>>& cache) + { + std::map> connected_neighbors; + +#ifdef PRINT_CONNECTIVITY_BUILDING + std::cout << "Gathering bit index for net " << n->get_id() << " with" << (guarantee_propagation ? "" : "out") << " guaranteed propagation " + << " in direction: " << (successors ? "forwards" : "backwards") << std::endl; +#endif + + // check whether the net is a global input or global output net (has no sources or destinations, but might have a bitorder annotated at the top module) + if ((successors && n->is_global_output_net()) || (!successors && n->is_global_input_net())) + { + auto m = n->get_netlist()->get_top_module(); + bool is_border_pin = successors ? m->is_input_net(n) : m->is_output_net(n); + if (is_border_pin) + { + auto border_pin = m->get_pin_by_net(n); + if (border_pin == nullptr) + { + return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(m->get_id()) + + ": net is border net but does not have a pin."); + } + auto pg = border_pin->get_group().first; + +#ifdef PRINT_CONNECTIVITY_BUILDING + std::cout << "Added global IO net as origin " << m->get_name() << " - " << pg->get_name() << " - " << n->get_id() << std::endl; +#endif + + connected_neighbors[{m, pg}].insert(n); + } + } + + const auto neighbors = successors ? n->get_destinations() : n->get_sources(); + for (const auto& ep : neighbors) + { + std::tuple t_ep = {ep, guarantee_propagation, inwards_module}; + if (visited.find(t_ep) != visited.end()) + { + continue; + } + visited.insert(t_ep); + + Gate* g = ep->get_gate(); + + if (g == nullptr) + { + continue; + } + +#ifdef PRINT_CONNECTIVITY_BUILDING + std::cout << "Checking gate " << g->get_id() << std::endl; +#endif + + if ((inwards_module != nullptr) && !inwards_module->contains_gate(g, true)) + { + continue; + } + + const auto modules = g->get_modules(); + + if (!guarantee_propagation) + { + // check whether the net that leads to the gate is part of a relevant pin_group + bool found_relevant_pin_group = false; + for (const auto& m : modules) + { + bool is_border_pin = successors ? m->is_input_net(n) : m->is_output_net(n); + if (is_border_pin) + { + auto border_pin = m->get_pin_by_net(n); + if (border_pin == nullptr) + { + return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(m->get_id()) + + ": net is border net but does not have a pin."); + } + auto border_pg = border_pin->get_group().first; + + // only consider relevant pin groups that already have a known bitorder or that are currently unknown but might get one + if (relevant_pin_groups.find({m, border_pg}) == relevant_pin_groups.end()) + { + continue; + } + + connected_neighbors[{m, border_pg}].insert(n); + found_relevant_pin_group = true; + } + } + + // stop the propagation at the gate when we reached it via at least one relevant pin group + if (found_relevant_pin_group) + { + continue; + } + } + + // propagate + std::vector next_eps; + + for (const auto& next_ep : successors ? g->get_fan_out_endpoints() : g->get_fan_in_endpoints()) + { + const GatePin* pin = next_ep->get_pin(); + if (g->get_type()->has_property(GateTypeProperty::sequential) && (g->get_type()->has_property(GateTypeProperty::ff) || g->get_type()->has_property(GateTypeProperty::latch))) + { + if (PinType t = pin->get_type(); (t == PinType::data) || (t == PinType::state) || (t == PinType::neg_state)) + { + next_eps.push_back(next_ep); + } + } + else + { + next_eps.push_back(next_ep); + } + } + + for (Endpoint* next_ep : next_eps) + { + // Check whether we leave the gate via a relevant pin group, if that is the case stop + bool found_relevant_pin_group = false; + for (const auto& m : modules) + { + bool is_border_pin = successors ? m->is_output_net(next_ep->get_net()) : m->is_input_net(next_ep->get_net()); + if (is_border_pin) + { + auto border_pin = m->get_pin_by_net(next_ep->get_net()); + if (border_pin == nullptr) + { + return ERR("cannot get bit index information for net with ID " + std::to_string(next_ep->get_net()->get_id()) + " from module with ID " + + std::to_string(m->get_id()) + ": net is border net but does not have a pin."); + } + auto border_pg = border_pin->get_group().first; + + // only consider relevant pin groups that already have a known bitorder or that are currently unknown but might get one + if (relevant_pin_groups.find({m, border_pg}) == relevant_pin_groups.end()) + { + continue; + } + + connected_neighbors[{m, border_pg}].insert(next_ep->get_net()); + found_relevant_pin_group = true; + } + } + + // stop the propagation at the gate when we would leave it via at least one relevant pin group + if (found_relevant_pin_group) + { + continue; + } + + std::map> connected; + std::tuple t = {next_ep, false, nullptr}; + if (auto it = cache.find(t); it != cache.end()) + { + connected = it->second; + } + else + { + auto res = gather_connected_neighbors(next_ep->get_net(), successors, relevant_pin_groups, false, nullptr, visited, cache); + if (res.is_error()) + { + return res; + } + connected = res.get(); + } + + cache[t] = connected; + + for (auto& [org_mpg, nets] : connected) + { + connected_neighbors[org_mpg].insert(nets.begin(), nets.end()); + } + } + } + + return OK(connected_neighbors); + } + + /** + * Reduce a collection of bit indices by deleting invalid indices. + * Indices are considered invalid if: + * - a pair of module and pin group annotates different indices for the same pin + * - a pair of module and pin group annotates the same index for different pins + * + * @param[in] collected_bitindices - All bit indices collected after propagation. + * @returns A reduced set of possible bit indices for every net. + */ + const std::map reduce_indices(const std::map& collected_bitindices) + { +#ifdef PRINT_CONFLICT + std::cout << "\tVanilla indices: " << std::endl; + for (const auto& [net, possible_bitindices] : collected_bitindices) + { + std::cout << "\t\tNet " << net->get_id() << " - " << net->get_name() << ": " << std::endl; + u32 origins = 0; + for (const auto& [org_mpg, indices] : possible_bitindices) + { + auto org_m = org_mpg.first; + auto org_pg = org_mpg.second; + + std::cout << "\t\t\t" << org_m->get_id() << "-" << org_pg->get_name() << ": ["; + for (const auto& index : indices) + { + std::cout << index << ", "; + } + std::cout << "]" << std::endl; + origins += 1; + } + + std::cout << "\t\tORIGINS: [" << origins << "]" << std::endl; + } +#endif + + auto reduced_collected_indices = collected_bitindices; + + // 1) Checks whether the mpg has annotated the same index to different nets + std::set> origin_indices; + std::set> origin_indices_to_remove; + + for (const auto& [net, possible_bitindices] : reduced_collected_indices) + { + for (const auto& [org_mpg, indices] : possible_bitindices) + { + for (const auto& index : indices) + { + if (origin_indices.find({org_mpg, index}) != origin_indices.end()) + { + origin_indices_to_remove.insert({org_mpg, index}); + } + else + { + origin_indices.insert({org_mpg, index}); + } + } + } + } + +#ifdef PRINT_CONFLICT + for (const auto& [org_mpg, index] : origin_indices_to_remove) + { + std::cout << "Found org " << org_mpg.first->get_id() << "-" << org_mpg.second->get_name() << " index " << index << " pair to remove!" << std::endl; + } +#endif + + for (auto& [net, possible_bitindices] : collected_bitindices) + { + for (auto& [org_mpg, indices] : possible_bitindices) + { + for (const auto& index : indices) + { + if (origin_indices_to_remove.find({org_mpg, index}) != origin_indices_to_remove.end()) + { + reduced_collected_indices.at(net).at(org_mpg).erase(index); + } + } + + if (reduced_collected_indices.at(net).at(org_mpg).empty()) + { + reduced_collected_indices.at(net).erase(org_mpg); + } + } + + if (reduced_collected_indices.at(net).empty()) + { + reduced_collected_indices.erase(net); + } + } + + if (reduced_collected_indices.empty()) + { + return {}; + } + + // 2) Checks whether a net has multiple indices annotated from the same origin mpg + auto further_reduced_collected_indices = reduced_collected_indices; + for (auto& [net, possible_bitindices] : reduced_collected_indices) + { + for (auto& [org_mpg, indices] : possible_bitindices) + { + if (indices.size() != 1) + { + further_reduced_collected_indices.at(net).erase(org_mpg); + } + } + + if (further_reduced_collected_indices.at(net).empty()) + { + further_reduced_collected_indices.erase(net); + } + } + + if (further_reduced_collected_indices.empty()) + { + return {}; + } + +#ifdef PRINT_CONFLICT + std::cout << "\tReduced Possible Indices: " << std::endl; + for (const auto& [net, possible_bitindices] : further_reduced_collected_indices) + { + std::cout << "\t\tNet " << net->get_id() << ": " << std::endl; + u32 origins = 0; + for (const auto& [org_mpg, indices] : possible_bitindices) + { + auto org_m = org_mpg.first; + auto org_pg = org_mpg.second; + + std::cout << "\t\t\t" << org_m->get_id() << "-" << org_pg->get_name() << ": ["; + for (const auto& index : indices) + { + std::cout << index << ", "; + } + std::cout << "]" << std::endl; + } + } +#endif + + return further_reduced_collected_indices; + } + + /** + * Check whether every net of a module pin group has been assigned a valid index. + * + * @param[in] mpg - The module pin group top check. + * @param[in] consensus_bitindices - The bit indices after attempting consensus finding. + * @returns `true` if the module pin group is complete, `false` otherwise. + */ + const bool check_completeness(const MPG& mpg, const std::map& consensus_bitindices) + { + bool is_complete_pin_group_bitorder = true; + + for (auto& pin : mpg.second->get_pins()) + { + Net* net = pin->get_net(); + if (consensus_bitindices.find(net) == consensus_bitindices.end()) + { + is_complete_pin_group_bitorder = false; + +#ifdef PRINT_CONFLICT + std::cout << "Missing net " << net->get_id() << " - " << net->get_name() << " for complete bitorder." << std::endl; +#endif + break; + } + } + +#ifdef PRINT_CONFLICT + if (is_complete_pin_group_bitorder) + { + std::cout << "Found complete bitorder for pingroup " << mpg.second->get_name() << std::endl; + for (const auto& [net, index] : consensus_bitindices) + { + std::cout << net->get_id() << ": " << index << std::endl; + } + } +#endif + + return is_complete_pin_group_bitorder; + } + + /** + * Align the given bit indices from range `[m:m+n]` to `[0:n]`. + * If the `enforce_continuous_bitorders` is `true`, also check whether the indices actually form a consecutive range. + * A checks whether all indices are unique, otherwise we can not determine an order. + * + * @param[in] consensus_bitindices - The bit indices after consensus finding. + * @param[in] enforce_continuous_bitorders - Set `true` to only allow consecutive bit orders, `false` otherwise. Defaults to `true`. + * @returns The aligned bit indices or an empty map if any condition has been violated. + */ + const std::map align_indices(const std::map& consensus_bitindices, const bool enforce_continuous_bitorders) + { + std::map aligned_consensus; + + std::set unique_indices; + for (const auto& [_n, index] : consensus_bitindices) + { + unique_indices.insert(index); + } + + if (unique_indices.empty()) + { + return {}; + } + + const i32 min_index = *(unique_indices.begin()); + const i32 max_index = *(unique_indices.rbegin()); + + // when the range is larger than pin group size there are holes in the bitorder + if (enforce_continuous_bitorders && ((max_index - min_index) > (i32(consensus_bitindices.size()) - 1))) + { + return {}; + } + + // when there are less unique indices in the range than nets, there are duplicates + if (unique_indices.size() < consensus_bitindices.size()) + { + return {}; + } + + std::map index_to_net; + for (const auto& [net, index] : consensus_bitindices) + { + index_to_net[index] = net; + } + + u32 index_counter = 0; + for (const auto& [_unaligned_index, net] : index_to_net) + { + aligned_consensus[net] = index_counter++; + } + + return aligned_consensus; + } + + /** + * Attempt consensus finding by searching for a pair-wise offset between all pairs of modules and pin groups. + * This offset must hold for all nets that have been assigned indices from the same origins. + * The offset propagates, so when A and B share an offset p and B and C share an offset q then the offset between A and C should be p + q. + * + * @param[in] mpg - The pin group for which to attempt consensus finding. + * @param[in] indices - The (already reduced) bit indices on which to search for a pair-wise offset. + * @param[in] enforce_continuous_bitorders - Set `true` to only allow consecutive bit orders, `false` otherwise. Defaults to `true`. + * @returns A map from nets to their index for the nets for which there is a common pair-wise offset. + */ + std::map find_consensus_via_offset(const MPG& mpg, const std::map& indices, const bool enforce_continuous_bitorders) + { + std::map consensus_bitindices; + + auto offset_matrix_res = build_offset_matrix(indices); + if (offset_matrix_res.is_error()) + { +#ifdef PRINT_CONFLICT + std::cout << "Failed to build offset matrix : " << offset_matrix_res.get_error().get() << std::endl; +#endif + return {}; + } + auto offset_matrix = offset_matrix_res.get(); + + // select a pseudo random base line and gather the offsets between the base line and all other possible module/pin group origins + auto base_line = offset_matrix.begin()->first; + +#ifdef PRINT_CONFLICT + std::cout << "Found valid offsets pingroup " << mpg.second->get_name() << ": " << std::endl; + std::cout << "Baseline: " << base_line.first->get_id() << "-" << base_line.second->get_name() << std::endl; + for (const auto& [org1, col] : offset_matrix) + { + std::cout << org1.first->get_id() << "-" << org1.second->get_name() << ": "; + for (const auto& [org2, offset] : col) + { + std::cout << org2.first->get_id() << "-" << org2.second->get_name() << "[" << offset << "] "; + } + std::cout << std::endl; + } +#endif + + for (const auto& [net, possible_bitindices] : indices) + { + // pair of first possible org_mod and org_pin_group + MPG org = possible_bitindices.begin()->first; + // index at first possible origin + i32 org_index = *(possible_bitindices.begin()->second.begin()); + std::set> v; + auto offset_res = get_offset(org, base_line, offset_matrix, v); + if (offset_res.is_error()) + { + if (possible_bitindices.size() == 1) + { + // if there cannot be found any valid offset to the baseline, but there is just one possible index annotated, we still allow it + // -> this wont break anything, since this only allows for bitorders that we otherwise would have discarded because of a missing net + consensus_bitindices[net] = org_index; + } + else + { + break; + } + } + else + { + i32 offset = offset_res.get(); + consensus_bitindices[net] = org_index + offset; + } + } + +#ifdef PRINT_CONFLICT + std::cout << "Found offset bitorder: " << std::endl; + for (const auto& [net, index] : consensus_bitindices) + { + std::cout << net->get_id() << ": " << index << std::endl; + } +#endif + + // check completeness, i.e., whether each pin of the pin group was annotated an index + const auto is_complete_pin_group_bitorder = check_completeness(mpg, consensus_bitindices); + + if (!is_complete_pin_group_bitorder) + { + return {}; + } + + // check if consecutive and shift so that indices start at 0 + const auto aligned_indices = align_indices(consensus_bitindices, enforce_continuous_bitorders); + + return aligned_indices; + } + + /** + * Find the most common bit index from a set of possible bit indices for all nets. + * + * @param[in] indices - The bit indices on which to perform the majority vote. + * @returns A map from nets to the most common index of the respective net. + */ + const std::map conduct_majority_vote(const std::map& indices) + { + std::map majority_indices; + + for (const auto& [net, possible_indices] : indices) + { + std::map index_to_count; + for (const auto& [_org, org_indices] : possible_indices) + { + for (const auto& index : org_indices) + { + index_to_count[index]++; + } + } + + // if there is only one index use this one + if (index_to_count.size() == 1) + { + majority_indices.insert({net, index_to_count.begin()->first}); + continue; + } + + // sort possible indices by how often they occur and afterwards check whether there is a clear majority + std::vector> index_counts = {index_to_count.begin(), index_to_count.end()}; + std::sort(index_counts.begin(), index_counts.end(), [](const auto& p1, const auto& p2) { return p1.second > p2.second; }); + + // check if unambiguous majority exists + if (index_counts.at(0).second > index_counts.at(1).second) + { + majority_indices.insert({net, index_counts.at(0).first}); + } + } + + return majority_indices; + } + + /** + * Attempt consensus finding by conducting a majority vote on the possible indices of each net of the target pin group. + * + * @param[in] mpg - The pin group for which to attempt consensus finding. + * @param[in] indices - The (already reduced) bit indices on which to perform the majority vote. + * @param[in] enforce_continuous_bitorders - Set `true` to only allow consecutive bit orders, `false` otherwise. Defaults to `true`. + * @returns A map from nets to the most common index of the respective net. + */ + std::map find_consensus_via_majority(const MPG& mpg, const std::map& indices, const bool enforce_continuous_bitorders) + { + const auto majority_indices = conduct_majority_vote(indices); + +#ifdef PRINT_CONFLICT + std::cout << "Found majority bitorder: " << std::endl; + for (const auto& [net, index] : majority_indices) + { + std::cout << net->get_id() << ": " << index << std::endl; + } +#endif + + // check completeness, i.e., whether each pin of the pin group was annotated an index + const auto is_complete_pin_group_bitorder = check_completeness(mpg, majority_indices); + if (!is_complete_pin_group_bitorder) + { + return {}; + } + + // check if consecutive and shift so that indices start at 0 + const auto aligned_indices = align_indices(majority_indices, enforce_continuous_bitorders); + + return aligned_indices; + } + + /** + * Attempt consensus finding by applying two majority vote iterations. + * First, a simple majority vote is performed on the already reduced bit indices. + * In the second iteration, all nets that already had an index annotated in the first iteration are disregarded from the set of ALL (unreduced) bit indices. + * Afterwards, the smaller set is then reduced again and a second majority vote is performed. + * The general idea is that conflicts that were previously present when considering all nets might disappear when disregarding nets that have already been annotated with an index. + * + * @param[in] mpg - The pin group for which to attempt consensus finding. + * @param[in] all_indices - All possible bit indices, i.e., the set of possible bit indices that have not yet been reduced. + * @param[in] reduced_indices - The (already reduced) bit indices on which to perform the majority vote. + * @param[in] enforce_continuous_bitorders - Set `true` to only allow consecutive bit orders, `false` otherwise. Defaults to `true`. + * @returns A map from nets to the most common index of the respective net after applying the relaxed majority voting. + */ + std::map find_consensus_via_majority_relaxed(const MPG& mpg, + const std::map& all_indices, + const std::map& reduced_indices, + const bool enforce_continuous_bitorders) + { + // 1st iteration + const auto first_majority_indices = conduct_majority_vote(reduced_indices); + + // take ALL collected net indices and delete the ones already annotated in the first iteration + auto unfound_indices = all_indices; + for (const auto& [net, _] : first_majority_indices) + { + unfound_indices.erase(net); + } + + // reduce indices again, but this time only consider nets that do not yet have an index found via majority + auto relaxed_reduced_indices = reduce_indices(unfound_indices); + + // 2nd iteration + const auto second_majority_indices = conduct_majority_vote(relaxed_reduced_indices); + +#ifdef PRINT_CONFLICT + std::cout << "Found majority bitorder: " << std::endl; + for (const auto& [net, index] : second_majority_indices) + { + std::cout << net->get_id() << ": " << index << std::endl; + } +#endif + + std::map combined_indices = first_majority_indices; + for (const auto& p : second_majority_indices) + { + combined_indices.insert(p); + } + + // check completeness, i.e., whether each pin of the pin group was annotated an index + const auto is_complete_pin_group_bitorder = check_completeness(mpg, combined_indices); + if (!is_complete_pin_group_bitorder) + { + return {}; + } + + // check if consecutive and shift so that indices start at 0 + const auto aligned_indices = align_indices(combined_indices, enforce_continuous_bitorders); + + return aligned_indices; + } + + /** + * Try to extract valid bit orders from the bit-index information that was gathered during the propagation step. + * The bit indices are given as a map from the net they are associated with to all possible bit indices, which are given as a map from the source module pin group to a set of the indices extracted from that pin group. + * First, conflicting information is deleted. + * Next, different strategies for consensus finding are applied. + * The resulting bit-order consensus is continuously validated in terms of its continuity and completeness. + * The validation strictness can be tweaked with the parameter `enforce_continuous_bitorders`. + * + * @param[in] mpg - The pin group for which to attempt consensus finding. + * @param[in] collected_bitindices - The bit indices collected during propagation. + * @param[in] enforce_continuous_bitorders - Set `true` to only allow consecutive bit orders, `false` otherwise. Defaults to `true`. + * @returns The resulting bit orders as a map from nets to their indices. + */ + std::map extract_well_formed_bitorder(const MPG& mpg, const std::map& collected_bitindices, bool enforce_continuous_bitorders = true) + { + auto reduced_collected_indices = reduce_indices(collected_bitindices); + + if (reduced_collected_indices.empty()) + { + return {}; + } + + auto aligned_consensus = find_consensus_via_offset(mpg, reduced_collected_indices, enforce_continuous_bitorders); + + if (aligned_consensus.empty()) + { + aligned_consensus = find_consensus_via_majority(mpg, reduced_collected_indices, enforce_continuous_bitorders); + } + + if (aligned_consensus.empty()) + { + aligned_consensus = find_consensus_via_majority_relaxed(mpg, collected_bitindices, reduced_collected_indices, enforce_continuous_bitorders); + } + + if (aligned_consensus.empty()) + { + return {}; + } + +#ifdef PRINT_CONFLICT + std::cout << "Found valid input bitorder for pingroup " << mpg.second->get_name() << std::endl; + for (const auto& [net, index] : aligned_consensus) + { + std::cout << net->get_id() << ": " << index << std::endl; + } +#endif + + return aligned_consensus; + } + + } // namespace + + Result>> + propagate_module_pingroup_bitorder(const std::map>& known_bitorders, const std::set& unknown_bitorders, const bool enforce_continuous_bitorders) + { + // std::unordered_map, std::vector>>, boost::hash>>> connectivity_inwards; + // std::unordered_map, std::vector>>, boost::hash>>> connectivity_outwards; + + std::map, std::vector>>> connectivity_inwards; + std::map, std::vector>>> connectivity_outwards; + +#ifdef PRINT_GENERAL + std::cout << "Known bitorders [" << known_bitorders.size() << "]:" << std::endl; + for (const auto& [mpg, _] : known_bitorders) + { + std::cout << "\t" << mpg.first->get_name() << " - " << mpg.second->get_name() << std::endl; + } + + std::cout << "Unknown bitorders [" << known_bitorders.size() << "]:" << std::endl; + for (const auto& [m, pg] : unknown_bitorders) + { + std::cout << "\t" << m->get_name() << " - " << pg->get_name() << std::endl; + } + +#endif + + std::set relevant_pin_groups = unknown_bitorders; + for (const auto& [kb, _] : known_bitorders) + { + relevant_pin_groups.insert(kb); + } + + std::map, std::map>> cache_outwards; + std::map, std::map>> cache_inwards; + + // Build connectivity + for (const auto& [m, pg] : unknown_bitorders) + { + bool successors = pg->get_direction() == PinDirection::output; + + for (const auto& p : pg->get_pins()) + { + const auto starting_net = p->get_net(); + + std::set> visited_outwards; + const auto res_outwards = gather_connected_neighbors(starting_net, successors, relevant_pin_groups, false, nullptr, visited_outwards, cache_outwards); + if (res_outwards.is_error()) + { + return ERR_APPEND(res_outwards.get_error(), + "cannot porpagate bitorder: failed to gather bit indices outwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group " + + pg->get_name()); + } + const auto connected_outwards = res_outwards.get(); + + std::set> visited_inwards; + // NOTE when propagating inwards we guarantee the first propagation since otherwise we would stop at our starting pingroup + const auto res_inwards = gather_connected_neighbors(starting_net, !successors, relevant_pin_groups, true, m, visited_inwards, cache_inwards); + if (res_inwards.is_error()) + { + return ERR_APPEND(res_inwards.get_error(), + "cannot porpagate bitorder: failed to gather bit indices inwwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group " + + pg->get_name()); + } + const auto connected_inwards = res_inwards.get(); + + for (const auto& [org_mpg, nets] : connected_outwards) + { + connectivity_outwards[{{m, pg}, starting_net}].push_back({org_mpg, nets}); + } + + for (const auto& [org_mpg, nets] : connected_inwards) + { + connectivity_inwards[{{m, pg}, starting_net}].push_back({org_mpg, nets}); + } + } + } + +#ifdef PRINT_CONNECTIVITY + for (const auto& [start, connected] : connectivity_outwards) + { + std::cout << start.first.first->get_id() << " / " << start.first.first->get_name() << " - " << start.first.second->get_name() << " (OUTWARDS)@ " << start.second->get_id() << " / " + << start.second->get_name() << std::endl; + for (const auto& [mpg, nets] : connected) + { + for (const auto& net : nets) + { + std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << ": " << net->get_id() << " / " << net->get_name() << std::endl; + } + } + } + for (const auto& [start, connected] : connectivity_inwards) + { + std::cout << start.first.first->get_id() << " / " << start.first.first->get_name() << " - " << start.first.second->get_name() << " (INWARDS)@ " << start.second->get_id() << " / " + << start.second->get_name() << std::endl; + for (const auto& [mpg, nets] : connected) + { + for (const auto& net : nets) + { + std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << ": " << net->get_id() << " / " << net->get_name() << std::endl; + } + } + } +#endif + + log_info("bitorder_propagation", "Finished conncetivity analysis for bitorder propagation"); + + std::map> wellformed_module_pin_groups = known_bitorders; + + u32 iteration_ctr = 0; + + while (true) + { + // find modules that are neither blocked nor are they already wellformed + std::vector modules_and_pingroup; + for (const auto& mpg : unknown_bitorders) + { + if (mpg.first->is_top_module()) + { + log_error("bitorder_propagation", "Top module is part of the unknown bitorders!"); + continue; + } + + // NOTE We can skip module/pin group pairs that are already wellformed + if (wellformed_module_pin_groups.find(mpg) == wellformed_module_pin_groups.end()) + { + modules_and_pingroup.push_back(mpg); + } + }; + + std::deque q = {modules_and_pingroup.begin(), modules_and_pingroup.end()}; + + if (q.empty()) + { + break; + } + + log_info("bitorder_propagation", "Starting {}bitorder propagation iteration {}.", (enforce_continuous_bitorders ? "strict " : ""), iteration_ctr); + + std::map> new_wellformed_module_pin_groups = {}; + + while (!q.empty()) + { + auto [m, pg] = q.front(); + q.pop_front(); + + // check wether m has submodules that are in the q + bool no_submodules_in_q = true; + for (const auto& sub_m : m->get_submodules(nullptr, true)) + { + for (const auto& [sm, sp] : q) + { + if (sm == sub_m) + { + no_submodules_in_q = false; + break; + } + } + } + + if (!no_submodules_in_q) + { + q.push_back({m, pg}); + continue; + } + + bool successors = pg->get_direction() == PinDirection::output; + + std::map collected_inwards; + std::map collected_outwards; + std::map collected_combined; + + for (const auto& pin : pg->get_pins()) + { + Net* starting_net = pin->get_net(); + + // ############################################### // + // ################### INWARDS ################### // + // ############################################### // + + if (auto con_it = connectivity_inwards.find({{m, pg}, starting_net}); con_it == connectivity_inwards.end()) + { + // log_warning("bitorder_propagation", + // "There are no valid origins connected to modue {} / {} with pin group {} and net {} / {}.", + // m->get_id(), + // m->get_name(), + // pg->get_name(), + // starting_net->get_id(), + // starting_net->get_name()); + continue; + } + + const auto& connected_inwards = connectivity_inwards.at({{m, pg}, starting_net}); + + for (const auto& [org_mpg, org_nets] : connected_inwards) + { + if (auto mpg_it = wellformed_module_pin_groups.find(org_mpg); mpg_it != wellformed_module_pin_groups.end()) + { + const auto& nets = mpg_it->second; + for (const auto& org_net : org_nets) + { + if (auto net_it = nets.find(org_net); net_it != nets.end()) + { + collected_inwards[starting_net][org_mpg].insert(net_it->second); + collected_combined[starting_net][org_mpg].insert(net_it->second); + } + else + { + log_warning("bitorder_propagation", + "Module {} / {} and pin group {} are wellformed but are missing an index for net {} / {}!", + org_mpg.first->get_id(), + org_mpg.first->get_name(), + org_mpg.second->get_name(), + org_net->get_id(), + org_net->get_name()); + } + } + } + } + + // ############################################### // + // ################### OUTWARDS ################## // + // ############################################### // + + if (auto con_it = connectivity_outwards.find({{m, pg}, starting_net}); con_it == connectivity_outwards.end()) + { + // log_warning("bitorder_propagation", + // "There are no valid origins connected to modue {} / {} with pin group {} and net {} / {}.", + // m->get_id(), + // m->get_name(), + // pg->get_name(), + // starting_net->get_id(), + // starting_net->get_name()); + continue; + } + + const auto& connected_outwards = connectivity_outwards.at({{m, pg}, starting_net}); + + for (const auto& [org_mpg, org_nets] : connected_outwards) + { + if (auto mpg_it = wellformed_module_pin_groups.find(org_mpg); mpg_it != wellformed_module_pin_groups.end()) + { + const auto& nets = mpg_it->second; + for (const auto& org_net : org_nets) + { + if (auto net_it = nets.find(org_net); net_it != nets.end()) + { + collected_outwards[starting_net][org_mpg].insert(net_it->second); + collected_combined[starting_net][org_mpg].insert(net_it->second); + } + else + { + log_warning("bitorder_propagation", + "Module {} / {} and pin group {} are wellformed but are missing an index for net {} / {}!", + org_mpg.first->get_id(), + org_mpg.first->get_name(), + org_mpg.second->get_name(), + org_net->get_id(), + org_net->get_name()); + } + } + } + } + } + +#ifdef PRINT_CONFLICT + std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (INWARDS) " << std::endl; +#endif + + const auto newly_wellformed_inwards = extract_well_formed_bitorder({m, pg}, collected_inwards, enforce_continuous_bitorders); + if (!newly_wellformed_inwards.empty()) + { + new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_inwards; + continue; + } + +#ifdef PRINT_CONFLICT + std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (OUTWARDS) " << std::endl; +#endif + const auto newly_wellformed_outwards = extract_well_formed_bitorder({m, pg}, collected_outwards, enforce_continuous_bitorders); + if (!newly_wellformed_outwards.empty()) + { + new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_outwards; + continue; + } + +#ifdef PRINT_CONFLICT + std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (COMBINED) " << std::endl; +#endif + const auto newly_wellformed_combined = extract_well_formed_bitorder({m, pg}, collected_combined, enforce_continuous_bitorders); + if (!newly_wellformed_combined.empty()) + { + new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_combined; + } + } + + if (new_wellformed_module_pin_groups.empty()) + { + break; + } + + log_info("bitorder_propagation", "Found {} new bitorders in iteration: {}", new_wellformed_module_pin_groups.size(), iteration_ctr); + + // NOTE could think about merging if we find that information is lost between iterations + wellformed_module_pin_groups.insert(new_wellformed_module_pin_groups.begin(), new_wellformed_module_pin_groups.end()); + + iteration_ctr++; + + if (iteration_ctr > 100) + { + log_error("bitorder_propagation", "Endless loop protection, something went wrong!"); + break; + } + } + + log_info("bitorder_propagation", "Found a valid bitorder for {} pingroups.", wellformed_module_pin_groups.size()); + + return OK(wellformed_module_pin_groups); + } + + Result reorder_module_pin_groups(const std::map>& ordered_module_pin_groups) + { + // reorder pin groups to match found bit orders + for (const auto& [mpg, bitorder] : ordered_module_pin_groups) + { + auto m = mpg.first; + auto pg = mpg.second; + + std::map index_to_pin; + + // collect pins by the nets that run through them and store new index of each pin + for (const auto& [net, index] : bitorder) + { + ModulePin* pin = m->get_pin_by_net(net); + if (pin != nullptr) + { + auto [current_pin_group, _old_index] = pin->get_group(); + if (pg == current_pin_group) + { + index_to_pin[index] = pin; + } + else + { + return ERR("cannot reorder module pin groups: pin '" + pin->get_name() + "' appears in bit order of pin group '" + pg->get_name() + "' for module with ID " + + std::to_string(m->get_id()) + " but belongs to pin group '" + current_pin_group->get_name() + "'"); + } + } + } + + // apply new indices to pins + for (const auto& [index, pin] : index_to_pin) + { + if (!m->move_pin_within_group(pg, pin, index)) + { + return ERR("cannot reorder module pin groups: failed to move pin '" + pin->get_name() + "' in pin group '" + pg->get_name() + "' of module with ID " + + std::to_string(m->get_id()) + " to new index " + std::to_string(index)); + } + + const auto pin_name = pg->get_name() + "(" + std::to_string(index) + ")"; + if (auto collision_pins = m->get_pins([pin_name](const ModulePin* pin) { return pin->get_name() == pin_name; }); !collision_pins.empty()) + { + m->set_pin_name(collision_pins.front(), pin_name + "_OLD"); + } + + m->set_pin_name(pin, pin_name); + } + } + + return OK({}); + } + + Result*>, std::map>> propagate_bitorder(Netlist* nl, const std::pair& src, const std::pair& dst) + { + const std::vector> src_vec = {src}; + const std::vector> dst_vec = {dst}; + return propagate_bitorder(nl, src_vec, dst_vec); + } + + Result*>, std::map>> propagate_bitorder(const std::pair*>& src, + const std::pair*>& dst) + { + const std::vector*>> src_vec = {src}; + const std::vector*>> dst_vec = {dst}; + return propagate_bitorder(src_vec, dst_vec); + } + + Result*>, std::map>> + propagate_bitorder(Netlist* nl, const std::vector>& src, const std::vector>& dst) + { + std::vector*>> internal_src; + std::vector*>> internal_dst; + + // collect known bit orders + for (const auto& [mod_id, pg_name] : src) + { + auto src_mod = nl->get_module_by_id(mod_id); + if (src_mod == nullptr) + { + return ERR("Cannot propagate bit order: failed to find a module with ID " + std::to_string(mod_id)); + } + + PinGroup* src_pin_group = nullptr; + for (const auto& pin_group : src_mod->get_pin_groups()) + { + if (pin_group->get_name() == pg_name) + { + // check whether there are multiple pin groups with the same name + if (src_pin_group != nullptr) + { + return ERR("Cannot propagate bit order: found multiple pin groups with name " + pg_name + " at module with ID " + std::to_string(mod_id)); + } + + src_pin_group = pin_group; + } + } + + if (src_pin_group == nullptr) + { + return ERR("Cannot propagate bit order: failed to find a pin group with the name '" + pg_name + "' at module with ID " + std::to_string(mod_id)); + } + + internal_src.push_back({src_mod, src_pin_group}); + } + + // collect unknown bit orders + for (const auto& [mod_id, pg_name] : dst) + { + auto src_mod = nl->get_module_by_id(mod_id); + if (src_mod == nullptr) + { + return ERR("Cannot propagate bit order: failed to find a module with ID " + std::to_string(mod_id)); + } + + PinGroup* src_pin_group = nullptr; + for (const auto& pin_group : src_mod->get_pin_groups()) + { + if (pin_group->get_name() == pg_name) + { + // check whether there are multiple pin groups with the same name + if (src_pin_group != nullptr) + { + return ERR("Cannot propagate bitorder: found multiple pin groups with name '" + pg_name + "' at module with ID " + std::to_string(mod_id)); + } + + src_pin_group = pin_group; + } + } + + if (src_pin_group == nullptr) + { + return ERR("Cannot propagate bitorder: failed to find a pin group with the name '" + pg_name + "' at module with ID " + std::to_string(mod_id)); + } + + internal_dst.push_back({src_mod, src_pin_group}); + } + + // actually propagate the bit order + return propagate_bitorder(internal_src, internal_dst); + } + + Result*>, std::map>> propagate_bitorder(const std::vector*>>& src, + const std::vector*>>& dst) + { + std::map> known_bitorders; + std::set unknown_bitorders = {dst.begin(), dst.end()}; + + // collect known bit orders + for (auto& [m, pg] : src) + { + std::map src_bitorder; + + // TODO this is gonna crash if pin does not start at index 0 + for (u32 index = 0; index < pg->get_pins().size(); index++) + { + auto pin_res = pg->get_pin_at_index(index); + if (pin_res.is_error()) + { + return ERR_APPEND(pin_res.get_error(), "cannot propagate bit order: failed to get pin at index " + std::to_string(index) + " inside of pin group '" + pg->get_name() + "'"); + } + const ModulePin* pin = pin_res.get(); + + src_bitorder.insert({pin->get_net(), index}); + } + + known_bitorders.insert({{m, pg}, src_bitorder}); + } + + // actually propagate the bit order + const auto res = propagate_module_pingroup_bitorder(known_bitorders, unknown_bitorders); + if (res.is_error()) + { + return ERR_APPEND(res.get_error(), "cannot propagate bit order: failed propagation"); + } + + const auto all_wellformed_module_pin_groups = res.get(); + + // apply bit orders to module pin groups (rename and reorder pins) + reorder_module_pin_groups(all_wellformed_module_pin_groups); + +#ifdef PRINT_GENERAL + for (const auto& [mpg, bitorder] : all_wellformed_module_pin_groups) + { + auto m = mpg.first; + auto pg = mpg.second; + + std::cout << "Module: " << m->get_id() << " / " << m->get_name() << ": " << std::endl; + std::cout << "Pingroup: " << pg->get_name() << ": " << std::endl; + + for (const auto& [net, index] : bitorder) + { + std::cout << net->get_id() << ": " << index << std::endl; + } + } +#endif + + // print stats + const u32 all_wellformed_bitorders_count = all_wellformed_module_pin_groups.size(); + const u32 new_bit_order_count = all_wellformed_bitorders_count - src.size(); + + log_info("bitorder_propagation", "reconstructed {} unknown bit orders from {} known bit orders", new_bit_order_count, src.size()); + log_info("bitorder_propagation", "{} / {} = {} of all unknown bit orders", new_bit_order_count, dst.size(), double(new_bit_order_count) / double(dst.size())); + log_info("bitorder_propagation", + "{} / {} = {} of all pin group bit orders", + all_wellformed_bitorders_count, + dst.size() + src.size(), + double(all_wellformed_bitorders_count) / double(dst.size() + src.size())); + + return OK(all_wellformed_module_pin_groups); + } + } // namespace bitorder_propagation +} // namespace hal \ No newline at end of file diff --git a/plugins/bitorder_propagation/src/plugin_bitorder_propagation.cpp b/plugins/bitorder_propagation/src/plugin_bitorder_propagation.cpp index 7e839e0d7ac..9b2dd252ac0 100644 --- a/plugins/bitorder_propagation/src/plugin_bitorder_propagation.cpp +++ b/plugins/bitorder_propagation/src/plugin_bitorder_propagation.cpp @@ -1,13 +1,8 @@ #include "bitorder_propagation/plugin_bitorder_propagation.h" -#include "boost/functional/hash.hpp" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/module.h" - -#include - // #define PRINT_CONFLICT // #define PRINT_CONNECTIVITY +// // #define PRINT_CONNECTIVITY_BUILDING // #define PRINT_GENERAL namespace hal @@ -24,1078 +19,12 @@ namespace hal std::string BitorderPropagationPlugin::get_version() const { - return std::string("0.1"); - } - - void BitorderPropagationPlugin::initialize() - { - } - - namespace - { - typedef std::pair*> MPG; - typedef std::map> POSSIBLE_BITINDICES; - - /* - * This function tries to find a offset between to origins with the help of a previously generated offset matrix. - * That matrix stores every known offset between two origins. - * By building a chain of known origin-offset pairs we try to find offsets even for origins that do not share an already known offset. - * During the chain building we populate the matrix along the way incase we find a valid offset. - */ - Result get_offset(MPG& org1, MPG& org2, std::map>& m, std::set>& v) - { - if (v.find({org1, org2}) != v.end()) - { - return ERR("Already tried to follow that offset."); - } - - v.insert({org1, org2}); - - if (org1 == org2) - { - m[org1][org2] = 0; - return OK(0); - } - - if (m.find(org1) == m.end()) - { - return ERR("No valid offset to other origins."); - } - - if (m.at(org1).find(org2) != m.at(org1).end()) - { - return OK(m.at(org1).at(org2)); - } - - for (auto& [dst_c, first_proxy_offset] : m.at(org1)) - { - // dirty workaround to lose the const qualifier - MPG dst = {dst_c.first, dst_c.second}; - auto second_proxy_offset_res = get_offset(dst, org2, m, v); - if (second_proxy_offset_res.is_error()) - { - continue; - } - i32 second_proxy_offset = second_proxy_offset_res.get(); - - m[org1][org2] = first_proxy_offset + second_proxy_offset; - return OK(first_proxy_offset + second_proxy_offset); - } - - return ERR("Not able to find a offset connection."); - } - - /* - * This function tries to build an offset matrix that maps each module-pin_group origin to all the other module-pin_group origins that overlap by providing an index for the same net. - * Since that index maybe different we calulate an offset and check whether that offset is the same for all nets where the two origins overlap. - * The matrix is populated in a way that the offsetat matrix[org_0][org_1] allow the user to calculate the index_1 = index_0 + offset. - */ - Result>> build_offset_matrix(const std::map& reduced_indices) - { - // offset at matrix[org_0][org_1] means index_0 + offset = index_1 - std::map> origin_offset_matrix; - - for (const auto& [net, possible_bitindices] : reduced_indices) - { - std::map all_possible_indices; - - // fill all possible indices - for (const auto& [org_mpg, indices] : possible_bitindices) - { - all_possible_indices[org_mpg] = *(indices.begin()); - } - - // check whether all possible indices are just shifted version of each other with a stable offset - for (const auto& [org_mpg, indices] : possible_bitindices) - { - for (const auto& [already_set_org, already_set_index] : all_possible_indices) - { - // there does not yet exist an offset between the already set index and the one to be added next - if (origin_offset_matrix[org_mpg].find(already_set_org) == origin_offset_matrix[org_mpg].end()) - { - i32 new_index = *indices.begin(); - i32 offset = already_set_index - new_index; - - origin_offset_matrix[org_mpg][already_set_org] = offset; - origin_offset_matrix[already_set_org][org_mpg] = -offset; - } - // check wether the already existing offset leads to the same index - else - { - i32 new_index = *indices.begin(); - i32 offset = origin_offset_matrix.at(org_mpg).at(already_set_org); - - if (new_index + offset != i32(already_set_index)) - { - return ERR("unable to build offset matrix: failed to find valid offset between " + std::to_string(org_mpg.first->get_id()) + "-" + org_mpg.second->get_name() + " and " - + std::to_string(already_set_org.first->get_id()) + "-" + already_set_org.second->get_name()); - } - } - } - } - } - - return OK(origin_offset_matrix); - } - - /* - * This function gathers the connected neighboring pingroups for a net by propagating to the neighboring gates and searches for module pin groups. - */ - Result>> gather_conntected_neighbors(Net* n, Module* module_border, std::unordered_set& visited, bool successors) - { - std::map> connected_neighbors; - - const bool PRINT_CONFLICT = false; - - if (PRINT_CONFLICT) - { - std::cout << "Gathering bit index for net " << n->get_id() << " with current module border " << (module_border ? std::to_string(module_border->get_id()) : "null") - << " in direction: " << (successors ? "forwards" : "backwards") << std::endl; - } - - // check whether the net is a global input or global output net (has no sources or destinations, but might have a bitorder annotated at the top module) - if ((successors && n->is_global_output_net()) || (!successors && n->is_global_input_net())) - { - auto m = n->get_netlist()->get_top_module(); - bool is_border_pin = successors ? m->is_input_net(n) : m->is_output_net(n); - if (is_border_pin) - { - auto border_pin = m->get_pin_by_net(n); - if (border_pin == nullptr) - { - return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(m->get_id()) - + ": net is border net but does not have a pin."); - } - auto pg = border_pin->get_group().first; - - connected_neighbors[{m, pg}].insert(n); - } - - return OK(connected_neighbors); - } - - const auto neighbors = successors ? n->get_destinations() : n->get_sources(); - for (const auto& ep : neighbors) - { - Gate* g = ep->get_gate(); - - if (g == nullptr) - { - continue; - } - - if (PRINT_CONFLICT) - { - std::cout << "Checking gate " << g->get_id() << std::endl; - } - - if (visited.find(g) != visited.end()) - { - continue; - } - visited.insert(g); - - // check whether we left a previously entered module - if (!module_border->contains_gate(g, true)) - { - if (PRINT_CONFLICT) - { - std::cout << "Encountered gate " << g->get_id() << " that was not part of the module border." << std::endl; - } - - bool is_border_pin = !successors ? module_border->is_input_net(n) : module_border->is_output_net(n); - if (is_border_pin) - { - auto border_pin = module_border->get_pin_by_net(n); - if (border_pin == nullptr) - { - return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(module_border->get_id()) - + ": net is border net but does not have a pin."); - } - auto border_pg = border_pin->get_group().first; - - connected_neighbors[{module_border, border_pg}].insert(n); - } - - continue; - } - - Module* found_module = g->get_module(); - - // reached another module that is not the module we are currently in - if (found_module != module_border) - { - if (PRINT_CONFLICT) - { - std::cout << "Found new module " << found_module->get_id() << std::endl; - } - - bool is_border_pin = successors ? found_module->is_input_net(n) : found_module->is_output_net(n); - if (is_border_pin) - { - auto border_pin = found_module->get_pin_by_net(n); - if (border_pin == nullptr) - { - return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(found_module->get_id()) - + ": net is border net but does not have a pin."); - } - auto found_pg = border_pin->get_group().first; - - connected_neighbors[{found_module, found_pg}].insert(n); - } - - // only stop propagation at modules with no submodules - if (found_module->get_submodules().size() == 0) - { - continue; - } - } - - // propagate and stop at gates that have unsupported gates types - std::vector next_nets; - if (!g->get_type()->has_property(GateTypeProperty::sequential)) - { - next_nets = successors ? g->get_fan_out_nets() : g->get_fan_in_nets(); - } - else if (g->get_type()->has_property(GateTypeProperty::sequential) && (g->get_type()->has_property(GateTypeProperty::ff) || g->get_type()->has_property(GateTypeProperty::latch))) - { - for (const auto& next_ep : successors ? g->get_fan_out_endpoints() : g->get_fan_in_endpoints()) - { - const GatePin* pin = next_ep->get_pin(); - if (PinType t = pin->get_type(); t == PinType::data || t == PinType::state || t == PinType::neg_state) - { - next_nets.push_back(next_ep->get_net()); - } - } - } - - /*std::unordered_set new_visited = visited;*/ - - for (Net* next_n : next_nets) - { - auto res = gather_conntected_neighbors(next_n, found_module, /*new_*/ visited, successors); - if (res.is_error()) - { - return res; - } - - for (auto& [org_mpg, nets] : res.get()) - { - connected_neighbors[org_mpg].insert(nets.begin(), nets.end()); - } - } - } - - return OK(connected_neighbors); - } - - /* - * This function tries to extract valid bit orders from the bit index information that was gathered during the propagation step. - * First conflicting information is deleted, second offsets between different information origins are calculated and lastly the resulting bitorder is validated in terms of continuity and completeness. - * The Validation strictness can be tweaked with the parameter 'only_allow_consecutive_bitorders'. - */ - std::map extract_well_formed_bitorder(const MPG& mpg, const std::map& collected_bitindices, bool only_allow_consecutive_bitorders = true) - { - // ############################################### // - // ############### CONFLICT FINDING ############## // - // ############################################### // - -#ifdef PRINT_CONFLICT - for (const auto& [net, possible_bitindices] : collected_bitindices) - { - std::cout << "\t\tNet " << net->get_id() << ": " << std::endl; - u32 origins = 0; - for (const auto& [org_mpg, indices] : possible_bitindices) - { - auto org_m = org_mpg.first; - auto org_pg = org_mpg.second; - - std::cout << "\t\t\t" << org_m->get_id() << "-" << org_pg->get_name() << ": ["; - for (const auto& index : indices) - { - std::cout << index << ", "; - } - std::cout << "]" << std::endl; - origins += 1; - } - - std::cout << "\t\tORIGINS: [" << origins << "]" << std::endl; - } -#endif - - // delete non-valid possible indices - // indices are considered non valid when: - // - a pingroup annotates different indices for the same pin - // - a pingroup annotates the same index to different pins - - // 1) Checks whether a net has multiple indices annotated from the same origin mpg - auto reduced_collected_indices = collected_bitindices; - - for (auto& [net, possible_bitindices] : collected_bitindices) - { - for (auto& [org_mpg, indices] : possible_bitindices) - { - if (indices.size() != 1) - { - reduced_collected_indices.at(net).erase(org_mpg); - } - } - - if (reduced_collected_indices.at(net).empty()) - { - reduced_collected_indices.erase(net); - } - } - - if (reduced_collected_indices.empty()) - { - return {}; - } - - // 2) Checks whether the mpg has annotated the same index to different nets - std::set> origin_indices; - std::set> origin_indices_to_remove; - - for (auto& [net, possible_bitindices] : reduced_collected_indices) - { - for (auto& [org_mpg, indices] : possible_bitindices) - { - u32 index = *(indices.begin()); - if (origin_indices.find({org_mpg, index}) != origin_indices.end()) - { - origin_indices_to_remove.insert({org_mpg, index}); - } - else - { - origin_indices.insert({org_mpg, index}); - } - } - } - -#ifdef PRINT_CONFLICT - for (const auto& [org_mpg, index] : origin_indices_to_remove) - { - std::cout << "Found org " << org_mpg.first->get_id() << "-" << org_mpg.second->get_name() << " index " << index << " pair to remove!" << std::endl; - } -#endif - - auto further_reduced_collected_indices = reduced_collected_indices; - for (auto& [net, possible_bitindices] : reduced_collected_indices) - { - for (auto& [org_mpg, indices] : possible_bitindices) - { - u32 index = *(indices.begin()); - if (origin_indices_to_remove.find({org_mpg, index}) != origin_indices_to_remove.end()) - { - further_reduced_collected_indices.at(net).erase(org_mpg); - } - } - - if (further_reduced_collected_indices.at(net).empty()) - { - further_reduced_collected_indices.erase(net); - } - } - - if (further_reduced_collected_indices.empty()) - { - return {}; - } - - // TODO remove debug printing -#ifdef PRINT_CONFLICT - std::cout << "\tReduced Possible Indices: " << std::endl; - for (const auto& [net, possible_bitindices] : further_reduced_collected_indices) - { - std::cout << "\t\tNet " << net->get_id() << ": " << std::endl; - u32 origins = 0; - for (const auto& [org_mpg, indices] : possible_bitindices) - { - auto org_m = org_mpg.first; - auto org_pg = org_mpg.second; - - std::cout << "\t\t\t" << org_m->get_id() << "-" << org_pg->get_name() << ": ["; - for (const auto& index : indices) - { - std::cout << index << ", "; - } - std::cout << "]" << std::endl; - } - } -#endif - // End debug printing - - // ######################################################## // - // ############### CONSENS FINDING - OFFSET ############### // - // ######################################################## // - - // try to find a consens between the different possible indices - std::map consens_bitindices; - - auto offset_matrix_res = build_offset_matrix(further_reduced_collected_indices); - if (offset_matrix_res.is_error()) - { -#ifdef PRINT_CONFLICT - std::cout << "Failed to build offset matrix : " << offset_matrix_res.get_error().get() << std::endl; -#endif - return {}; - } - auto offset_matrix = offset_matrix_res.get(); - - auto base_line = offset_matrix.begin()->first; - - // TODO remove -#ifdef PRINT_CONFLICT - std::cout << "Found valid offsets pingroup " << mpg.second->get_name() << ": " << std::endl; - std::cout << "Baseline: " << base_line.first->get_id() << "-" << base_line.second->get_name() << std::endl; - for (const auto& [org1, col] : offset_matrix) - { - std::cout << org1.first->get_id() << "-" << org1.second->get_name() << ": "; - for (const auto& [org2, offset] : col) - { - std::cout << org2.first->get_id() << "-" << org2.second->get_name() << "[" << offset << "] "; - } - std::cout << std::endl; - } -#endif - - for (const auto& [net, possible_bitindices] : further_reduced_collected_indices) - { - // pair of first possible org_mod and org_pin_group - MPG org = possible_bitindices.begin()->first; - // index at first possible origin - i32 org_index = *(possible_bitindices.begin()->second.begin()); - std::set> v; - auto offset_res = get_offset(org, base_line, offset_matrix, v); - if (offset_res.is_error()) - { - if (possible_bitindices.size() == 1) - { - // if there cannot be found any valid offset to the baseline, but there is just one possible index annotated, we still allow it - // -> this wont break anything, since this only allows for bitorders that we otherwise would have discarded because of a missing net - consens_bitindices[net] = org_index; - } - else - { - // TODO remove - // std::cout << "Cannot find connection from origin " << org.first->get_id() << "-" << org.second->get_name() << " to baseline!" << std::endl; - break; - } - } - else - { - i32 offset = offset_res.get(); - consens_bitindices[net] = org_index + offset; - //std::cout << "Org Index: " << org_index << " Offset: " << offset << std::endl; - } - } - -#ifdef PRINT_CONFLICT - std::cout << "Found offset bitorder: " << std::endl; - for (const auto& [net, index] : consens_bitindices) - { - std::cout << net->get_id() << ": " << index << std::endl; - } -#endif - - // ############################################################## // - // ############### CONSENS FINDING - COMPLETENESS ############### // - // ############################################################## // - - bool complete_pin_group_bitorder = true; - std::map complete_consens; - - for (auto& pin : mpg.second->get_pins()) - { - Net* net = pin->get_net(); - // Currently also ignoring power/gnd nets but a more optimal approach would be to optimize them away where they are not needed (but we only got LUT4) - // -> maybe not, we would destroy 16 bit muxes if the top most MUX - if (net->is_gnd_net() || net->is_vcc_net()) - { - continue; - } - - if (consens_bitindices.find(net) == consens_bitindices.end()) - { - complete_pin_group_bitorder = false; - - // TODO remove - // std::cout << "Missing in net " << in_net->get_id() << " for complete bitorder." << std::endl; - - break; - } - else - { - complete_consens[net] = consens_bitindices.at(net); - } - } - - if (!complete_pin_group_bitorder) - { - return {}; - } - - // TODO remove -#ifdef PRINT_CONFLICT - std::cout << "Found complete bitorder for pingroup " << mpg.second->get_name() << std::endl; - for (const auto& [net, index] : complete_consens) - { - std::cout << net->get_id() << ": " << index << std::endl; - } -#endif - - // ########################################################### // - // ############### CONSENS FINDING - ALIGNMENT ############### // - // ########################################################### // - - std::map aligned_consens; - - // align consens from m:m+n to 0:n - i32 max_index = 0x80000000; - i32 min_index = 0x7fffffff; - std::set unique_indices; - for (const auto& [_n, index] : complete_consens) - { - unique_indices.insert(index); - - if (index > max_index) - { - max_index = index; - } - - if (index < min_index) - { - min_index = index; - } - } - - // when the range is larger than pin group size there are holes in the bitorder - if (only_allow_consecutive_bitorders && ((max_index - min_index) > (i32(complete_consens.size()) - 1))) - { - return {}; - } - - // when there are less unique indices in the range than nets, there are duplicates - if (unique_indices.size() < complete_consens.size()) - { - return {}; - } - - std::map index_to_net; - for (const auto& [net, index] : complete_consens) - { - index_to_net[index] = net; - } - - u32 index_counter = 0; - for (const auto& [_unaligned_index, net] : index_to_net) - { - aligned_consens[net] = index_counter++; - } - - // TODO remove -#ifdef PRINT_CONFLICT - std::cout << "Found valid input bitorder for pingroup " << mpg.second->get_name() << std::endl; - for (const auto& [net, index] : aligned_consens) - { - std::cout << net->get_id() << ": " << index << std::endl; - } -#endif - - return aligned_consens; - } - - } // namespace - - Result>> BitorderPropagationPlugin::propagate_module_pingroup_bitorder(const std::map>& known_bitorders, - const std::set& unknown_bitorders, - const bool strict_consens_finding) - { - std::unordered_map, std::vector>, boost::hash>> connectivity_inwards; - std::unordered_map, std::vector>, boost::hash>> connectivity_outwards; - - // Build connectivity - for (const auto& [m, pg] : unknown_bitorders) - { - bool successors = pg->get_direction() == PinDirection::output; - - for (const auto& p : pg->get_pins()) - { - const auto starting_net = p->get_net(); - - std::unordered_set visited_outwards; - const auto res_outwards = gather_conntected_neighbors(starting_net, m->get_parent_module(), visited_outwards, successors); - if (res_outwards.is_error()) - { - return ERR_APPEND(res_outwards.get_error(), - "cannot porpagate bitorder: failed to gather bit indices outwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group " - + pg->get_name()); - } - const auto connected_outwards = res_outwards.get(); - - std::unordered_set visited_inwards; - const auto res_inwards = gather_conntected_neighbors(starting_net, m, visited_inwards, !successors); - if (res_inwards.is_error()) - { - return ERR_APPEND(res_inwards.get_error(), - "cannot porpagate bitorder: failed to gather bit indices inwwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group " - + pg->get_name()); - } - const auto connected_inwards = res_inwards.get(); - - for (const auto& [org_mpg, nets] : connected_outwards) - { - // ignore MPG origins that are connected via multiple nets - // if (nets.size() > 1) - // { - // continue; - // } - - connectivity_outwards[{{m, pg}, starting_net}].push_back({org_mpg, *nets.begin()}); - } - - for (const auto& [org_mpg, nets] : connected_inwards) - { - // ignore MPG origins that are connected via multiple nets - // if (nets.size() > 1) - // { - // continue; - // } - - connectivity_inwards[{{m, pg}, starting_net}].push_back({org_mpg, *nets.begin()}); - } - } - } - - // TODO remove debug printing -#ifdef PRINT_CONNECTIVITY - for (const auto& [start, connected] : connectivity_outwards) - { - std::cout << start.first.first->get_id() << " / " << start.first.first->get_name() << " - " << start.first.second->get_name() << " (OUTWARDS)@ " << start.second->get_id() << " / " - << start.second->get_name() << std::endl; - for (const auto& [mpg, net] : connected) - { - std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << ": " << net->get_id() << " / " << net->get_name() << std::endl; - } - } - for (const auto& [start, connected] : connectivity_inwards) - { - std::cout << start.first.first->get_id() << " / " << start.first.first->get_name() << " - " << start.first.second->get_name() << " (INWARDS)@ " << start.second->get_id() << " / " - << start.second->get_name() << std::endl; - for (const auto& [mpg, net] : connected) - { - std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << ": " << net->get_id() << " / " << net->get_name() << std::endl; - } - } -#endif - - log_info("bitorder_propagation", "Finished conncetivity analysis for bitorder propagation"); - - std::map> wellformed_module_pin_groups = known_bitorders; - - u32 iteration_ctr = 0; - - while (true) - { - // find modules that are neither blocked nor are they already wellformed - std::vector modules_and_pingroup; - for (const auto& mpg : unknown_bitorders) - { - if (mpg.first->is_top_module()) - { - log_error("bitorder_propagation", "Top module is part of the unknown bitorders!"); - continue; - } - - // NOTE We can skip module/pin group pairs that are already wellformed - if (wellformed_module_pin_groups.find(mpg) == wellformed_module_pin_groups.end()) - { - modules_and_pingroup.push_back(mpg); - } - }; - - std::deque q = {modules_and_pingroup.begin(), modules_and_pingroup.end()}; - - if (q.empty()) - { - break; - } - - log_info("bitorder_propagation", "Starting {}bitorder propagation iteration {}.", (strict_consens_finding ? "strict " : ""), iteration_ctr); - - std::map> new_wellformed_module_pin_groups = {}; - - while (!q.empty()) - { - auto [m, pg] = q.front(); - q.pop_front(); - - // check wether m has submodules that are in the q - bool no_submodules_in_q = true; - for (const auto& sub_m : m->get_submodules(nullptr, true)) - { - for (const auto& [sm, sp] : q) - { - if (sm == sub_m) - { - no_submodules_in_q = false; - break; - } - } - } - - if (!no_submodules_in_q) - { - q.push_back({m, pg}); - continue; - } - - bool successors = pg->get_direction() == PinDirection::output; - - std::map collected_inwards; - std::map collected_outwards; - std::map collected_combined; - - for (const auto& pin : pg->get_pins()) - { - Net* starting_net = pin->get_net(); - - // ############################################### // - // ################### INWARDS ################### // - // ############################################### // - - if (auto con_it = connectivity_inwards.find({{m, pg}, starting_net}); con_it == connectivity_inwards.end()) - { - // log_warning("bitorder_propagation", - // "There are no valid origins connected to modue {} / {} with pin group {} and net {} / {}.", - // m->get_id(), - // m->get_name(), - // pg->get_name(), - // starting_net->get_id(), - // starting_net->get_name()); - continue; - } - - const auto& connected_inwards = connectivity_inwards.at({{m, pg}, starting_net}); - - for (const auto& [org_mpg, org_net] : connected_inwards) - { - if (auto mpg_it = wellformed_module_pin_groups.find(org_mpg); mpg_it != wellformed_module_pin_groups.end()) - { - const auto& nets = mpg_it->second; - if (auto net_it = nets.find(org_net); net_it != nets.end()) - { - collected_inwards[starting_net][org_mpg].insert(net_it->second); - collected_combined[starting_net][org_mpg].insert(net_it->second); - } - else - { - log_warning("bitorder_propagation", - "Module {} / {} and pin group {} are wellformed but are missing an index for net {} / {}!", - org_mpg.first->get_id(), - org_mpg.first->get_name(), - org_mpg.second->get_name(), - org_net->get_id(), - org_net->get_name()); - } - } - } - - // ############################################### // - // ################### OUTWARDS ################## // - // ############################################### // - - if (auto con_it = connectivity_outwards.find({{m, pg}, starting_net}); con_it == connectivity_outwards.end()) - { - // log_warning("bitorder_propagation", - // "There are no valid origins connected to modue {} / {} with pin group {} and net {} / {}.", - // m->get_id(), - // m->get_name(), - // pg->get_name(), - // starting_net->get_id(), - // starting_net->get_name()); - continue; - } - - const auto& connected_outwards = connectivity_outwards.at({{m, pg}, starting_net}); - - for (const auto& [org_mpg, org_net] : connected_outwards) - { - if (auto mpg_it = wellformed_module_pin_groups.find(org_mpg); mpg_it != wellformed_module_pin_groups.end()) - { - const auto& nets = mpg_it->second; - if (auto net_it = nets.find(org_net); net_it != nets.end()) - { - collected_outwards[starting_net][org_mpg].insert(net_it->second); - collected_combined[starting_net][org_mpg].insert(net_it->second); - } - else - { - log_warning("bitorder_propagation", - "Module {} / {} and pin group {} are wellformed but are missing an index for net {} / {}!", - org_mpg.first->get_id(), - org_mpg.first->get_name(), - org_mpg.second->get_name(), - org_net->get_id(), - org_net->get_name()); - } - } - } - } - -#ifdef PRINT_GENERAL - std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (INWARDS) " << std::endl; -#endif - - const auto newly_wellformed_inwards = extract_well_formed_bitorder({m, pg}, collected_inwards, strict_consens_finding); - if (!newly_wellformed_inwards.empty()) - { - new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_inwards; - continue; - } - -#ifdef PRINT_GENERAL - std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (OUTWARDS) " << std::endl; -#endif - const auto newly_wellformed_outwards = extract_well_formed_bitorder({m, pg}, collected_outwards, strict_consens_finding); - if (!newly_wellformed_outwards.empty()) - { - new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_outwards; - continue; - } - -#ifdef PRINT_GENERAL - std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (COMBINED) " << std::endl; -#endif - const auto newly_wellformed_combined = extract_well_formed_bitorder({m, pg}, collected_combined, strict_consens_finding); - if (!newly_wellformed_combined.empty()) - { - new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_combined; - } - } - - if (new_wellformed_module_pin_groups.empty()) - { - break; - } - - log_info("bitorder_propagation", "Found {} new bitorders in iteration: {}", new_wellformed_module_pin_groups.size(), iteration_ctr); - - // NOTE could think about merging if we find that information is lost between iterations - wellformed_module_pin_groups.insert(new_wellformed_module_pin_groups.begin(), new_wellformed_module_pin_groups.end()); - - iteration_ctr++; - - if (iteration_ctr > 100) - { - log_error("bitorder_propagation", "Endless loop protection, something went wrong!"); - break; - } - } - - log_info("bitorder_propagation", "Found a valid bitorder for {} pingroups.", wellformed_module_pin_groups.size()); - - return OK(wellformed_module_pin_groups); - } - - Result BitorderPropagationPlugin::reorder_module_pin_groups(const std::map>& ordered_module_pin_groups) - { - // reorder pin groups to match found bitorders - for (const auto& [mpg, bitorder] : ordered_module_pin_groups) - { - auto m = mpg.first; - auto pg = mpg.second; - - std::map index_to_pin; - - for (const auto& [net, index] : bitorder) - { - ModulePin* pin = m->get_pin_by_net(net); - if (pin != nullptr) - { - auto [current_pin_group, _old_index] = pin->get_group(); - if (pg == current_pin_group) - { - index_to_pin[index] = pin; - } - else - { - return ERR("cannot reorder module pin groups: pin " + pin->get_name() + " appears in bit order of pin group " + pg->get_name() + " for module with ID " - + std::to_string(m->get_id()) + " but belongs to pin group " + current_pin_group->get_name()); - } - } - } - - for (const auto& [index, pin] : index_to_pin) - { - if (!m->move_pin_within_group(pg, pin, index)) - { - return ERR( - "cannot reorder module pin groups: failed to move pin " + pin->get_name() + " in pin group " + pg->get_name() + " of module with ID " - + std::to_string(m->get_id()) + " to new index " + std::to_string(index)); - } - - const auto pin_name = pg->get_name() + "(" + std::to_string(index) + ")"; - if (auto collision_pins = m->get_pins([pin_name](const ModulePin* pin) { return pin->get_name() == pin_name; }); !collision_pins.empty()) - { - m->set_pin_name(collision_pins.front(), pin_name + "_OLD"); - } - - m->set_pin_name(pin, pin_name); - } - } - - return OK({}); - } - - Result*>, std::map>> - BitorderPropagationPlugin::propagate_bitorder(Netlist* nl, const std::pair& src, const std::pair& dst) - { - const std::vector> src_vec = {src}; - const std::vector> dst_vec = {dst}; - return propagate_bitorder(nl, src_vec, dst_vec); + return std::string("0.2"); } - Result*>, std::map>> BitorderPropagationPlugin::propagate_bitorder(const std::pair*>& src, - const std::pair*>& dst) + std::string BitorderPropagationPlugin::get_description() const { - const std::vector*>> src_vec = {src}; - const std::vector*>> dst_vec = {dst}; - return propagate_bitorder(src_vec, dst_vec); - } - - Result*>, std::map>> - BitorderPropagationPlugin::propagate_bitorder(Netlist* nl, const std::vector>& src, const std::vector>& dst) - { - std::vector*>> internal_src; - std::vector*>> internal_dst; - - for (const auto& [mod_id, pg_name] : src) - { - auto src_mod = nl->get_module_by_id(mod_id); - if (src_mod == nullptr) - { - return ERR("Cannot propagate bitorder: failed to find a module with id " + std::to_string(mod_id)); - } - - PinGroup* src_pin_group = nullptr; - for (const auto& pin_group : src_mod->get_pin_groups()) - { - if (pin_group->get_name() == pg_name) - { - // Check wether there are multiple pin groups with the same name - if (src_pin_group != nullptr) - { - return ERR("Cannot propagate bitorder: found multiple pin groups with name " + pg_name + " at module with ID " + std::to_string(mod_id)); - } - - src_pin_group = pin_group; - } - } - - if (src_pin_group == nullptr) - { - return ERR("Cannot propagate bitorder: failed to find a pin group with the name " + pg_name + " at module with ID " + std::to_string(mod_id)); - } - - internal_src.push_back({src_mod, src_pin_group}); - } - - for (const auto& [mod_id, pg_name] : dst) - { - auto src_mod = nl->get_module_by_id(mod_id); - if (src_mod == nullptr) - { - return ERR("Cannot propagate bitorder: failed to find a module with id " + std::to_string(mod_id)); - } - - PinGroup* src_pin_group = nullptr; - for (const auto& pin_group : src_mod->get_pin_groups()) - { - if (pin_group->get_name() == pg_name) - { - // Check wether there are multiple pin groups with the same name - if (src_pin_group != nullptr) - { - return ERR("Cannot propagate bitorder: found multiple pin groups with name " + pg_name + " at module with ID " + std::to_string(mod_id)); - } - - src_pin_group = pin_group; - } - } - - if (src_pin_group == nullptr) - { - return ERR("Cannot propagate bitorder: failed to find a pin group with the name " + pg_name + " at module with ID " + std::to_string(mod_id)); - } - - internal_dst.push_back({src_mod, src_pin_group}); - } - - return propagate_bitorder(internal_src, internal_dst); + return "Tool to automatically propagate known bit orders to module pin groups of unknown bit order."; } - Result*>, std::map>> BitorderPropagationPlugin::propagate_bitorder(const std::vector*>>& src, - const std::vector*>>& dst) - { - std::map> known_bitorders; - std::set unknown_bitorders = {dst.begin(), dst.end()}; - - for (auto& [m, pg] : src) - { - std::map src_bitorder; - for (u32 index = 0; index < pg->get_pins().size(); index++) - { - auto pin_res = pg->get_pin_at_index(index); - if (pin_res.is_error()) - { - return ERR_APPEND(pin_res.get_error(), "cannot propagate bitorder: failed to get pin at index " + std::to_string(index) + " inside of pin group " + pg->get_name()); - } - const ModulePin* pin = pin_res.get(); - - src_bitorder.insert({pin->get_net(), index}); - } - - known_bitorders.insert({{m, pg}, src_bitorder}); - } - - const auto res = propagate_module_pingroup_bitorder(known_bitorders, unknown_bitorders); - if (res.is_error()) - { - return ERR_APPEND(res.get_error(), "cannot propagate bitorder: failed propagation"); - } - - const auto all_wellformed_module_pin_groups = res.get(); - - reorder_module_pin_groups(all_wellformed_module_pin_groups); - -#ifdef PRINT_GENERAL - for (const auto& [mpg, bitorder] : all_wellformed_module_pin_groups) - { - auto m = mpg.first; - auto pg = mpg.second; - - std::cout << "Module: " << m->get_id() << " / " << m->get_name() << ": " << std::endl; - std::cout << "Pingroup: " << pg->get_name() << ": " << std::endl; - - for (const auto& [net, index] : bitorder) - { - std::cout << net->get_id() << ": " << index << std::endl; - } - } -#endif - - const u32 all_wellformed_bitorders_count = all_wellformed_module_pin_groups.size(); - const u32 new_bit_order_count = all_wellformed_bitorders_count - src.size(); - - log_info("bitorder_propagation", "With {} known bitorder, {} unknown bitorders got reconstructed.", src.size(), new_bit_order_count); - log_info("bitorder_propagation", "{} / {} = {} of all unknown bitorders.", new_bit_order_count, dst.size(), double(new_bit_order_count) / double(dst.size())); - log_info("bitorder_propagation", - "{} / {} = {} of all pin group bitorders.", - all_wellformed_bitorders_count, - dst.size() + src.size(), - double(all_wellformed_bitorders_count) / double(dst.size() + src.size())); - - return OK(all_wellformed_module_pin_groups); - } -} // namespace hal +} // namespace hal \ No newline at end of file diff --git a/plugins/gui/src/graph_widget/contexts/graph_context.cpp b/plugins/gui/src/graph_widget/contexts/graph_context.cpp index 4b9a7866b8c..552e72c8664 100644 --- a/plugins/gui/src/graph_widget/contexts/graph_context.cpp +++ b/plugins/gui/src/graph_widget/contexts/graph_context.cpp @@ -786,6 +786,12 @@ namespace hal } } + if (nodesToPlace.isEmpty()) + { + log_warning("gui", "Cannot restore view id={}, there are no nodes to place.", mId); + return false; + } + mModules.clear(); mGates.clear(); for (const QPair& box : nodesToPlace) diff --git a/plugins/gui/src/graph_widget/graph_context_manager.cpp b/plugins/gui/src/graph_widget/graph_context_manager.cpp index 2e7c97d34c2..54f1e6fef1b 100644 --- a/plugins/gui/src/graph_widget/graph_context_manager.cpp +++ b/plugins/gui/src/graph_widget/graph_context_manager.cpp @@ -685,9 +685,10 @@ namespace hal int visibleFlag = 1; // default to visible before flag was invented if (jsonView.contains("visible")) visibleFlag = jsonView["visible"].toInt(); + + u32 viewParentId = 0; if (!jsonView.contains("parentId")) - continue; - u32 viewParentId = jsonView["parentId"].toInt(); + viewParentId = jsonView["parentId"].toInt(); BaseTreeItem* viewParent = mContextTreeModel->getRootItem(); diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index d3493a7fc83..0d56740554c 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -669,6 +669,12 @@ namespace hal mCoordY[pnt.y()].testMinMax(rect.bottom()); } + // add topmost and leftmost coordinate entry (unless it already exists) + if (!mCoordX.contains(mNodeBoundingBox.left())) + mCoordX[mNodeBoundingBox.left()].testMinMax(0); + if (!mCoordY.contains(mNodeBoundingBox.top())) + mCoordY[mNodeBoundingBox.top()].testMinMax(0); + // fill gaps in coordinate system if any if (!mCoordX.isEmpty()) { diff --git a/plugins/gui/src/module_widget/module_widget.cpp b/plugins/gui/src/module_widget/module_widget.cpp index d86cb69af7b..59c93fb9795 100644 --- a/plugins/gui/src/module_widget/module_widget.cpp +++ b/plugins/gui/src/module_widget/module_widget.cpp @@ -350,7 +350,7 @@ namespace hal if (clicked == &extractPythonAction){ switch(type) { - case ModuleItem::TreeItemType::Module: QApplication::clipboard()->setText("netlist.get_Module_by_id(" + QString::number(getModuleItemFromIndex(index)->id()) + ")"); break; + case ModuleItem::TreeItemType::Module: QApplication::clipboard()->setText("netlist.get_module_by_id(" + QString::number(getModuleItemFromIndex(index)->id()) + ")"); break; case ModuleItem::TreeItemType::Gate: QApplication::clipboard()->setText("netlist.get_gate_by_id(" + QString::number(getModuleItemFromIndex(index)->id()) + ")"); break; case ModuleItem::TreeItemType::Net: QApplication::clipboard()->setText("netlist.get_net_by_id(" + QString::number(getModuleItemFromIndex(index)->id()) + ")"); break; }