diff --git a/CHANGELOG.md b/CHANGELOG.md index b5bc014f7c2..e150b7a3ac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,47 +4,57 @@ All notable changes to this project will be documented in this file. ## [Unreleased] * **WARNING:** this release breaks compatibility with Ubuntu 20.04 LTS * **WARNING:** this release breaks the API of the `graph_algorithm` plugin -* refactored module widget - * added option to show gate content for each module - * added option to show interior nets for each module - * added `Isolate in new view` feature for nets - * added button to expand or collapse all tree items - * added delete module action and shortcut - * added entries for context menu - * adapted appearance for menu content tree, selection details tree, grouping content tree (same model for all) -* refactored search bar - * changed appearance of search bar to be more intuitive - * added menu for extended options - e.g. option to search in selected columns only - * added search history - * added filter proxy class for trees and tables increasing the search performance -* refactored layouter module - * switched to multithreaded algorithm - * boosted performance by using classes with faster memory access - * removed layouter code used prior to version 3.1.0 - thus removing the setting option to use that code - * added setting option to dump junction layout input data for experts to debug in case of layout errors -* refactored `graph_algorithm` plugin - * updated the igraph dependency shipped with HAL - * changed the API and made everything accessible via Python - * graph corresponding to a netlist is now encapsulated within an `NetlistGraph` object that allows easy interaction with the graph - * added new functions for computing neighborhoods, shortest paths, subgraphs, and (strongly) connected components -* simulation - * added feature to VCD parser: removal of leading backslash and trailing whitespace from waveform name - * extended maximum line with the CSV parser can handle - * changed warning messages for waveform parsing and made them more specific - * changed policy toward 'dangling' wires, they are no longer ignored but considered as global inputs or outputs -* added `hawkeye` plugin for the detection of symmetric cryptographic implementations in gate-level netlists - * see publication `HAWKEYE - Recovering Symmetric Cryptography From Hardware Circuits` at CRYPTO'24 for details -* added `NetlistTraversalDecorator` to ease exploration of a netlist - * added `get_next_matching_gates` to get successor/predecessor gates matching a certain condition - * added `get_next_matching_gates_until` to get successor/predecessor gates until a certain condition is fulfilled - * added `get_next_matching_gates_until_depth` to get successor/predecessor gates up to a certain depth - * added `get_next_sequential_gates` and `get_next_sequential_gates_map` to get the next layer of sequential successors/predecessors - * added `get_next_combinational_gates` to get all combinational gates until the next non-combinational gates are reached -* module pins - * added qualifier for `pin_changed` core events telling receiver details about the recent modification - * added event scope and stacking classes so that `pin_changed` events can be collected and prioritized - * added specific GUI handler for every `pin_changed` event thus replacing the reload-entire-pingroup-tree policy - * added class `ActionPingroup` so that UNDO function works for all pin / pin group actions issued from GUI +* **WARNING:** this release breaks the API of the `dataflow_analysis` plugin +* GUI + * refactored module widget + * added option to show gate content for each module + * added option to show interior nets for each module + * added `Isolate in new view` feature for nets + * added button to expand or collapse all tree items + * added delete module action and shortcut + * added entries for context menu + * adapted appearance for menu content tree, selection details tree, grouping content tree (same model for all) + * refactored search bar + * changed appearance of search bar to be more intuitive + * added menu for extended options - e.g. option to search in selected columns only + * added search history + * added filter proxy class for trees and tables increasing the search performance + * refactored layouter module + * switched to multithreaded algorithm + * boosted performance by using classes with faster memory access + * removed layouter code used prior to version 3.1.0 - thus removing the setting option to use that code + * added setting option to dump junction layout input data for experts to debug in case of layout errors +* plugins + * added `hawkeye` plugin for the detection of symmetric cryptographic implementations in gate-level netlists + * see publication `HAWKEYE - Recovering Symmetric Cryptography From Hardware Circuits` at CRYPTO'24 for details + * changed `graph_algorithm` plugin + * updated the igraph dependency shipped with HAL + * graph corresponding to a netlist is now encapsulated within an `NetlistGraph` object that allows easy interaction with the graph + * added new functions for computing neighborhoods, shortest paths, subgraphs, and (strongly) connected components + * changed the API to facilitate for the aforementioned changes and made everything accessible via Python + * changed `dataflow_analysis` plugin + * can now operate on arbitrary, user-defined gate types, not only FFs + * user can now specify the pin types to be considered as control pins + * can now take known registers and other known word-level structures into account during analysis + * changed the API to facilitate for the aforementioned changes + * changed `simulator` plugin + * added feature to VCD parser: removal of leading backslash and trailing whitespace from waveform name + * extended maximum line with the CSV parser can handle + * changed warning messages for waveform parsing and made them more specific + * changed policy toward 'dangling' wires, they are no longer ignored but considered as global inputs or outputs +* netlist + * module pins + * added qualifier for `pin_changed` core events telling receiver details about the recent modification + * added event scope and stacking classes so that `pin_changed` events can be collected and prioritized + * added specific GUI handler for every `pin_changed` event thus replacing the reload-entire-pingroup-tree policy + * added class `ActionPingroup` so that UNDO function works for all pin / pin group actions issued from GUI +* decorators + * added `NetlistTraversalDecorator` to ease exploration of a netlist + * added `get_next_matching_gates` to get successor/predecessor gates matching a certain condition + * added `get_next_matching_gates_until` to get successor/predecessor gates until a certain condition is fulfilled + * added `get_next_matching_gates_until_depth` to get successor/predecessor gates up to a certain depth + * added `get_next_sequential_gates` and `get_next_sequential_gates_map` to get the next layer of sequential successors/predecessors + * added `get_next_combinational_gates` to get all combinational gates until the next non-combinational gates are reached * miscellaneous * added support for Ubuntu 24.04 LTS * added INIT field declaration to FF-gate-types in example library diff --git a/plugins/dataflow_analysis/documentation/dataflow.rst b/plugins/dataflow_analysis/documentation/dataflow.rst index a2cf8f91c2b..74b2779d820 100644 --- a/plugins/dataflow_analysis/documentation/dataflow.rst +++ b/plugins/dataflow_analysis/documentation/dataflow.rst @@ -1,16 +1,16 @@ Dataflow Analysis (DANA) ========================== -.. autoclass:: dataflow.DataflowPlugin - :members: +.. automodule:: dataflow + :members: analyze -.. autoclass:: dataflow.Dataflow.Configuration +.. autoclass:: dataflow.Configuration :members: .. automethod:: __init__ -.. autoclass:: dataflow.Dataflow.Result +.. autoclass:: dataflow.Result :members: -.. automodule:: dataflow.Dataflow - :members: analyze +.. autoclass:: dataflow.DataflowPlugin + :members: diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/api/configuration.h b/plugins/dataflow_analysis/include/dataflow_analysis/api/configuration.h index c8f61367595..4a8ced990cf 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/api/configuration.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/api/configuration.h @@ -23,10 +23,21 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +/** + * @file configuration.h + * @brief This file contains the struct that holds all information on a dataflow analysis configuration. + */ + #pragma once #include "hal_core/defines.h" +#include "hal_core/netlist/gate_library/enums/gate_type_property.h" +#include "hal_core/netlist/gate_library/enums/pin_type.h" +#include "hal_core/netlist/pins/module_pin.h" +#include "hal_core/netlist/pins/pin_group.h" +#include +#include #include namespace hal @@ -34,41 +45,74 @@ namespace hal class Gate; class Module; class Grouping; + class Netlist; + class Net; + class GateType; namespace dataflow { /** - * Holds the configuration of a dataflow analysis run. + * @struct Configuration + * @brief Configuration of a dataflow analysis run. + * + * This struct holds all information relevant for the configuration of a dataflow analysis run, including the netlist to analyze. */ struct Configuration { /** - * Minimum size of a group. Smaller groups will be penalized during analysis. Defaults to 8. + * @brief Construct a new dataflow analysis configuration for the given netlist. + * + * @param[in] nl - The netlist. + */ + Configuration(Netlist* nl); + + /** + * @brief The netlist to be analyzed. + */ + Netlist* netlist; + + /** + * @brief Minimum size of a group. Smaller groups will be penalized during analysis. Defaults to 8. */ u32 min_group_size = 8; /** - * Expected group sizes. Groups of these sizes will be prioritized. Defaults to an empty vector. + * @brief Expected group sizes. Groups of these sizes will be prioritized. Defaults to an empty vector. */ std::vector expected_sizes = {}; /** - * Already identified groups of sequential gates as a vector of groups with each group being a vector of gate IDs. Defaults to an empty vector. + * @brief Groups of gates that have already been identified as word-level groups beforehand. All gates of a group must be of one of the target gate types. Defaults to an empty vector. */ - std::vector> known_groups = {}; + std::vector> known_gate_groups = {}; /** - * Enable register stage identification as part of dataflow analysis. Defaults to `false`. + * @brief Groups of nets that have been identified as word-level datapathes beforehand. Defaults to an empty vector. */ - bool enable_register_stages = false; + std::vector> known_net_groups = {}; /** - * Enforce type consistency inside of a group. Defaults to `false`. + * @brief The gate types to be grouped by dataflow analysis. Defaults to an empty set. + */ + std::set gate_types = {}; + + /** + * @brief The pin types of the pins to be considered control pins. Defaults to an empty set. + */ + std::set control_pin_types = {}; + + /** + * @brief Enable stage identification as part of dataflow analysis. Defaults to `false`. + */ + bool enable_stages = false; + + /** + * @brief Enforce gate type consistency inside of a group. Defaults to `false`. */ bool enforce_type_consistency = false; /** - * Set the minimum size of a group. Smaller groups will be penalized during analysis. + * @brief Set the minimum size of a group. Smaller groups will be penalized during analysis. * * @param[in] size - The minimum group size. * @returns The updated dataflow analysis configuration. @@ -76,7 +120,7 @@ namespace hal Configuration& with_min_group_size(u32 size); /** - * Set the expected group sizes. Groups of these sizes will be prioritized. + * @brief Set the expected group sizes. Groups of these sizes will be prioritized. * * @param[in] sizes - The expected group sizes. * @returns The updated dataflow analysis configuration. @@ -84,47 +128,191 @@ namespace hal Configuration& with_expected_sizes(const std::vector& sizes); /** - * Set already identified groups of sequential gates as a vector of groups with each group being a module. + * @brief Add modules to the set of previously identified word-level structures. + * + * The gates contained in the modules do not have to be of the target gate types. + * The input and output pin groups of these modules will be used to guide datapath analysis. + * Only pin groups larger than `min_group_size´ will be considered. + * + * @param[in] structures - A vector of modules. + * @param[in] overwrite - Set `true` to overwrite the existing known word-level structures, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_structures(const std::vector& structures, bool overwrite = false); + + /** + * @brief Add modules to the set of previously identified word-level structures. + * + * The gates contained in the modules do not have to be of the target gate types. + * The input and output pin groups of these modules will be used to guide datapath analysis. + * For each module, the input and output pin groups to be considered for analysis must be specified. + * An empty pin group vector results in all pin groups of the module being considered. + * Only pin groups larger than `min_group_size´ will be considered. + * + * @param[in] structures - A vector of modules, each of them with a vector of module pin groups. + * @param[in] overwrite - Set `true` to overwrite the existing known word-level structures, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_structures(const std::vector*>>>& structures, bool overwrite = false); + + /** + * @brief Add (typically large) gates to the set of previously identified word-level structures. + * + * The gates do not have to be of the target gate types. + * The input and output pin groups of these gates will be used to guide datapath analysis. + * Only pin groups larger than `min_group_size´ will be considered. + * + * @param[in] structures - A vector of gates. + * @param[in] overwrite - Set `true` to overwrite the existing known word-level structures, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_structures(const std::vector& structures, bool overwrite = false); + + /** + * @brief Add (typically large) gates to the set of previously identified word-level structures. + * + * The gates do not have to be of the target gate types. + * The input and output pin groups of these gates will be used to guide datapath analysis. + * For each gate, the input and output pin groups to be considered for analysis must be specified. + * An empty pin group vector results in all pin groups of the gate being considered. + * Only pin groups larger than `min_group_size´ will be considered. + * + * @param[in] structures - A vector of gates, each of them with a vector of gate pin groups. + * @param[in] overwrite - Set `true` to overwrite the existing known word-level structures, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_structures(const std::vector*>>>& structures, bool overwrite = false); + + /** + * @brief Add all gates of a (typically large) gate type to the set of previously identified word-level structures. + * + * The gate types do not have to be part of the target gate types. + * The input and output pin groups of the gates of these types will be used to guide datapath analysis. + * Only pin groups larger than `min_group_size´ will be considered. + * + * @param[in] structures - A set of gate types. + * @param[in] overwrite - Set `true` to overwrite the existing known word-level structures, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_structures(const std::unordered_set& structures, bool overwrite = false); + + /** + * @brief Add all gates of a (typically large) gate type to the set of previously identified word-level structures. + * + * The gate types do not have to be part of the target gate types. + * The input and output pin groups of the gates of these types will be used to guide datapath analysis. + * For each gate type, the input and output pin groups to be considered for analysis must be specified. + * An empty pin group vector results in all pin groups of the gate type being considered. + * Only pin groups larger than `min_group_size´ will be considered. + * + * @param[in] structures - A map from gates to a vector of a subset of their pin groups. + * @param[in] overwrite - Set `true` to overwrite the existing known word-level structures, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_structures(const std::unordered_map*>>& structures, bool overwrite = false); + + /** + * @brief Add modules to the set of previously identified word-level groups. + * + * These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + * The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + * + * @param[in] groups - A vector of modules. + * @param[in] overwrite - Set `true` to overwrite the existing previously identified word-level groups, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_known_groups(const std::vector& groups, bool overwrite = false); + + /** + * @brief Add vectors of gates to the set of previously identified word-level groups. * - * @param[in] groups - A vector of groups. + * These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + * The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + * + * @param[in] groups - A vector of groups, each of them as a vector of gates. + * @param[in] overwrite - Set `true` to overwrite existing set of identified word-level structures, `false` otherwise. Defaults to `false`. * @returns The updated dataflow analysis configuration. */ - Configuration& with_known_groups(const std::vector& groups); + Configuration& with_known_groups(const std::vector>& groups, bool overwrite = false); /** - * Set already identified groups of sequential gates as a vector of groups with each group being a grouping. + * @brief Add vectors of gate IDs to the set of previously identified word-level groups. * - * @param[in] groups - A vector of groups. + * These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + * The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + * + * @param[in] groups - A vector of groups, each of them given as a vector of gate IDs. + * @param[in] overwrite - Set `true` to overwrite existing set of identified word-level structures, `false` otherwise. Defaults to `false`. * @returns The updated dataflow analysis configuration. */ - Configuration& with_known_groups(const std::vector& groups); + Configuration& with_known_groups(const std::vector>& groups, bool overwrite = false); /** - * Set already identified groups of sequential gates as a vector of groups with each group being a vector of gates. + * @brief Add groups from a previous dataflow analysis run to the set of previously identified word-level groups. * - * @param[in] groups - A vector of groups. + * These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + * The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + * The group IDs will be ignored during analysis and the same group may be assigned a new ID. + * + * @param[in] groups - A map from group IDs to groups, each of them given as a set of gates. + * @param[in] overwrite - Set `true` to overwrite existing set of identified word-level structures, `false` otherwise. Defaults to `false`. * @returns The updated dataflow analysis configuration. */ - Configuration& with_known_groups(const std::vector>& groups); + Configuration& with_known_groups(const std::unordered_map>& groups, bool overwrite = false); /** - * Set already identified groups of sequential gates as a vector of groups with each group being a vector of gate IDs. + * @brief Add the gate types to the set of gate types to be grouped by dataflow analysis. + * + * Overwrite the existing set of gate types by setting the optional `overwrite` flag to `true`. + * + * @param[in] types - A set of gate types. + * @param[in] overwrite - Set `true` to overwrite existing set of gate types, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_gate_types(const std::set& types, bool overwrite = false); + + /** + * @brief Add the gate types featuring the specified properties to the set of gate types to be grouped by dataflow analysis. + * + * Overwrite the existing set of gate types by setting the optional `overwrite` flag to `true`. + * + * @param[in] type_properties - A set of gate type properties. + * @param[in] overwrite - Set `true` to overwrite existing set of gate types, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_gate_types(const std::set& type_properties, bool overwrite = false); + + /** + * @brief Set the pin types of the pins to be considered control pins by dataflow analysis. + * + * Overwrite the existing set of pin types by setting the optional `overwrite` flag to `true`. + * + * @param[in] types - A set of pin types. + * @param[in] overwrite - Set `true` to overwrite existing set of pin types, `false` otherwise. Defaults to `false`. + * @returns The updated dataflow analysis configuration. + */ + Configuration& with_control_pin_types(const std::set& types, bool overwrite = false); + + /** + * @brief Use the default detection configuration for flip-flops. + * + * Includes all flip-flop types as target gate types and sets `clock`, `enable`, `set`, and `reset` pins as control pins. + * Overwrites any existing gate type and control pin configuration. * - * @param[in] groups - A vector of group. * @returns The updated dataflow analysis configuration. */ - Configuration& with_known_groups(const std::vector>& groups); + Configuration& with_flip_flops(); /** - * Enable register stage identification as part of dataflow analysis. + * @brief Enable stage identification as part of dataflow analysis. * - * @param[in] enable - Set `true` to enable register stage identification, `false` otherwise. Defaults to `true`. + * @param[in] enable - Set `true` to enable stage identification, `false` otherwise. Defaults to `true`. * @returns The updated dataflow analysis configuration. */ - Configuration& with_register_stage_identification(bool enable = true); + Configuration& with_stage_identification(bool enable = true); /** - * Enable type consistency as part of dataflow analysis when deciding whether two gates are allowed to merge into the same group. + * @brief Enable type consistency as part of dataflow analysis when deciding whether two gates are allowed to merge into the same group. * * @param[in] enable - Set `true` to enable type consistency inside of a group, `false` otherwise. Defaults to `true`. * @returns The updated dataflow analysis configuration. diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/api/dataflow.h b/plugins/dataflow_analysis/include/dataflow_analysis/api/dataflow.h index 72f267a1303..8e9fbcb384c 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/api/dataflow.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/api/dataflow.h @@ -23,6 +23,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +/** + * @file dataflow.h + * @brief This file contains the function that analyses the dataflow of a gate-level netlist. + */ + #pragma once #include "dataflow_analysis/api/configuration.h" @@ -39,12 +44,14 @@ namespace hal namespace dataflow { /** - * Analyze the datapath to identify word-level registers in the given netlist. + * @brief Analyze the gate-level netlist to identify word-level registers. + * + * Reconstructs registers based on properties such as the control inputs of, e.g., their flip-flops and common successors/predecessors. + * Operates on an abstraction of the netlist that, e.g., contains only flip-flops and connections between two flip-flops only if they are connected through combinational logic. * - * @param[in] nl - The netlist. * @param[in] config - The dataflow analysis configuration. * @returns Ok() and the dataflow analysis result on success, an error otherwise. */ - hal::Result analyze(Netlist* nl, const Configuration& config = Configuration()); + hal::Result analyze(const Configuration& config); } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/api/result.h b/plugins/dataflow_analysis/include/dataflow_analysis/api/result.h index 35cd0f6c9fa..8da81fa1093 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/api/result.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/api/result.h @@ -23,9 +23,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +/** + * @file result.h + * @brief This file contains the struct that holds all information on the result of a dataflow analysis run. + */ + #pragma once #include "dataflow_analysis/common/grouping.h" +#include "hal_core/netlist/gate_library/enums/gate_type_property.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/result.h" @@ -34,39 +41,46 @@ namespace hal class Gate; class Net; class Module; + class GateType; namespace dataflow { /** - * The result of a dataflow analysis run containing the identified groups of sequential gates and their interconnections. + * @class Result + * @brief Result of a dataflow analysis run. + * + * This class holds result of a dataflow analysis run, which contains the identified groups of sequential gates and their interconnections. + * Each such group is assigned a unique ID by which it can be addressed in many of the member functions of this class. + * Please note that this ID is not related to any other HAL ID. */ - struct Result + class Result { + public: Result(Netlist* nl, const Grouping& grouping); /** - * Get the netlist on which dataflow analysis has been performed. + * @brief Get the netlist on which dataflow analysis has been performed. * * @returns The netlist. */ Netlist* get_netlist() const; /** - * Get the groups of sequential gates resulting from dataflow analysis. + * @brief Get the groups of sequential gates resulting from dataflow analysis. * * @returns A map from group ID to a set of gates belonging to the respective group. */ const std::unordered_map>& get_groups() const; /** - * Get all gates contained in any of the groups groups. + * @brief Get all gates contained in any of the groups groups. * * @returns A vector of gates. */ std::vector get_gates() const; /** - * Get the gates of the specified group of sequential gates. + * @brief Get the gates of the specified group of sequential gates. * * @param[in] group_id - The ID of the group. * @returns Ok() and the gates of the group as a set on success, an error otherwise. @@ -74,7 +88,7 @@ namespace hal hal::Result> get_gates_of_group(const u32 group_id) const; /** - * Get the group ID of the group that contains the given gate. + * @brief Get the group ID of the group that contains the given gate. * * @param[in] gate - The gate. * @returns Ok() and the group ID on success, an error otherwise. @@ -82,7 +96,7 @@ namespace hal hal::Result get_group_id_of_gate(const Gate* gate) const; /** - * Get the control nets of the group with the given group ID that are connected to a pin of the specified type. + * @brief Get the control nets of the group with the given group ID that are connected to a pin of the specified type. * * @param[in] group_id - The group ID. * @param[in] type - The pin type. @@ -91,7 +105,7 @@ namespace hal hal::Result> get_group_control_nets(const u32 group_id, const PinType type) const; /** - * Get the control nets of the given gate that are connected to a pin of the specified type. + * @brief Get the control nets of the given gate that are connected to a pin of the specified type. * * @param[in] gate - The gate. * @param[in] type - The pin type. @@ -100,7 +114,7 @@ namespace hal hal::Result> get_gate_control_nets(const Gate* gate, const PinType type) const; /** - * Get the successor groups of the group with the given ID. + * @brief Get the successor groups of the group with the given ID. * * @param[in] group_id - The group ID. * @returns Ok() and the successors of the group as a set of group IDs on success, an error otherwise. @@ -108,7 +122,7 @@ namespace hal hal::Result> get_group_successors(const u32 group_id) const; /** - * Get the sequential successor gates of the given sequential gate. + * @brief Get the sequential successor gates of the given sequential gate. * * @param[in] gate - The gate. * @returns Ok() and the successors of the gate as a set of gates on success, an error otherwise. @@ -116,7 +130,7 @@ namespace hal hal::Result> get_gate_successors(const Gate* gate) const; /** - * Get the predecessor groups of the group with the given ID. + * @brief Get the predecessor groups of the group with the given ID. * * @param[in] group_id - The group ID. * @returns Ok() and the predecessors of the group as a set of group IDs on success, an error otherwise. @@ -124,7 +138,7 @@ namespace hal hal::Result> get_group_predecessors(const u32 group_id) const; /** - * Get the sequential predecessor gates of the given sequential gate. + * @brief Get the sequential predecessor gates of the given sequential gate. * * @param[in] gate - The gate. * @returns Ok() and the predecessors of the gate as a set of gates on success, an error otherwise. @@ -132,7 +146,7 @@ namespace hal hal::Result> get_gate_predecessors(const Gate* gate) const; /** - * Write the dataflow graph as a DOT graph to the specified location. + * @brief Write the dataflow graph as a DOT graph to the specified location. * * @param[in] out_path - The output path. * @param[in] group_ids - The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. @@ -141,7 +155,7 @@ namespace hal hal::Result write_dot(const std::filesystem::path& out_path, const std::unordered_set& group_ids = {}) const; /** - * Write the groups resulting from dataflow analysis to a `.txt` file. + * @brief Write the groups resulting from dataflow analysis to a `.txt` file. * * @param[in] out_path - The output path. * @param[in] group_ids - The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. @@ -150,15 +164,35 @@ namespace hal hal::Result write_txt(const std::filesystem::path& out_path, const std::unordered_set& group_ids = {}) const; /** - * Create modules for the dataflow analysis result. + * @brief Create modules for the dataflow analysis result. + * + * Please note that the IDs of the module are assigned independent of the group IDs of the register groups. + * + * @param[in] module_suffixes - The suffixes to use for modules containing only gates of a specific gate type. Defaults to `"module"` for mixed and unspecified gate types. + * @param[in] pin_prefixes - The prefixes to use for the module pins that (within the module) only connect to gate pins of a specific name. Defaults to the gate pin name. + * @param[in] group_ids - The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. + * @returns Ok() and a map from group IDs to Modules on success, an error otherwise. + */ + hal::Result> create_modules(const std::map& module_suffixes = {}, + const std::map, std::string>& pin_prefixes = {}, + const std::unordered_set& group_ids = {}) const; + + /** + * @brief Create modules for the dataflow analysis result. + * + * Please note that the IDs of the module are assigned independent of the group IDs of the register groups. * + * @param[in] module_suffixes - The suffixes to use for modules containing only gates of a specific gate type. All gate types featuring the specified gate type property are considered, but the module must still be pure (i.e., all gates must be of the same type) for the suffix to be used. Defaults to `"module"` for mixed and unspecified gate types. + * @param[in] pin_prefixes - The prefixes to use for the module pins that (within the module) only connect to gate pins of a specific name. Defaults to the gate pin name. * @param[in] group_ids - The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. * @returns Ok() and a map from group IDs to Modules on success, an error otherwise. */ - hal::Result> create_modules(const std::unordered_set& group_ids = {}) const; + hal::Result> create_modules(const std::map& module_suffixes, + const std::map, std::string>& pin_prefixes = {}, + const std::unordered_set& group_ids = {}) const; /** - * Get the groups of the dataflow analysis result as a list. + * @brief Get the groups of the dataflow analysis result as a list. * * @param[in] group_ids - The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. * @returns A vector of groups with each group being a vector of gates. @@ -166,16 +200,18 @@ namespace hal std::vector> get_groups_as_list(const std::unordered_set& group_ids = {}) const; /** - * Merge multiple groups specified by ID. + * @brief Merge multiple groups specified by ID. + * * All specified groups are merged into the first group of the provided vector and are subsequently deleted. * * @param[in] group_ids - The group IDs of the groups to merge. - * @returns The ID of the group that all over groups have been merged into on success, an error otherwise. + * @returns The ID of the group that all other groups have been merged into on success, an error otherwise. */ hal::Result merge_groups(const std::vector& group_ids); /** - * Split a group into multiple smaller groups specified by sets of gates. + * @brief Split a group into multiple smaller groups specified by sets of gates. + * * All gates of the group to split must be contained in the sets exactly once and all gates in the sets must be contained in the group to split. * The group that is being split is deleted in the process. * @@ -186,21 +222,54 @@ namespace hal hal::Result> split_group(u32 group_id, const std::vector>& new_groups); private: + /** + * The associated netlist. + */ Netlist* m_netlist; + /** + * The last assigned group ID. + */ u32 m_last_id = 0; + /** + * A map from group IDs to all gates contained within each of the groups. + */ std::unordered_map> m_gates_of_group; + + /** + * A group from gates to the group ID of the group they are contained in. + */ std::unordered_map m_parent_group_of_gate; - // gate information + /** + * A map that (for each gate) holds all nets connected to the pins of any given type. + */ std::unordered_map>> m_gate_signals; + + /** + * The successor gates of a gate within the netlist abstraction on which analysis was performed. + */ std::unordered_map> m_gate_successors; + + /** + * The predecessor gates of a within the netlist abstraction on which analysis was performed. + */ std::unordered_map> m_gate_predecessors; - // group information + /** + * A map that (for each group) holds all nets connected to the pins of any given type. + */ std::unordered_map>> m_group_signals; + + /** + * The successor groups of a group. + */ std::unordered_map> m_group_successors; + + /** + * The predecessor groups of a group. + */ std::unordered_map> m_group_predecessors; }; } // namespace dataflow diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/common/grouping.h b/plugins/dataflow_analysis/include/dataflow_analysis/common/grouping.h index 97deead3e00..3c98fa438d4 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/common/grouping.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/common/grouping.h @@ -23,6 +23,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +/** + * @file grouping.h + * @brief This file contains the class that holds all information of a dataflow analysis grouping. + */ + #pragma once #include "dataflow_analysis/common/netlist_abstraction.h" @@ -39,34 +44,148 @@ namespace hal { namespace dataflow { + /** + * @class Grouping + * @brief Grouping used during dataflow analysis. + * + * This class provides access to all information related to a grouping as an (intermediate) product of dataflow analysis. + * Each grouping is a collection of groups of, e.g., flip-flops that result from different paths that have been executed on a previous grouping. + */ struct Grouping { + /** + * @brief Construct a new (empty) grouping from a netlist abstraction. + * + * @param[in] na - The netlist abstraction. + */ Grouping(const NetlistAbstraction& na); - Grouping(const NetlistAbstraction& na, const std::vector>& groups); + + /** + * @brief Construct a new grouping from a netlist abstraction and a vector of groups (as a vector of gates). + * + * @param[in] na - The netlist abstraction. + * @param[in] groups - A vector of groups. + */ + Grouping(const NetlistAbstraction& na, const std::vector>& groups); + + /** + * @brief Construct a new grouping as a copy of an existing grouping. + */ Grouping(const Grouping& other); + /** + * The netlist abstraction associated with the grouping. + */ const NetlistAbstraction& netlist_abstr; + /** + * A map from group the an ordered list of control net IDs. + */ std::unordered_map> group_control_fingerprint_map; + /** + * A map from group to all gates contained in the group. + */ std::unordered_map> gates_of_group; + + /** + * A map from gate ID to the group that this gate belongs to. + */ std::unordered_map parent_group_of_gate; + + /** + * A map from a group to a flag that determines whether operations on the group are allowed. + */ std::map operations_on_group_allowed; + /** + * @brief Check two groupings for equality. + * + * Two groupings are equal if the comprise the same number of groups and if these groups are made up from the same gates. + * + * @param[in] other - The other grouping. + * @return `true` if the groupings are equal, `false` otherwise. + */ bool operator==(const Grouping& other) const; + + /** + * @brief Check two groupings for inequality. + * + * Two groupings are equal if the comprise the same number of groups and if these groups are made up from the same gates. + * + * @param[in] other - The other grouping. + * @return `true` if the groupings are unequal, `false` otherwise. + */ bool operator!=(const Grouping& other) const; - std::unordered_set get_clock_signals_of_group(u32 group_id) const; - std::unordered_set get_control_signals_of_group(u32 group_id) const; - std::unordered_set get_reset_signals_of_group(u32 group_id) const; - std::unordered_set get_set_signals_of_group(u32 group_id) const; + /** + * @brief Get the control signals of a group as a map from the control pin type to the connected net IDs. + * + * @param[in] group_id - The ID of the group. + * @returns The group's control signals. + */ + std::map> get_control_signals_of_group(u32 group_id) const; + /** + * @brief Get the successor groups of a group. + * + * @param[in] group_id - The ID of the group. + * @returns The group's successor groups. + */ std::unordered_set get_successor_groups_of_group(u32 group_id) const; + + /** + * @brief Get the predecessor groups of a group. + * + * @param[in] group_id - The ID of the group. + * @returns The group's predecessor groups. + */ std::unordered_set get_predecessor_groups_of_group(u32 group_id) const; + /** + * @brief Get the known successor groups of a group. + * + * The known groups have initially been fed to the dataflow analysis by the user. + * + * @param[in] group_id - The ID of the group. + * @returns The group's known successor groups. + */ + std::unordered_set get_known_successor_groups_of_group(u32 group_id) const; + + /** + * @brief Get the known predecessor groups of a group. + * + * The known groups have initially been fed to the dataflow analysis by the user. + * + * @param[in] group_id - The ID of the group. + * @returns The group's known predecessor groups. + */ + std::unordered_set get_known_predecessor_groups_of_group(u32 group_id) const; + + /** + * @brief Get the intersection of the register stages of all gates of the group. + * + * @param[in] group_id - The ID of the group. + * @returns The register stage intersection of all gates of the group. + */ std::set get_register_stage_intersect_of_group(u32 group_id) const; + /** + * @brief Check if two groups are allowed to be merged. + * + * @param[in] group_1_id - The ID of the first group. + * @param[in] group_2_id - The ID of the second group. + * @param[in] enforce_type_consistency - Set `true` to enforce that the gates of both groups must be of the same type, `false` otherwise. + * @returns `true` if the groups are allowed to be joined, `false` otherwise. + */ bool are_groups_allowed_to_merge(u32 group_1_id, u32 group_2_id, bool enforce_type_consistency) const; + + /** + * @brief Check if the group is allowed to be split. + * + * @param[in] group_id - The ID of the group. + * @returns `true` if the group is allowed to be split, `false` otherwise. + */ bool is_group_allowed_to_split(u32 group_id) const; private: @@ -76,6 +195,8 @@ namespace hal std::shared_mutex mutex; std::unordered_map> suc_cache; std::unordered_map> pred_cache; + std::unordered_map> suc_known_group_cache; + std::unordered_map> pred_known_group_cache; std::set> comparison_cache; } cache; diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/common/netlist_abstraction.h b/plugins/dataflow_analysis/include/dataflow_analysis/common/netlist_abstraction.h index 42fc8932e63..bef83d73ec7 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/common/netlist_abstraction.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/common/netlist_abstraction.h @@ -23,9 +23,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +/** + * @file netlist_abstraction.h + * @brief This file contains the struct that holds all information on the netlist abstraction used for dataflow analysis. + */ + #pragma once #include "hal_core/defines.h" +#include "hal_core/netlist/gate_library/enums/pin_type.h" #include #include @@ -42,28 +48,40 @@ namespace hal { struct Grouping; + /** + * @struct NetlistAbstraction + * @brief The abstraction of the netlist that only contains gates of a specified type, e.g., flip-flops. + */ struct NetlistAbstraction { + /** + * @brief Construct a netlist abstraction from a netlist. + * + * @param[in] nl_arg - The netlist. + */ NetlistAbstraction(const Netlist* nl_arg); - // netlist + /** + * The netlist associated with the netlist abstraction. + */ const Netlist* nl; // utils bool yosys; - // all ffs - std::vector all_sequential_gates; + /** + * The target gates that should be grouped by dataflow analysis. + */ + std::vector target_gates; /* pre_processed_data */ std::unordered_map> gate_to_fingerprint; - std::unordered_map> gate_to_clock_signals; - std::unordered_map> gate_to_enable_signals; - std::unordered_map> gate_to_reset_signals; - std::unordered_map> gate_to_set_signals; + std::unordered_map>> gate_to_control_signals; std::unordered_map> gate_to_register_stages; std::unordered_map> gate_to_predecessors; std::unordered_map> gate_to_successors; + std::unordered_map> gate_to_known_predecessor_groups; + std::unordered_map> gate_to_known_successor_groups; std::unordered_map>> gate_to_output_shape; std::unordered_map>> gate_to_input_shape; }; diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/plugin_dataflow.h b/plugins/dataflow_analysis/include/dataflow_analysis/plugin_dataflow.h index f7e2d8ed284..20ad0529193 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/plugin_dataflow.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/plugin_dataflow.h @@ -38,7 +38,7 @@ namespace hal class Netlist; class Gate; - class plugin_dataflow; + class DataflowPlugin; class CliExtensionDataflow : public CliExtensionInterface { @@ -52,31 +52,47 @@ namespace hal class GuiExtensionDataflow : public GuiExtensionInterface { - dataflow::Configuration m_config; - std::string m_output_path; - bool m_write_dot; - bool m_write_txt; - bool m_create_modules; - bool m_button_clicked; + std::string m_output_path = "/tmp"; + bool m_write_dot = false; + bool m_write_txt = false; + bool m_create_modules = false; + bool m_button_clicked = false; + + std::vector m_expected_sizes = {}; + u32 m_min_group_size = 8; + bool m_enable_stages = false; public: - GuiExtensionDataflow() : m_output_path("/tmp"), m_write_dot(false), m_write_txt(false), m_create_modules(false), m_button_clicked(false) - { - } + /** + * @brief Default constructor for `GuiExtensionDataflow`. + */ + GuiExtensionDataflow() = default; /** - * Get list of configurable parameter + * @brief Get a vector of configurable parameters. * - * @returns list of parameter + * @returns The vector of parameters. */ std::vector get_parameter() const override; /** - * Set configurable parameter to values - * @param params The parameter with values + * @brief Set values for a vector of configurable parameters. + * + * @param[in] params - The parameters including their values. */ void set_parameter(const std::vector& params) override; + /** + * @brief Execute the plugin on the given netlist. + * + * All parameters but the netlist are ignored. + * + * @param[in] tag - A tag (ignored). + * @param[in] nl - The netlist to operate on. + * @param[in] mods - Module IDs (ignored). + * @param[in] gats - Gate IDs (ignored). + * @param[in] nets - Net IDs (ignored). + */ void execute_function(std::string tag, Netlist* nl, const std::vector& mods, const std::vector& gats, const std::vector& nets) override; /** @@ -88,47 +104,51 @@ namespace hal static std::function s_progress_indicator_function; }; - class PLUGIN_API plugin_dataflow : public BasePluginInterface + /** + * @class DataflowPlugin + * @brief Plugin interface for the dataflow analysis plugin (DANA). + * + * This class provides an interface to integrate the DANA tool as a plugin within the HAL framework. + */ + class PLUGIN_API DataflowPlugin : public BasePluginInterface { public: - /* - * interface implementations + /** + * @brief Constructor for `DataflowPlugin`. */ + DataflowPlugin(); - plugin_dataflow(); - ~plugin_dataflow() = default; + /** + * @brief Default destructor for `DataflowPlugin`. + */ + ~DataflowPlugin() = default; /** - * Get the name of the plugin. + * @brief Get the name of the plugin. * * @returns The name of the plugin. */ std::string get_name() const override; /** - * Get short description for plugin. + * @brief Get the version of the plugin. * - * @return The short description. + * @returns The version of the plugin. */ - std::string get_description() const override; + std::string get_version() const override; /** - * Get the version of the plugin. + * @brief Get a short description of the plugin. * - * @returns The version of the plugin. + * @return The short description of the plugin. */ - std::string get_version() const override; + std::string get_description() const override; /** - * \deprecated + * @brief Get the plugin dependencies. + * + * @returns A set of plugin names that this plugin depends on. */ - [[deprecated("Will be removed in a future version, use dataflow::analyze instead.")]] std::vector> execute(Netlist* nl, - std::string out_path, - const std::vector sizes, - bool draw_graph, - bool create_modules = false, - bool register_stage_identification = false, - std::vector> known_groups = {}, - u32 min_group_size = 8); + std::set get_dependencies() const override; }; } // namespace hal diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/pre_processing/pre_processing.h b/plugins/dataflow_analysis/include/dataflow_analysis/pre_processing/pre_processing.h index d07dc7d7d64..5df73b17b9d 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/pre_processing/pre_processing.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/pre_processing/pre_processing.h @@ -25,6 +25,7 @@ #pragma once +#include "dataflow_analysis/api/configuration.h" #include "dataflow_analysis/common/netlist_abstraction.h" namespace hal @@ -35,7 +36,7 @@ namespace hal { namespace pre_processing { - NetlistAbstraction run(Netlist* netlist, bool register_stage_identification); + NetlistAbstraction run(const dataflow::Configuration& config, std::shared_ptr& initial_grouping); } // namespace pre_processing - } // namespace dataflow + } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/processing/configuration.h b/plugins/dataflow_analysis/include/dataflow_analysis/processing/configuration.h index c5a013520f5..45275fc3bb7 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/processing/configuration.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/processing/configuration.h @@ -39,8 +39,9 @@ namespace hal u32 num_threads; bool enforce_type_consistency; + bool has_known_groups = false; }; } // namespace processing - } // namespace dataflow -} \ No newline at end of file + } // namespace dataflow +} // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/processing/pass_collection.h b/plugins/dataflow_analysis/include/dataflow_analysis/processing/pass_collection.h index cd15934e7e5..46601ce72a6 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/processing/pass_collection.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/processing/pass_collection.h @@ -54,8 +54,9 @@ namespace hal namespace pass_collection { std::vector get_passes(const Configuration& config, const std::vector>& previous_passes); + void clear(); } // namespace pass_collection - } // namespace processing - } // namespace dataflow + } // namespace processing + } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_control_signals.h b/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_control_signals.h index d1856980102..9a42d8b84ce 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_control_signals.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_control_signals.h @@ -41,10 +41,7 @@ namespace hal namespace group_by_control_signals { - std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state, bool clock, bool clock_enable, bool reset, bool set); - std::shared_ptr - pure_control_signals_process(const processing::Configuration& config, const std::shared_ptr& state, bool clock, bool clock_enable, bool reset, bool set); - + std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state); } // namespace group_by_control_signals - } // namespace dataflow + } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_successor_predecessor_known_groups.h b/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_successor_predecessor_known_groups.h new file mode 100644 index 00000000000..2d821388165 --- /dev/null +++ b/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/group_by_successor_predecessor_known_groups.h @@ -0,0 +1,48 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" + +namespace hal +{ + namespace dataflow + { + /* forward declaration */ + struct Grouping; + + namespace processing + { + struct Configuration; + } + + namespace group_by_successor_predecessor_known_groups + { + std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state, bool successors); + + } // namespace group_by_successor_predecessor_known_groups + } // namespace dataflow +} // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/split_by_successor_predecessor_known_groups.h b/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/split_by_successor_predecessor_known_groups.h new file mode 100644 index 00000000000..892c2c00f4f --- /dev/null +++ b/plugins/dataflow_analysis/include/dataflow_analysis/processing/passes/split_by_successor_predecessor_known_groups.h @@ -0,0 +1,48 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" + +namespace hal +{ + namespace dataflow + { + /* forward declaration */ + struct Grouping; + + namespace processing + { + struct Configuration; + } + + namespace split_by_successor_predecessor_known_groups + { + std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state, bool successors); + + } // namespace split_by_successor_predecessor_known_groups + } // namespace dataflow +} \ No newline at end of file diff --git a/plugins/dataflow_analysis/include/dataflow_analysis/processing/processing.h b/plugins/dataflow_analysis/include/dataflow_analysis/processing/processing.h index 4858c674c13..8b87d6addb7 100644 --- a/plugins/dataflow_analysis/include/dataflow_analysis/processing/processing.h +++ b/plugins/dataflow_analysis/include/dataflow_analysis/processing/processing.h @@ -1,20 +1,20 @@ // 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 @@ -37,6 +37,7 @@ namespace hal namespace processing { processing::Result run(const processing::Configuration& config, const std::shared_ptr& initial_grouping); + void clear(); } // namespace processing - } // namespace dataflow + } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/python/python_bindings.cpp b/plugins/dataflow_analysis/python/python_bindings.cpp index d24139945cb..e1cd215082f 100644 --- a/plugins/dataflow_analysis/python/python_bindings.cpp +++ b/plugins/dataflow_analysis/python/python_bindings.cpp @@ -12,67 +12,62 @@ namespace hal #ifdef PYBIND11_MODULE PYBIND11_MODULE(dataflow, m) { - m.doc() = "hal DataflowPlugin python bindings"; + m.doc() = "Dataflow analysis tool DANA to recover word-level structures such as registers from gate-level netlists."; #else PYBIND11_PLUGIN(dataflow) { - py::module m("dataflow", "hal DataflowPlugin python bindings"); + py::module m("dataflow", "Dataflow analysis tool DANA to recover word-level structures such as registers from gate-level netlists."); #endif // ifdef PYBIND11_MODULE - py::class_, BasePluginInterface>(m, "DataflowPlugin") - .def_property_readonly("name", &plugin_dataflow::get_name, R"( - The name of the plugin. - - :type: str - )") - .def("get_name", &plugin_dataflow::get_name, R"( - Get the name of the plugin. - - :returns: Plugin name. - :rtype: str - )") - .def_property_readonly("version", &plugin_dataflow::get_version, R"( - The version of the plugin. - - :type: str - )") - .def("get_version", &plugin_dataflow::get_version, R"( - Get the version of the plugin. - - :returns: Plugin version. - :rtype: str - )") - .def("execute", - &plugin_dataflow::execute, - py::arg("netlist"), - py::arg("output_path"), - py::arg("sizes"), - py::arg("draw_graph") = false, - py::arg("create_modules") = false, - py::arg("register_stage_identification") = false, - py::arg("known_groups") = std::vector>(), - py::arg("min_group_size") = 8, - R"( - Executes the dataflow analysis plugin (DANA). Starting from the netlist DANA tries to identify high-level registers. - - :param hal_py.Netlist netlist: The netlist to operate on. - :param str output_path: Path where the dataflow graph should be written to - :param list[int] sizes: Prioritized sizes. - :param bool draw_graph: Switch to turn on/off the generation of the graph. - :param bool create_modules: Switch to turn on/off the creation of HAL modules for the registers. - :param bool register_stage_identification: Switch to turn on/off the register stage rule. Note that this rule can be too restrictive and is turned off by default. - :param list[list[int]] known_groups: Previously known groups that stay untouched. - :returns: Register groups created by DANA - :rtype: list[list[hal_py.Gate]] - )"); - - auto py_dataflow = m.def_submodule("Dataflow"); - - py::class_> py_dataflow_configuration(py_dataflow, "Configuration", R"( - Holds the configuration of a dataflow analysis run. - )"); - - py_dataflow_configuration.def(py::init<>(), R"( - Constructs a new dataflow analysis configuration. + py::class_, BasePluginInterface> py_dataflow_plugin( + m, "DataflowPlugin", R"(This class provides an interface to integrate the DANA tool as a plugin within the HAL framework.)"); + + py_dataflow_plugin.def_property_readonly("name", &DataflowPlugin::get_name, R"( + The name of the plugin. + + :type: str + )"); + + py_dataflow_plugin.def("get_name", &DataflowPlugin::get_name, R"( + Get the name of the plugin. + + :returns: The name of the plugin. + :rtype: str + )"); + + py_dataflow_plugin.def_property_readonly("description", &DataflowPlugin::get_description, R"( + The short description of the plugin. + + :type: str + )"); + + py_dataflow_plugin.def("get_description", &DataflowPlugin::get_description, R"( + Get the short description of the plugin. + + :returns: The short description of the plugin. + :rtype: str + )"); + + py_dataflow_plugin.def_property_readonly("version", &DataflowPlugin::get_version, R"( + The version of the plugin. + + :type: str + )"); + + py_dataflow_plugin.def("get_version", &DataflowPlugin::get_version, R"( + Get the version of the plugin. + + :returns: The version of the plugin. + :rtype: str + )"); + + py::class_> py_dataflow_configuration(m, "Configuration", R"( + This class holds all information relevant for the configuration of a dataflow analysis run, including the netlist to analyze. + )"); + + py_dataflow_configuration.def(py::init(), py::arg("nl"), R"( + Construct a new dataflow analysis configuration for the given netlist. + + :param hal_py.Netlist nl: The netlist. )"); py_dataflow_configuration.def_readwrite("min_group_size", &dataflow::Configuration::min_group_size, R"( @@ -87,18 +82,38 @@ namespace hal :type: list[int] )"); - py_dataflow_configuration.def_readwrite("known_groups", &dataflow::Configuration::known_groups, R"( - Already identified groups of sequential gates as a list of groups with each group being a list of gate IDs. Defaults to an empty list. + py_dataflow_configuration.def_readwrite("known_gate_groups", &dataflow::Configuration::known_gate_groups, R"( + Groups of gates that have already been identified as word-level groups beforehand. All gates of a group must be of one of the target gate types. Defaults to an empty list. - :type: list[list[int]] + :type: list[list[hal_py.Gate]] )"); - py_dataflow_configuration.def_readwrite("enable_register_stages", &dataflow::Configuration::enable_register_stages, R"( - Enable register stage identification as part of dataflow analysis. Defaults to ``False``. + py_dataflow_configuration.def_readwrite("known_net_groups", &dataflow::Configuration::known_net_groups, R"( + Groups of nets that have been identified as word-level datapathes beforehand. Defaults to an empty list. + :type: list[list[hal_py.Net]] + )"); + + py_dataflow_configuration.def_readwrite("gate_types", &dataflow::Configuration::gate_types, R"( + The gate types to be grouped by dataflow analysis. Defaults to an empty set. + :type: set[hal_py.GateType] + )"); + + py_dataflow_configuration.def_readwrite("control_pin_types", &dataflow::Configuration::control_pin_types, R"( + The pin types of the pins to be considered control pins. Defaults to an empty set. + :type: set[hal_py.PinType] + )"); + + py_dataflow_configuration.def_readwrite("enable_stages", &dataflow::Configuration::enable_stages, R"( + Enable stage identification as part of dataflow analysis. Defaults to ``False``. :type: bool )"); + py_dataflow_configuration.def_readwrite("enforce_type_consistency", &dataflow::Configuration::enforce_type_consistency, R"( + Enforce gate type consistency inside of a group. Defaults to ``False``. + :type: bool + )"); + py_dataflow_configuration.def("with_min_group_size", &dataflow::Configuration::with_min_group_size, py::arg("size"), R"( Set the minimum size of a group. Smaller groups will be penalized during analysis. @@ -115,42 +130,193 @@ namespace hal :rtype: dataflow.Dataflow.Configuration )"); - py_dataflow_configuration.def("with_known_groups", py::overload_cast&>(&dataflow::Configuration::with_known_groups), py::arg("groups"), R"( - Set already identified groups of sequential gates as a list of groups with each group being a module. + py_dataflow_configuration.def( + "with_known_structures", py::overload_cast&, bool>(&dataflow::Configuration::with_known_structures), py::arg("structures"), py::arg("overwrite") = false, R"( + Add modules to the set of previously identified word-level structures. + The gates contained in the modules do not have to be of the target gate types. + The input and output pin groups of these modules will be used to guide datapath analysis. + Only pin groups larger than ``min_group_size`` will be considered. + :param list[hal_py.Module] structures: A list of modules. + :param bool overwrite: Set ``True`` to overwrite the existing known word-level structures, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def("with_known_structures", + py::overload_cast*>>>&, bool>(&dataflow::Configuration::with_known_structures), + py::arg("structures"), + py::arg("overwrite") = false, + R"( + Add modules to the set of previously identified word-level structures. + The gates contained in the modules do not have to be of the target gate types. + The input and output pin groups of these modules will be used to guide datapath analysis. + For each module, the input and output pin groups to be considered for analysis must be specified. + An empty pin group vector results in all pin groups of the module being considered. + Only pin groups larger than ``min_group_size`` will be considered. + :param list[tuple(hal_py.Module,list[hal_py.ModulePinGroup])] structures: A list of modules, each of them with a list of module pin groups. + :param bool overwrite: Set ``True`` to overwrite the existing known word-level structures, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def( + "with_known_structures", py::overload_cast&, bool>(&dataflow::Configuration::with_known_structures), py::arg("structures"), py::arg("overwrite") = false, R"( + Add (typically large) gates to the set of previously identified word-level structures. + The gates do not have to be of the target gate types. + The input and output pin groups of these gates will be used to guide datapath analysis. + Only pin groups larger than ``min_group_size`` will be considered. + :param list[hal_py.Gate] structures: A list of gates. + :param bool overwrite: Set ``True`` to overwrite the existing known word-level structures, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def("with_known_structures", + py::overload_cast*>>>&, bool>(&dataflow::Configuration::with_known_structures), + py::arg("structures"), + py::arg("overwrite") = false, + R"( + Add (typically large) gates to the set of previously identified word-level structures. + The gates do not have to be of the target gate types. + The input and output pin groups of these gates will be used to guide datapath analysis. + For each gate, the input and output pin groups to be considered for analysis must be specified. + An empty pin group vector results in all pin groups of the gate being considered. + Only pin groups larger than ``min_group_size`` will be considered. + :param list[tuple(hal_py.Gate,list[hal_py.GatePinGroup])] structures: A list of gates, each of them with a list of gate pin groups. + :param bool overwrite: Set ``True`` to overwrite the existing known word-level structures, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def("with_known_structures", + py::overload_cast&, bool>(&dataflow::Configuration::with_known_structures), + py::arg("structures"), + py::arg("overwrite") = false, + R"( + Add all gates of a (typically large) gate type to the set of previously identified word-level structures. + The gate types do not have to be part of the target gate types. + The input and output pin groups of the gates of these types will be used to guide datapath analysis. + Only pin groups larger than ``min_group_size`` will be considered. + :param set[hal_py.GateType] structures: A set of gates. + :param bool overwrite: Set ``True`` to overwrite the existing known word-level structures, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); - :param list[hal_py.Module] groups: A list of groups. + py_dataflow_configuration.def("with_known_structures", + py::overload_cast*>>&, bool>(&dataflow::Configuration::with_known_structures), + py::arg("structures"), + py::arg("overwrite") = false, + R"( + Add all gates of a (typically large) gate type to the set of previously identified word-level structures. + The gate types do not have to be part of the target gate types. + The input and output pin groups of the gates of these types will be used to guide datapath analysis. + For each gate type, the input and output pin groups to be considered for analysis must be specified. + An empty pin group vector results in all pin groups of the gate type being considered. + Only pin groups larger than ``min_group_size`` will be considered. + :param dict[hal_py.GateType,list[hal_py.GatePinGroup]] structures: A dict from gates to a vector of a subset of their pin groups. + :param bool overwrite: Set ``True`` to overwrite the existing known word-level structures, ``False`` otherwise. Defaults to ``False``. :returns: The updated dataflow analysis configuration. :rtype: dataflow.Dataflow.Configuration )"); - py_dataflow_configuration.def("with_known_groups", py::overload_cast&>(&dataflow::Configuration::with_known_groups), py::arg("groups"), R"( - Set already identified groups of sequential gates as a vector of groups with each group being a grouping. + py_dataflow_configuration.def( + "with_known_groups", py::overload_cast&, bool>(&dataflow::Configuration::with_known_groups), py::arg("groups"), py::arg("overwrite") = false, R"( + Add modules to the set of previously identified word-level groups. + These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + + :param list[hal_py.Module] groups: A list of modules. + :param bool overwrite: Set ``True`` to overwrite the existing previously identified word-level groups, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); - :param list[hal_py.Grouping] groups: A list of groups. + py_dataflow_configuration.def("with_known_groups", + py::overload_cast>&, bool>(&dataflow::Configuration::with_known_groups), + py::arg("groups"), + py::arg("overwrite") = false, + R"( + Add lists of gates to the set of previously identified word-level groups. + These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + :param list[list[hal_py.Gate]] groups: A list of groups, each of them given as a list of gates. + :param bool overwrite: Set ``True`` to overwrite the existing previously identified word-level groups, ``False`` otherwise. Defaults to ``False``. :returns: The updated dataflow analysis configuration. :rtype: dataflow.Dataflow.Configuration )"); - py_dataflow_configuration.def("with_known_groups", py::overload_cast>&>(&dataflow::Configuration::with_known_groups), py::arg("groups"), R"( - Set already identified groups of sequential gates as a list of groups with each group being a list of gates. + py_dataflow_configuration.def( + "with_known_groups", py::overload_cast>&, bool>(&dataflow::Configuration::with_known_groups), py::arg("groups"), py::arg("overwrite") = false, R"( + Add lists of gate IDs to the set of previously identified word-level groups. + These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + The groups will be used to guide dataflow analysis, but will remain unaltered in the process. - :param list[list[hal_py.Gate]] groups: A list of groups. + :param list[list[int]] groups: A list of groups, each of them given as a list of gate IDs. + :param bool overwrite: Set ``True`` to overwrite the existing previously identified word-level groups, ``False`` otherwise. Defaults to ``False``. :returns: The updated dataflow analysis configuration. :rtype: dataflow.Dataflow.Configuration )"); - py_dataflow_configuration.def("with_known_groups", py::overload_cast>&>(&dataflow::Configuration::with_known_groups), py::arg("groups"), R"( - Set already identified groups of sequential gates as a list of groups with each group being a list of gate IDs. + py_dataflow_configuration.def("with_known_groups", + py::overload_cast>&, bool>(&dataflow::Configuration::with_known_groups), + py::arg("groups"), + py::arg("overwrite") = false, + R"( + Add groups from a previous dataflow analysis run to the set of previously identified word-level groups. + These groups must only contain gates of the target gate types specified for analysis and will otherwise be ignored. + The groups will be used to guide dataflow analysis, but will remain unaltered in the process. + The group IDs will be ignored during analysis and the same group may be assigned a new ID. + :param dict[int,set[hal_py.Gate]] groups: A dict from group IDs to groups, each of them given as a set of gates. + :param bool overwrite: Set ``True`` to overwrite the existing previously identified word-level groups, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); - :param list[list[int]] groups: A list of groups. + py_dataflow_configuration.def( + "with_gate_types", py::overload_cast&, bool>(&dataflow::Configuration::with_gate_types), py::arg("types"), py::arg("overwrite") = false, R"( + Add the gate types to the set of gate types to be grouped by dataflow analysis. + Overwrite the existing set of gate types by setting the optional ``overwrite`` flag to ``True``. + :param set[hal_py.GateType] types: A set of gate types. + :param bool overwrite: Set ``True`` to overwrite existing set of gate types, ``False`` otherwise. Defaults to ``False``. :returns: The updated dataflow analysis configuration. :rtype: dataflow.Dataflow.Configuration )"); - py_dataflow_configuration.def("with_register_stage_identification", &dataflow::Configuration::with_register_stage_identification, py::arg("enable") = true, R"( - Enable register stage identification as part of dataflow analysis. + py_dataflow_configuration.def( + "with_gate_types", py::overload_cast&, bool>(&dataflow::Configuration::with_gate_types), py::arg("type_properties"), py::arg("overwrite") = false, R"( + Add the gate types featuring the specified properties to the set of gate types to be grouped by dataflow analysis. + Overwrite the existing set of gate types by setting the optional ``overwrite`` flag to ``True``. - :param bool enable: Set ``True`` to enable register stage identification, ``False`` otherwise. Defaults to ``True``. + :param set[hal_py.GateTypeProperty] type_properties: A set of gate type properties. + :param bool overwrite: Set ``True`` to overwrite existing set of gate types, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def("with_control_pin_types", &dataflow::Configuration::with_control_pin_types, py::arg("types"), py::arg("overwrite") = false, R"( + Set the pin types of the pins to be considered control pins by dataflow analysis. + Overwrite the existing set of pin types by setting the optional ``overwrite`` flag to ``True``. + + :param set[hal_py.PinType] types: A set of pin types. + :param bool enable: Set ``True`` to overwrite existing set of pin types, ``False`` otherwise. Defaults to ``False``. + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def("with_flip_flops", &dataflow::Configuration::with_flip_flops, R"( + Use the default detection configuration for flip-flops. + Includes all flip-flop types as target gate types and sets ``clock``, ``enable``, ``set``, and ``reset`` pins as control pins. + Overwrites any existing gate type and control pin configuration. + + :returns: The updated dataflow analysis configuration. + :rtype: dataflow.Dataflow.Configuration + )"); + + py_dataflow_configuration.def("with_stage_identification", &dataflow::Configuration::with_stage_identification, py::arg("enable") = true, R"( + Enable stage identification as part of dataflow analysis. + + :param bool enable: Set ``True`` to enable stage identification, ``False`` otherwise. Defaults to ``True``. :returns: The updated dataflow analysis configuration. :rtype: dataflow.Dataflow.Configuration )"); @@ -163,10 +329,10 @@ namespace hal :rtype: dataflow.Dataflow.Configuration )"); - py_dataflow.def( + m.def( "analyze", - [](Netlist* nl, const dataflow::Configuration& config = dataflow::Configuration()) -> std::optional { - auto res = dataflow::analyze(nl, config); + [](const dataflow::Configuration& config) -> std::optional { + auto res = dataflow::analyze(config); if (res.is_ok()) { return res.get(); @@ -177,19 +343,21 @@ namespace hal return std::nullopt; } }, - py::arg("nl"), - py::arg("config") = dataflow::Configuration(), + py::arg("config"), R"( - Analyze the datapath to identify word-level registers in the given netlist. + Analyze the gate-level netlist to identify word-level registers. + Reconstructs registers based on properties such as the control inputs of their flip-flops and common successors/predecessors. + Operates on an abstraction of the netlist that contains only flip-flops and connections between two flip-flops only if they are connected through combinational logic. - :param hal_py.Netlist nl: The netlist. :param dataflow.Dataflow.Configuration config: The dataflow analysis configuration. :returns: The dataflow analysis result on success, ``None`` otherwise. :rtype: dataflow.Dataflow.Result or None )"); - py::class_> py_dataflow_result(py_dataflow, "Result", R"( - The result of a dataflow analysis run containing the identified groups of sequential gates and their interconnections. + py::class_> py_dataflow_result(m, "Result", R"( + This class holds result of a dataflow analysis run, which contains the identified groups of sequential gates and their interconnections. + Each such group is assigned a unique ID by which it can be addressed in many of the member functions of this class. + Please note that this ID is not related to any other HAL ID. )"); py_dataflow_result.def("get_netlist", &dataflow::Result::get_netlist, R"( @@ -453,8 +621,11 @@ namespace hal py_dataflow_result.def( "create_modules", - [](const dataflow::Result& self, const std::unordered_set& group_ids = {}) -> std::optional> { - auto res = self.create_modules(group_ids); + [](const dataflow::Result& self, + const std::map& module_suffixes = {}, + const std::map, std::string>& pin_prefixes = {}, + const std::unordered_set& group_ids = {}) -> std::optional> { + auto res = self.create_modules(module_suffixes, pin_prefixes, group_ids); if (res.is_ok()) { return res.get(); @@ -465,10 +636,42 @@ namespace hal return std::nullopt; } }, - py::arg("group_ids") = std::unordered_set(), + py::arg("module_suffixes") = std::map(), + py::arg("pin_prefixes") = std::map, std::string>(), + py::arg("group_ids") = std::unordered_set(), R"( Create modules for the dataflow analysis result. + :param dict[hal_py.GateType,str] module_suffixes: The suffixes to use for modules containing only gates of a specific gate type. Defaults to ``"module"`` for mixed and unspecified gate types. + :param dict[tuple(hal_py.PinDirection,str),str] pin_prefixes: The prefixes to use for the module pins that (within the module) only connect to gate pins of a specific name. Defaults to the gate pin name. + :param set[int] group_ids: The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. + :returns: A map from group IDs to Modules on success, ``None`` otherwise. + :rtype: dict[int,hal_py.Module] or None + )"); + py_dataflow_result.def( + "create_modules", + [](const dataflow::Result& self, + const std::map& module_suffixes, + const std::map, std::string>& pin_prefixes = {}, + const std::unordered_set& group_ids = {}) -> std::optional> { + auto res = self.create_modules(module_suffixes, pin_prefixes, group_ids); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "error encountered while creating modules:\n{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("module_suffixes"), + py::arg("pin_prefixes") = std::map, std::string>(), + py::arg("group_ids") = std::unordered_set(), + R"( + Create modules for the dataflow analysis result. + :param dict[hal_py.GateTypeProperty,str] module_suffixes: The suffixes to use for modules containing only gates of a specific gate type. All gate types featuring the specified gate type property are considered, but the module must still be pure (i.e., all gates must be of the same type) for the suffix to be used. Defaults to ``"module"`` for mixed and unspecified gate types. + :param dict[tuple(hal_py.PinDirection,str),str] pin_prefixes: The prefixes to use for the module pins that (within the module) only connect to gate pins of a specific name. Defaults to the gate pin name. :param set[int] group_ids: The group IDs to consider. If no IDs are provided, all groups will be considered. Defaults to an empty set. :returns: A map from group IDs to Modules on success, ``None`` otherwise. :rtype: dict[int,hal_py.Module] or None @@ -505,7 +708,7 @@ namespace hal All specified groups are merged into the first group of the provided vector and are subsequently deleted. :param set[int] group_ids: The group IDs of the groups to merge. - :returns: The ID of the group that all over groups have been merged into on success, ``None`` otherwise. + :returns: The ID of the group that all other groups have been merged into on success, ``None`` otherwise. :rtype: int or None )"); diff --git a/plugins/dataflow_analysis/src/api/configuration.cpp b/plugins/dataflow_analysis/src/api/configuration.cpp index ce2848007c9..8ac3b820a3a 100644 --- a/plugins/dataflow_analysis/src/api/configuration.cpp +++ b/plugins/dataflow_analysis/src/api/configuration.cpp @@ -1,13 +1,19 @@ #include "dataflow_analysis/api/configuration.h" #include "hal_core/netlist/gate.h" +#include "hal_core/netlist/gate_library/gate_library.h" #include "hal_core/netlist/grouping.h" #include "hal_core/netlist/module.h" +#include "hal_core/netlist/netlist.h" namespace hal { namespace dataflow { + Configuration::Configuration(Netlist* nl) : netlist(nl) + { + } + Configuration& Configuration::with_min_group_size(u32 size) { this->min_group_size = size; @@ -20,50 +26,292 @@ namespace hal return *this; } - Configuration& Configuration::with_known_groups(const std::vector& groups) + Configuration& Configuration::with_known_structures(const std::vector& structures, bool overwrite) + { + if (overwrite) + { + this->known_net_groups.clear(); + } + + for (const auto* mod : structures) + { + for (const auto* pin_group : mod->get_pin_groups()) + { + std::vector nets; + for (const auto* pin : pin_group->get_pins()) + { + nets.push_back(pin->get_net()); + } + this->known_net_groups.push_back(nets); + } + } + + return *this; + } + + Configuration& Configuration::with_known_structures(const std::vector*>>>& structures, bool overwrite) + { + if (overwrite) + { + this->known_net_groups.clear(); + } + + for (const auto& [_, pin_groups] : structures) + { + for (const auto* pin_group : pin_groups) + { + std::vector nets; + for (const auto* pin : pin_group->get_pins()) + { + nets.push_back(pin->get_net()); + } + this->known_net_groups.push_back(nets); + } + } + + return *this; + } + + Configuration& Configuration::with_known_structures(const std::vector& structures, bool overwrite) + { + if (overwrite) + { + this->known_net_groups.clear(); + } + + for (const auto* gate : structures) + { + for (const auto* pin_group : gate->get_type()->get_pin_groups()) + { + std::vector nets; + for (const auto* pin : pin_group->get_pins()) + { + if (pin->get_direction() == PinDirection::input) + { + nets.push_back(gate->get_fan_in_net(pin)); + } + else if (pin->get_direction() == PinDirection::output) + { + nets.push_back(gate->get_fan_out_net(pin)); + } + } + this->known_net_groups.push_back(nets); + } + } + + return *this; + } + + Configuration& Configuration::with_known_structures(const std::vector*>>>& structures, bool overwrite) + { + if (overwrite) + { + this->known_net_groups.clear(); + } + + for (const auto& [gate, pin_groups] : structures) + { + for (const auto* pin_group : pin_groups) + { + std::vector nets; + for (const auto* pin : pin_group->get_pins()) + { + if (pin->get_direction() == PinDirection::input) + { + nets.push_back(gate->get_fan_in_net(pin)); + } + else if (pin->get_direction() == PinDirection::output) + { + nets.push_back(gate->get_fan_out_net(pin)); + } + } + this->known_net_groups.push_back(nets); + } + } + + return *this; + } + + Configuration& Configuration::with_known_structures(const std::unordered_set& structures, bool overwrite) + { + if (overwrite) + { + this->known_net_groups.clear(); + } + + for (const auto* gate : this->netlist->get_gates([structures](const Gate* g) { return structures.find(g->get_type()) != structures.end(); })) + { + for (const auto* pin_group : gate->get_type()->get_pin_groups()) + { + std::vector nets; + for (const auto* pin : pin_group->get_pins()) + { + if (pin->get_direction() == PinDirection::input) + { + nets.push_back(gate->get_fan_in_net(pin)); + } + else if (pin->get_direction() == PinDirection::output) + { + nets.push_back(gate->get_fan_out_net(pin)); + } + } + this->known_net_groups.push_back(nets); + } + } + + return *this; + } + + Configuration& Configuration::with_known_structures(const std::unordered_map*>>& structures, bool overwrite) + { + if (overwrite) + { + this->known_net_groups.clear(); + } + + for (const auto* gate : this->netlist->get_gates([structures](const Gate* g) { return structures.find(g->get_type()) != structures.end(); })) + { + for (const auto* pin_group : structures.at(gate->get_type())) + { + std::vector nets; + for (const auto* pin : pin_group->get_pins()) + { + if (pin->get_direction() == PinDirection::input) + { + nets.push_back(gate->get_fan_in_net(pin)); + } + else if (pin->get_direction() == PinDirection::output) + { + nets.push_back(gate->get_fan_out_net(pin)); + } + } + this->known_net_groups.push_back(nets); + } + } + + return *this; + } + + Configuration& Configuration::with_known_groups(const std::vector& groups, bool overwrite) + { + if (overwrite) + { + this->known_gate_groups.clear(); + } + + for (auto* mod : groups) + { + this->known_gate_groups.push_back(mod->get_gates()); + } + + return *this; + } + + Configuration& Configuration::with_known_groups(const std::vector>& groups, bool overwrite) + { + if (overwrite) + { + this->known_gate_groups = groups; + } + else + { + this->known_gate_groups.insert(this->known_gate_groups.end(), groups.begin(), groups.end()); + } + + return *this; + } + + Configuration& Configuration::with_known_groups(const std::vector>& groups, bool overwrite) { - for (const auto* mod : groups) + if (overwrite) + { + this->known_gate_groups.clear(); + } + + for (const auto& gate_ids : groups) { - std::vector group; - const auto& gates = mod->get_gates(); - std::transform(gates.cbegin(), gates.cend(), std::back_inserter(group), [](const Gate* g) { return g->get_id(); }); - this->known_groups.push_back(std::move(group)); + std::vector gates; + std::transform(gate_ids.cbegin(), gate_ids.cend(), std::back_inserter(gates), [this](u32 gid) { return this->netlist->get_gate_by_id(gid); }); + this->known_gate_groups.push_back(gates); } + return *this; } - Configuration& Configuration::with_known_groups(const std::vector& groups) + Configuration& Configuration::with_known_groups(const std::unordered_map>& groups, bool overwrite) { - for (const auto* grp : groups) + if (overwrite) + { + this->known_gate_groups.clear(); + } + + for (const auto& [_, gates] : groups) { - std::vector group; - const auto& gates = grp->get_gates(); - std::transform(gates.cbegin(), gates.cend(), std::back_inserter(group), [](const Gate* g) { return g->get_id(); }); - this->known_groups.push_back(std::move(group)); + std::vector group(gates.cbegin(), gates.cend()); + this->known_gate_groups.push_back(group); } + return *this; } - Configuration& Configuration::with_known_groups(const std::vector>& groups) + Configuration& Configuration::with_gate_types(const std::set& types, bool overwrite) { - for (const auto& gates : groups) + if (overwrite) + { + this->gate_types = types; + } + else { - std::vector group; - std::transform(gates.cbegin(), gates.cend(), std::back_inserter(group), [](const Gate* g) { return g->get_id(); }); - this->known_groups.push_back(std::move(group)); + this->gate_types.insert(types.begin(), types.end()); } + return *this; } - Configuration& Configuration::with_known_groups(const std::vector>& groups) + Configuration& Configuration::with_gate_types(const std::set& gate_type_properties, bool overwrite) { - this->known_groups = groups; + auto gate_types_map = this->netlist->get_gate_library()->get_gate_types([gate_type_properties](const GateType* gt) { + for (GateTypeProperty p : gate_type_properties) + { + if (gt->has_property(p)) + { + return true; + } + } + return false; + }); + std::set types; + std::transform(gate_types_map.begin(), gate_types_map.end(), std::inserter(types, types.begin()), [](const auto& gt) { return gt.second; }); + this->with_gate_types(types, overwrite); + + return *this; + } + + Configuration& Configuration::with_control_pin_types(const std::set& types, bool overwrite) + { + if (overwrite) + { + this->control_pin_types = types; + } + else + { + this->control_pin_types.insert(types.begin(), types.end()); + } + + return *this; + } + + Configuration& Configuration::with_flip_flops() + { + this->with_gate_types({GateTypeProperty::ff}, true); + this->control_pin_types = {PinType::clock, PinType::enable, PinType::set, PinType::reset}; + return *this; } - Configuration& Configuration::with_register_stage_identification(bool enable) + Configuration& Configuration::with_stage_identification(bool enable) { - this->enable_register_stages = enable; + this->enable_stages = enable; return *this; } diff --git a/plugins/dataflow_analysis/src/api/dataflow.cpp b/plugins/dataflow_analysis/src/api/dataflow.cpp index bd3a3424533..3c673c26ff3 100644 --- a/plugins/dataflow_analysis/src/api/dataflow.cpp +++ b/plugins/dataflow_analysis/src/api/dataflow.cpp @@ -9,13 +9,23 @@ namespace hal { namespace dataflow { - hal::Result analyze(Netlist* nl, const Configuration& config) + hal::Result analyze(const Configuration& config) { - if (nl == nullptr) + if (config.netlist == nullptr) { return ERR("netlist is a nullptr"); } + if (config.gate_types.empty()) + { + return ERR("no gate types specified"); + } + + if (config.control_pin_types.empty()) + { + return ERR("no control pin types specified"); + } + // set up dataflow analysis double total_time = 0; auto begin_time = std::chrono::high_resolution_clock::now(); @@ -24,6 +34,7 @@ namespace hal proc_config.pass_layers = 2; proc_config.num_threads = std::thread::hardware_concurrency(); proc_config.enforce_type_consistency = config.enforce_type_consistency; + proc_config.has_known_groups = !config.known_net_groups.empty(); dataflow::evaluation::Context eval_ctx; @@ -36,9 +47,9 @@ namespace hal log_info("dataflow", "will prioritize sizes {}", utils::join(", ", config.expected_sizes)); } - auto netlist_abstr = dataflow::pre_processing::run(nl, config.enable_register_stages); - auto initial_grouping = std::make_shared(netlist_abstr, config.known_groups); - std::shared_ptr final_grouping; + std::shared_ptr initial_grouping = nullptr; + auto netlist_abstr = dataflow::pre_processing::run(config, initial_grouping); + std::shared_ptr final_grouping = nullptr; u32 iteration = 0; while (true) @@ -62,11 +73,13 @@ namespace hal iteration++; } + dataflow::processing::clear(); + total_time = (double)std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - begin_time).count() / 1000; log_info("dataflow", "dataflow processing finished in {:3.2f}s", total_time); - return OK(dataflow::Result(nl, *final_grouping)); + return OK(dataflow::Result(config.netlist, *final_grouping)); } } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/src/api/result.cpp b/plugins/dataflow_analysis/src/api/result.cpp index d8441ec5c2c..2d348572f4f 100644 --- a/plugins/dataflow_analysis/src/api/result.cpp +++ b/plugins/dataflow_analysis/src/api/result.cpp @@ -1,6 +1,7 @@ #include "dataflow_analysis/api/result.h" #include "hal_core/netlist/gate.h" +#include "hal_core/netlist/gate_library/gate_type.h" #include "hal_core/netlist/module.h" #include "hal_core/netlist/netlist.h" #include "hal_core/utilities/log.h" @@ -30,7 +31,7 @@ namespace hal m_netlist = nl; const auto& na = grouping.netlist_abstr; - for (const auto* gate : na.all_sequential_gates) + for (const auto* gate : na.target_gates) { auto gate_id = gate->get_id(); @@ -50,35 +51,14 @@ namespace hal } } - if (const auto it = na.gate_to_clock_signals.find(gate_id); it != na.gate_to_clock_signals.end()) + if (const auto it = na.gate_to_control_signals.find(gate_id); it != na.gate_to_control_signals.end()) { - for (auto clock_net_id : std::get<1>(*it)) + for (const auto& [type, signals] : std::get<1>(*it)) { - this->m_gate_signals[gate][PinType::clock].insert(nl->get_net_by_id(clock_net_id)); - } - } - - if (const auto it = na.gate_to_enable_signals.find(gate_id); it != na.gate_to_enable_signals.end()) - { - for (auto enable_net_id : std::get<1>(*it)) - { - this->m_gate_signals[gate][PinType::enable].insert(nl->get_net_by_id(enable_net_id)); - } - } - - if (const auto it = na.gate_to_reset_signals.find(gate_id); it != na.gate_to_reset_signals.end()) - { - for (auto reset_net_id : std::get<1>(*it)) - { - this->m_gate_signals[gate][PinType::reset].insert(nl->get_net_by_id(reset_net_id)); - } - } - - if (const auto it = na.gate_to_set_signals.find(gate_id); it != na.gate_to_set_signals.end()) - { - for (auto set_net_id : std::get<1>(*it)) - { - this->m_gate_signals[gate][PinType::set].insert(nl->get_net_by_id(set_net_id)); + for (auto signal_net_id : signals) + { + this->m_gate_signals[gate][type].insert(nl->get_net_by_id(signal_net_id)); + } } } } @@ -94,24 +74,12 @@ namespace hal } m_gates_of_group[group_id] = gates; - for (const auto net_id : grouping.get_clock_signals_of_group(group_id)) - { - this->m_group_signals[group_id][PinType::clock].insert(m_netlist->get_net_by_id(net_id)); - } - - for (const auto net_id : grouping.get_control_signals_of_group(group_id)) - { - this->m_group_signals[group_id][PinType::enable].insert(m_netlist->get_net_by_id(net_id)); - } - - for (const auto net_id : grouping.get_reset_signals_of_group(group_id)) - { - this->m_group_signals[group_id][PinType::reset].insert(m_netlist->get_net_by_id(net_id)); - } - - for (const auto net_id : grouping.get_set_signals_of_group(group_id)) + for (const auto& [type, signals] : grouping.get_control_signals_of_group(group_id)) { - this->m_group_signals[group_id][PinType::set].insert(m_netlist->get_net_by_id(net_id)); + for (auto signal_net_id : signals) + { + this->m_group_signals[group_id][type].insert(m_netlist->get_net_by_id(signal_net_id)); + } } if (auto suc_ids = grouping.get_successor_groups_of_group(group_id); !suc_ids.empty()) @@ -446,21 +414,29 @@ namespace hal return ERR("failed to open file at '" + write_path.string() + "' for writing dataflow gate groups."); } - hal::Result> dataflow::Result::create_modules(const std::unordered_set& group_ids) const + hal::Result> dataflow::Result::create_modules(const std::map& module_suffixes, + const std::map, std::string>& pin_prefixes, + const std::unordered_set& group_ids) const { auto* nl = this->get_netlist(); // delete all modules that start with DANA + std::vector modules_to_delete; for (const auto mod : nl->get_modules()) { - if (mod->get_name().find("DANA") != std::string::npos) + if (utils::starts_with(mod->get_name(), std::string("DANA_"))) { - nl->delete_module(mod); + modules_to_delete.push_back(mod); } } + + for (auto* mod : modules_to_delete) + { + nl->delete_module(mod); + } log_info("dataflow", "successfully deleted old DANA modules"); - // create new modules and try to keep hierachy if possible + // create new modules and try to keep hierarchy if possible std::unordered_map group_to_module; for (const auto& [group_id, group] : this->get_groups()) { @@ -470,8 +446,10 @@ namespace hal } bool gate_hierachy_matches_for_all = true; + bool gate_type_matches_for_all = true; bool first_run = true; - auto* reference_module = nl->get_top_module(); + const GateType* gate_type; + auto* reference_module = nl->get_top_module(); std::vector gates; for (const auto gate : group) @@ -481,13 +459,15 @@ namespace hal if (first_run) { reference_module = gate->get_module(); + gate_type = gate->get_type(); first_run = false; } - else if (!gate_hierachy_matches_for_all) + else if (gate->get_module() != reference_module) { - continue; + gate_hierachy_matches_for_all = false; } - else if (gate->get_module() != reference_module) + + if (gate_type != gate->get_type()) { gate_hierachy_matches_for_all = false; } @@ -498,124 +478,133 @@ namespace hal reference_module = nl->get_top_module(); } - auto* new_mod = nl->create_module("DANA_register_" + std::to_string(group_id), reference_module, gates); - group_to_module[group_id] = new_mod; + std::string suffix; + if (const auto it = module_suffixes.find(gate_type); gate_type_matches_for_all && it != module_suffixes.end()) + { + suffix = it->second; + } + else + { + suffix = "module"; + } - PinGroup* data_in_group = nullptr; - PinGroup* data_out_group = nullptr; + auto* new_mod = nl->create_module("DANA_" + suffix + "_" + std::to_string(group_id), reference_module, gates); + group_to_module[group_id] = new_mod; + std::map, PinGroup*> pin_groups; for (auto* pin : new_mod->get_pins()) { if (pin->get_direction() == PinDirection::input) { const auto destinations = pin->get_net()->get_destinations([new_mod](const Endpoint* ep) { return ep->get_gate()->get_module() == new_mod; }); - if (std::all_of(destinations.begin(), destinations.end(), [](const Endpoint* ep) { return ep->get_pin()->get_type() == PinType::data; })) + + const auto* first_pin = destinations.front()->get_pin(); + auto pin_type = first_pin->get_type(); + auto pin_name = first_pin->get_name(); + if (std::all_of(destinations.begin(), destinations.end(), [pin_name](const Endpoint* ep) { return ep->get_pin()->get_name() == pin_name; })) { - if (data_in_group == nullptr) + const auto pg_key = std::make_pair(PinDirection::input, pin_name); + + std::string prefix; + if (const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end()) { - data_in_group = pin->get_group().first; - new_mod->set_pin_group_name(data_in_group, "DI"); - new_mod->set_pin_group_type(data_in_group, PinType::data); + prefix = prefix_it->second; } else { - if (!new_mod->assign_pin_to_group(data_in_group, pin)) + prefix = "i_" + pin_name; + } + + if (const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end()) + { + auto* pin_group = pin->get_group().first; + pin_groups[pg_key] = pin_group; + new_mod->set_pin_group_name(pin_group, prefix); + new_mod->set_pin_group_type(pin_group, pin_type); + } + else + { + if (!new_mod->assign_pin_to_group(pg_it->second, pin)) { log_warning("dataflow", "Assign pin to group failed."); } } - new_mod->set_pin_name(pin, "DI(" + std::to_string(pin->get_group().second) + ")"); - new_mod->set_pin_type(pin, PinType::data); + new_mod->set_pin_name(pin, prefix + "(" + std::to_string(pin->get_group().second) + ")"); + new_mod->set_pin_type(pin, pin_type); } } else if (pin->get_direction() == PinDirection::output) { const auto sources = pin->get_net()->get_sources([new_mod](const Endpoint* ep) { return ep->get_gate()->get_module() == new_mod; }); - if (sources.size() == 1 && sources.at(0)->get_pin()->get_type() == PinType::state) + + const auto* first_pin = sources.front()->get_pin(); + auto pin_type = first_pin->get_type(); + auto pin_name = first_pin->get_name(); + if (sources.size() == 1) { - if (data_out_group == nullptr) + const auto pg_key = std::make_pair(PinDirection::output, pin_name); + + std::string prefix; + if (const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end()) + { + prefix = prefix_it->second; + } + else { - data_out_group = pin->get_group().first; - new_mod->set_pin_group_name(data_out_group, "DO"); - new_mod->set_pin_group_type(data_out_group, PinType::data); + prefix = "o_" + pin_name; + } + + if (const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end()) + { + auto* pin_group = pin->get_group().first; + pin_groups[pg_key] = pin_group; + new_mod->set_pin_group_name(pin_group, prefix); + new_mod->set_pin_group_type(pin_group, pin_type); } else { - if (!new_mod->assign_pin_to_group(data_out_group, pin)) + if (!new_mod->assign_pin_to_group(pg_it->second, pin)) { log_warning("dataflow", "Assign pin to group failed."); } } - new_mod->set_pin_name(pin, "DO(" + std::to_string(pin->get_group().second) + ")"); - new_mod->set_pin_type(pin, PinType::data); + new_mod->set_pin_name(pin, prefix + "(" + std::to_string(pin->get_group().second) + ")"); + new_mod->set_pin_type(pin, pin_type); } } } - for (const auto& [pin_type, nets] : m_group_signals.at(group_id)) + for (const auto* pin_group : new_mod->get_pin_groups()) { - std::string prefix; - switch (pin_type) + if (pin_group->size() == 1) { - case PinType::clock: - prefix = "CLK"; - break; - case PinType::enable: - prefix = "EN"; - break; - case PinType::reset: - prefix = "RST"; - break; - case PinType::set: - prefix = "SET"; - break; - default: - continue; - } - - PinGroup* pin_group = nullptr; - for (auto* net : nets) - { - auto* pin = new_mod->get_pin_by_net(net); - - if (pin_group == nullptr) - { - pin_group = pin->get_group().first; - new_mod->set_pin_group_name(pin_group, prefix); - new_mod->set_pin_group_type(pin_group, pin_type); - } - else - { - if (!new_mod->assign_pin_to_group(pin_group, pin)) - { - log_warning("dataflow", "Assign pin to group failed."); - } - } - - if (nets.size() == 1) - { - new_mod->set_pin_name(pin, prefix); - } - else - { - if (const auto res = pin_group->get_index(pin); res.is_error()) - { - log_warning("dataflow", "{}", res.get_error().get()); - } - else - { - new_mod->set_pin_name(pin, prefix + "(" + std::to_string(res.get()) + ")"); - } - } - new_mod->set_pin_type(pin, pin_type); + auto* pin = pin_group->get_pins().front(); + new_mod->set_pin_name(pin, pin_group->get_name()); } } } return OK(group_to_module); } + hal::Result> dataflow::Result::create_modules(const std::map& module_suffixes, + const std::map, std::string>& pin_prefixes, + const std::unordered_set& group_ids) const + { + const auto* gl = this->m_netlist->get_gate_library(); + std::map gate_type_suffixes; + for (const auto& suffix : module_suffixes) + { + for (const auto& [_, type] : gl->get_gate_types([suffix](const GateType* gt) { return gt->has_property(suffix.first); })) + { + gate_type_suffixes[type] = suffix.second; + } + } + + return this->create_modules(gate_type_suffixes, pin_prefixes, group_ids); + } + std::vector> dataflow::Result::get_groups_as_list(const std::unordered_set& group_ids) const { std::vector> groups; diff --git a/plugins/dataflow_analysis/src/common/grouping.cpp b/plugins/dataflow_analysis/src/common/grouping.cpp index 170f14fa543..87289103ee2 100644 --- a/plugins/dataflow_analysis/src/common/grouping.cpp +++ b/plugins/dataflow_analysis/src/common/grouping.cpp @@ -13,27 +13,29 @@ namespace hal { } - Grouping::Grouping(const NetlistAbstraction& na, const std::vector>& groups) : Grouping(na) + Grouping::Grouping(const NetlistAbstraction& na, const std::vector>& groups) : Grouping(na) { /* initialize state */ u32 new_id_counter = -1; bool group_is_known; - for (const auto& gate : na.all_sequential_gates) + for (const auto* gate : na.target_gates) { group_is_known = false; for (const auto& gates : groups) { - for (const auto& gate_id : gates) + for (const auto* g : gates) { - if (gate->get_id() == gate_id) + if (gate == g) { group_is_known = true; break; } } if (group_is_known) + { break; + } } if (!group_is_known) { @@ -59,12 +61,13 @@ namespace hal u32 new_group_id = ++new_id_counter; this->operations_on_group_allowed[new_group_id] = false; - this->group_control_fingerprint_map[new_group_id] = na.gate_to_fingerprint.at(*gates.begin()); - this->gates_of_group[new_group_id].insert(gates.begin(), gates.end()); + this->group_control_fingerprint_map[new_group_id] = na.gate_to_fingerprint.at(gates.front()->get_id()); - for (const auto& gate_id : gates) + for (const auto& g : gates) { - this->parent_group_of_gate[gate_id] = new_group_id; + auto gid = g->get_id(); + this->gates_of_group[new_group_id].insert(gid); + this->parent_group_of_gate[gid] = new_group_id; } } } @@ -103,24 +106,19 @@ namespace hal return !(*this == other); } - std::unordered_set Grouping::get_clock_signals_of_group(u32 id) const + std::map> Grouping::get_control_signals_of_group(u32 group_id) const { - return get_signals_of_group(id, this->netlist_abstr.gate_to_clock_signals); - } + std::map> res; - std::unordered_set Grouping::get_control_signals_of_group(u32 id) const - { - return get_signals_of_group(id, this->netlist_abstr.gate_to_enable_signals); - } - - std::unordered_set Grouping::get_reset_signals_of_group(u32 id) const - { - return get_signals_of_group(id, this->netlist_abstr.gate_to_reset_signals); - } + for (auto gate : gates_of_group.at(group_id)) + { + if (auto it = this->netlist_abstr.gate_to_control_signals.find(gate); it != this->netlist_abstr.gate_to_control_signals.end()) + { + res.insert(it->second.begin(), it->second.end()); + } + } - std::unordered_set Grouping::get_set_signals_of_group(u32 id) const - { - return get_signals_of_group(id, this->netlist_abstr.gate_to_set_signals); + return res; } std::unordered_set Grouping::get_signals_of_group(u32 id, const std::unordered_map>& signals) const @@ -172,11 +170,11 @@ namespace hal return std::set(intersect.begin(), intersect.end()); } - std::unordered_set Grouping::get_successor_groups_of_group(u32 id) const + std::unordered_set Grouping::get_successor_groups_of_group(u32 group_id) const { { std::shared_lock lock(cache.mutex); - if (auto it = cache.suc_cache.find(id); it != cache.suc_cache.end()) + if (auto it = cache.suc_cache.find(group_id); it != cache.suc_cache.end()) { return it->second; } @@ -184,13 +182,13 @@ namespace hal std::unique_lock lock(cache.mutex); // check again, since another thread might have gotten the unique lock first - if (auto it = cache.suc_cache.find(id); it != cache.suc_cache.end()) + if (auto it = cache.suc_cache.find(group_id); it != cache.suc_cache.end()) { return it->second; } std::unordered_set successors; - for (auto gate : gates_of_group.at(id)) + for (auto gate : gates_of_group.at(group_id)) { for (auto gate_id : this->netlist_abstr.gate_to_successors.at(gate)) { @@ -198,16 +196,16 @@ namespace hal } } - cache.suc_cache.emplace(id, successors); + cache.suc_cache.emplace(group_id, successors); return successors; } - std::unordered_set Grouping::get_predecessor_groups_of_group(u32 id) const + std::unordered_set Grouping::get_predecessor_groups_of_group(u32 group_id) const { { std::shared_lock lock(cache.mutex); - if (auto it = cache.pred_cache.find(id); it != cache.pred_cache.end()) + if (auto it = cache.pred_cache.find(group_id); it != cache.pred_cache.end()) { return it->second; } @@ -215,13 +213,13 @@ namespace hal std::unique_lock lock(cache.mutex); // check again, since another thread might have gotten the unique lock first - if (auto it = cache.pred_cache.find(id); it != cache.pred_cache.end()) + if (auto it = cache.pred_cache.find(group_id); it != cache.pred_cache.end()) { return it->second; } std::unordered_set predecessors; - for (auto gate : gates_of_group.at(id)) + for (auto gate : gates_of_group.at(group_id)) { for (auto gate_id : this->netlist_abstr.gate_to_predecessors.at(gate)) { @@ -229,7 +227,69 @@ namespace hal } } - cache.pred_cache.emplace(id, predecessors); + cache.pred_cache.emplace(group_id, predecessors); + + return predecessors; + } + + std::unordered_set Grouping::get_known_successor_groups_of_group(u32 group_id) const + { + { + std::shared_lock lock(cache.mutex); + if (auto it = cache.suc_known_group_cache.find(group_id); it != cache.suc_known_group_cache.end()) + { + return it->second; + } + } + std::unique_lock lock(cache.mutex); + + // check again, since another thread might have gotten the unique lock first + if (auto it = cache.suc_known_group_cache.find(group_id); it != cache.suc_known_group_cache.end()) + { + return it->second; + } + + std::unordered_set successors; + for (auto gate : gates_of_group.at(group_id)) + { + for (auto known_group_id : this->netlist_abstr.gate_to_known_successor_groups.at(gate)) + { + successors.insert(known_group_id); + } + } + + cache.suc_known_group_cache.emplace(group_id, successors); + + return successors; + } + + std::unordered_set Grouping::get_known_predecessor_groups_of_group(u32 group_id) const + { + { + std::shared_lock lock(cache.mutex); + if (auto it = cache.pred_known_group_cache.find(group_id); it != cache.pred_known_group_cache.end()) + { + return it->second; + } + } + std::unique_lock lock(cache.mutex); + + // check again, since another thread might have gotten the unique lock first + if (auto it = cache.pred_known_group_cache.find(group_id); it != cache.pred_known_group_cache.end()) + { + return it->second; + } + + std::unordered_set predecessors; + for (auto gate : gates_of_group.at(group_id)) + { + for (auto known_group_id : this->netlist_abstr.gate_to_known_predecessor_groups.at(gate)) + { + predecessors.insert(known_group_id); + } + } + + cache.pred_known_group_cache.emplace(group_id, predecessors); return predecessors; } diff --git a/plugins/dataflow_analysis/src/evaluation/evaluation.cpp b/plugins/dataflow_analysis/src/evaluation/evaluation.cpp index 5ab908e1c0f..ca67f401471 100644 --- a/plugins/dataflow_analysis/src/evaluation/evaluation.cpp +++ b/plugins/dataflow_analysis/src/evaluation/evaluation.cpp @@ -54,8 +54,8 @@ namespace hal // mark all sequential gates as unassigned gates std::vector unassigned_gates; - unassigned_gates.reserve(netlist_abstr.all_sequential_gates.size()); - std::transform(netlist_abstr.all_sequential_gates.begin(), netlist_abstr.all_sequential_gates.end(), std::back_inserter(unassigned_gates), [](auto& g) { return g->get_id(); }); + unassigned_gates.reserve(netlist_abstr.target_gates.size()); + std::transform(netlist_abstr.target_gates.begin(), netlist_abstr.target_gates.end(), std::back_inserter(unassigned_gates), [](auto& g) { return g->get_id(); }); // sort unassignes gates to be able to use std::algorithms std::sort(unassigned_gates.begin(), unassigned_gates.end()); @@ -304,5 +304,5 @@ namespace hal return output; } } // namespace evaluation - } // namespace dataflow + } // namespace dataflow } // namespace hal diff --git a/plugins/dataflow_analysis/src/plugin_dataflow.cpp b/plugins/dataflow_analysis/src/plugin_dataflow.cpp index 61dc7b16587..efdab1d47ac 100644 --- a/plugins/dataflow_analysis/src/plugin_dataflow.cpp +++ b/plugins/dataflow_analysis/src/plugin_dataflow.cpp @@ -13,25 +13,30 @@ namespace hal { extern std::unique_ptr create_plugin_instance() { - return std::make_unique(); + return std::make_unique(); } - std::string plugin_dataflow::get_name() const + std::string DataflowPlugin::get_name() const { return std::string("dataflow"); } - std::string plugin_dataflow::get_description() const + std::string DataflowPlugin::get_version() const { - return "Dataflow analysis for gate-level netlist reverse engineering"; + return std::string("0.3"); } - std::string plugin_dataflow::get_version() const + std::string DataflowPlugin::get_description() const { - return std::string("0.1"); + return "Dataflow analysis tool DANA to recover word-level structures such as registers from gate-level netlists."; } - plugin_dataflow::plugin_dataflow() + std::set DataflowPlugin::get_dependencies() const + { + return {}; + } + + DataflowPlugin::DataflowPlugin() { m_extensions.push_back(new CliExtensionDataflow()); m_extensions.push_back(new GuiExtensionDataflow()); @@ -56,7 +61,7 @@ namespace hal { UNUSED(args); - dataflow::Configuration config; + dataflow::Configuration config(nl); std::string path; if (args.is_option_set("--path")) @@ -91,7 +96,7 @@ namespace hal } } - auto grouping_res = dataflow::analyze(nl, config); + auto grouping_res = dataflow::analyze(config); if (grouping_res.is_error()) { log_error("dataflow", "dataflow analysis failed:\n{}", grouping_res.get_error().get()); @@ -125,12 +130,12 @@ namespace hal std::string s; while (std::getline(f, s, ',')) { - m_config.expected_sizes.emplace_back(std::stoi(s)); + m_expected_sizes.emplace_back(std::stoi(s)); } } else if (par.get_tagname() == "min_group_size") { - m_config.min_group_size = atoi(par.get_value().c_str()); + m_min_group_size = atoi(par.get_value().c_str()); } else if (par.get_tagname() == "write_txt") { @@ -150,7 +155,7 @@ namespace hal } else if (par.get_tagname() == "register_stage_identification") { - m_config.enable_register_stages = (par.get_value() == "true"); + m_enable_stages = (par.get_value() == "true"); } else if (par.get_tagname() == "exec") { @@ -178,7 +183,13 @@ namespace hal dataflow::GuiLayoutLocker gll; - auto grouping_res = dataflow::analyze(nl, m_config); + auto config = dataflow::Configuration(nl) + .with_expected_sizes(m_expected_sizes) + .with_min_group_size(m_min_group_size) + .with_stage_identification(m_enable_stages) + .with_control_pin_types({PinType::clock, PinType::enable, PinType::reset, PinType::set}) + .with_gate_types({GateTypeProperty::ff}); + auto grouping_res = dataflow::analyze(config); if (grouping_res.is_error()) { log_error("dataflow", "dataflow analysis failed:\n{}", grouping_res.get_error().get()); @@ -216,45 +227,6 @@ namespace hal } } - std::vector> plugin_dataflow::execute(Netlist* nl, - std::string output_path, - const std::vector sizes, - bool draw_graph, - bool create_modules, - bool register_stage_identification, - std::vector> known_groups, - u32 min_group_size) - { - auto config = - dataflow::Configuration().with_min_group_size(min_group_size).with_expected_sizes(sizes).with_known_groups(known_groups).with_register_stage_identification(register_stage_identification); - - const auto grouping_res = dataflow::analyze(nl, config); - if (grouping_res.is_error()) - { - log_error("dataflow", "dataflow analysis failed:\n{}", grouping_res.get_error().get()); - return {}; - } - const auto grouping = grouping_res.get(); - - if (draw_graph) - { - if (const auto res = grouping.write_dot(output_path); res.is_error()) - { - log_error("dataflow", "could not write DOT graph to file:\n{}", res.get_error().get()); - } - } - - if (create_modules) - { - if (const auto res = grouping.create_modules(); res.is_error()) - { - log_error("dataflow", "could not create modules:\n{}", res.get_error().get()); - } - } - - return grouping.get_groups_as_list(); - } - std::function GuiExtensionDataflow::s_progress_indicator_function = nullptr; void GuiExtensionDataflow::register_progress_indicator(std::function pif) diff --git a/plugins/dataflow_analysis/src/pre_processing/pre_processing.cpp b/plugins/dataflow_analysis/src/pre_processing/pre_processing.cpp index df010daa66a..765bc16e16b 100644 --- a/plugins/dataflow_analysis/src/pre_processing/pre_processing.cpp +++ b/plugins/dataflow_analysis/src/pre_processing/pre_processing.cpp @@ -1,11 +1,14 @@ #include "dataflow_analysis/pre_processing/pre_processing.h" +#include "dataflow_analysis/api/configuration.h" +#include "dataflow_analysis/common/grouping.h" #include "dataflow_analysis/common/netlist_abstraction.h" #include "dataflow_analysis/pre_processing/register_stage_identification.h" #include "dataflow_analysis/utils/parallel_for_each.h" #include "dataflow_analysis/utils/progress_printer.h" #include "dataflow_analysis/utils/timing_utils.h" #include "hal_core/netlist/gate.h" +#include "hal_core/netlist/module.h" #include "hal_core/netlist/net.h" #include "hal_core/netlist/netlist.h" #include "hal_core/netlist/netlist_utils.h" @@ -24,231 +27,317 @@ namespace hal { namespace { - // void remove_buffers(NetlistAbstraction& netlist_abstr) - // { - // auto buf_gates = netlist_abstr.nl->get_gates([](auto g) { - // const GateType* gt = g->get_type(); - // return gt->get_name().find("BUF") != std::string::npos && gt->get_input_pins().size() == 1 && gt->get_output_pins().size() == 1; - // }); - // log_info("dataflow", "removing {} buffers", buf_gates.size()); - // for (const auto& g : buf_gates) - // { - // auto in_net = *(g->get_fan_in_nets().begin()); - // auto out_net = *(g->get_fan_out_nets().begin()); - // auto dsts = out_net->get_destinations(); - // for (const auto& dst : dsts) - // { - // out_net->remove_destination(dst->get_gate(), dst->get_pin()); - // in_net->add_destination(dst->get_gate(), dst->get_pin()); - // } - // netlist_abstr.nl->delete_net(out_net); - // netlist_abstr.nl->delete_gate(g); - // } - // } - - // void merge_duplicated_logic_cones(NetlistAbstraction& netlist_abstr) - // { - // measure_block_time("merge duplicated logic cones"); - - // auto all_sequential_gates = netlist_abstr.all_sequential_gates; - // auto all_gates = netlist_abstr.nl->get_gates(); - // std::sort(all_gates.begin(), all_gates.end()); - - // std::vector all_combinational_gates; - // all_combinational_gates.reserve(all_gates.size() - all_sequential_gates.size()); - // std::set_difference(all_gates.begin(), all_gates.end(), all_sequential_gates.begin(), all_sequential_gates.end(), std::back_inserter(all_combinational_gates)); - - // std::unordered_map, std::vector>> characteristic_of_gate; - - // log_info("dataflow", "computing boolean functions..."); - // { - // measure_block_time("computing boolean functions"); - - // // allocate values for all the gates so that each thread can access it without changing the container - // for (auto gate : all_combinational_gates) - // { - // characteristic_of_gate[gate] = {}; - // } - - // utils::parallel_for_each(all_combinational_gates, [&characteristic_of_gate](auto& g) { characteristic_of_gate.at(g) = compute_merge_characteristic_of_gate(g); }); - // } - - // log_info("dataflow", "merging gates..."); - // u32 gates_removed = 0; - // measure_block_time("merging gates"); - // bool changes = true; - // while (changes) - // { - // changes = false; - - // // map from gate we will keep (key) to set of gates that have exactly the same function and will be removed - // std::map, std::vector>, std::unordered_set> duplicate_gates; - // for (auto it : characteristic_of_gate) - // { - // duplicate_gates[it.second].insert(it.first); - // } - - // // delete all duplicate gates - // for (const auto& [function, gate_set] : duplicate_gates) - // { - // if (gate_set.size() > 1) - // { - // changes = true; - // auto it = gate_set.begin(); - // Gate* gate_1 = *it; - // it++; - // std::vector out_pins = gate_1->get_type()->get_output_pins(); - - // std::unordered_set affected_gates; - // for (; it != gate_set.end(); ++it) - // { - // auto gate_2 = *it; - - // for (auto out_pin : out_pins) - // { - // auto merge_net = gate_1->get_fan_out_net(out_pin); - // auto remove_net = gate_2->get_fan_out_net(out_pin); - // if (remove_net != nullptr) - // { - // if (merge_net == nullptr) - // { - // remove_net->remove_source(gate_2, out_pin); - // remove_net->add_source(gate_1, out_pin); - // } - // else - // { - // for (auto dst : remove_net->get_destinations()) - // { - // remove_net->remove_destination(dst->get_gate(), dst->get_pin()); - // merge_net->add_destination(dst->get_gate(), dst->get_pin()); - // affected_gates.insert(dst->get_gate()); - // } - // netlist_abstr.nl->delete_net(remove_net); - // } - // } - // } - // characteristic_of_gate.erase(gate_2); - // netlist_abstr.nl->delete_gate(gate_2); - // gates_removed++; - // } - - // for (auto affected_gate : affected_gates) - // { - // if (auto char_it = characteristic_of_gate.find(affected_gate); char_it != characteristic_of_gate.end()) - // { - // char_it->second = compute_merge_characteristic_of_gate(affected_gate); - // } - // } - // } - // } - // } - // log_info("dataflow", "merged {} gates into others, {} gates left", gates_removed, all_gates.size() - gates_removed); - // } - - void identify_all_sequential_gates(NetlistAbstraction& netlist_abstr) + void identify_all_target_gates(const dataflow::Configuration& config, NetlistAbstraction& netlist_abstr) { - // TODO currently only accepts FFs - log_info("dataflow", "identifying sequential gates"); - netlist_abstr.all_sequential_gates = netlist_abstr.nl->get_gates([&](auto g) { return g->get_type()->has_property(GateTypeProperty::ff); }); - std::sort(netlist_abstr.all_sequential_gates.begin(), netlist_abstr.all_sequential_gates.end(), [](const Gate* g1, const Gate* g2) { return g1->get_id() < g2->get_id(); }); + log_info("dataflow", "identifying target gates"); + netlist_abstr.target_gates = netlist_abstr.nl->get_gates([config](auto g) { return config.gate_types.find(g->get_type()) != config.gate_types.end(); }); + std::sort(netlist_abstr.target_gates.begin(), netlist_abstr.target_gates.end(), [](const Gate* g1, const Gate* g2) { return g1->get_id() < g2->get_id(); }); log_info("dataflow", " #gates: {}", netlist_abstr.nl->get_gates().size()); - log_info("dataflow", " #sequential gates: {}", netlist_abstr.all_sequential_gates.size()); + log_info("dataflow", " #target gates: {}", netlist_abstr.target_gates.size()); } - void identify_all_control_signals(NetlistAbstraction& netlist_abstr) + void identify_all_control_signals(const dataflow::Configuration& config, NetlistAbstraction& netlist_abstr) { auto begin_time = std::chrono::high_resolution_clock::now(); log_info("dataflow", "identifying control signals"); - for (auto sg : netlist_abstr.all_sequential_gates) + for (auto sg : netlist_abstr.target_gates) { std::vector fingerprint; auto id = sg->get_id(); - sg->get_name(); - for (auto net : netlist_utils::get_nets_at_pins( - sg, sg->get_type()->get_pins([](const GatePin* p) { return p->get_direction() == PinDirection::input && p->get_type() == PinType::clock; }))) + for (auto type : config.control_pin_types) { - netlist_abstr.gate_to_clock_signals[id].insert(net->get_id()); - fingerprint.push_back(net->get_id()); + for (auto net : + netlist_utils::get_nets_at_pins(sg, sg->get_type()->get_pins([type](const GatePin* p) { return p->get_direction() == PinDirection::input && p->get_type() == type; }))) + { + netlist_abstr.gate_to_control_signals[id][type].insert(net->get_id()); + fingerprint.push_back(net->get_id()); + } } - for (auto net : netlist_utils::get_nets_at_pins( - sg, sg->get_type()->get_pins([](const GatePin* p) { return p->get_direction() == PinDirection::input && p->get_type() == PinType::enable; }))) - { - netlist_abstr.gate_to_enable_signals[id].insert(net->get_id()); - fingerprint.push_back(net->get_id()); - } + netlist_abstr.gate_to_fingerprint[id] = fingerprint; + } + + log_info("dataflow", " done after {:3.2f}s", seconds_since(begin_time)); + } - for (auto net : netlist_utils::get_nets_at_pins( - sg, sg->get_type()->get_pins([](const GatePin* p) { return p->get_direction() == PinDirection::input && p->get_type() == PinType::reset; }))) + void identify_known_groups(const dataflow::Configuration& config, NetlistAbstraction& netlist_abstr, std::vector>& known_target_groups) + { + // for known gates, only check if they all match the target gate types; discard groups that do not + for (const auto& gates : config.known_gate_groups) + { + if (std::all_of( + gates.begin(), gates.end(), [&netlist_abstr](const Gate* g) { return netlist_abstr.gate_to_fingerprint.find(g->get_id()) != netlist_abstr.gate_to_fingerprint.end(); })) { - netlist_abstr.gate_to_reset_signals[id].insert(net->get_id()); - fingerprint.push_back(net->get_id()); + known_target_groups.push_back(gates); } - - for (auto net : - netlist_utils::get_nets_at_pins(sg, sg->get_type()->get_pins([](const GatePin* p) { return p->get_direction() == PinDirection::input && p->get_type() == PinType::set; }))) + else { - netlist_abstr.gate_to_set_signals[id].insert(net->get_id()); - fingerprint.push_back(net->get_id()); + log_warning("dataflow", + "known group containing gate '{}' with ID {} contains gates that are not of the target gate type, known group will be ignored...", + gates.front()->get_name(), + gates.front()->get_id()); } - - netlist_abstr.gate_to_fingerprint[id] = fingerprint; } - - log_info("dataflow", " done after {:3.2f}s", seconds_since(begin_time)); } /* get all successor/predecessor FFs of all FFs */ - void identify_all_succesors_predecessors_ffs_of_all_ffs(NetlistAbstraction& netlist_abstr) + void identify_successors_predecessors(const dataflow::Configuration& config, NetlistAbstraction& netlist_abstr) { log_info("dataflow", "identifying successors and predecessors of sequential gates..."); measure_block_time("identifying successors and predecessors of sequential gates") ProgressPrinter progress_bar; float cnt = 0; - std::unordered_map> cache; + // cache map of nets to group indices of known net groups + std::unordered_map net_to_group_index; + for (u32 i = 0; i < config.known_net_groups.size(); i++) + { + const auto& net_group = config.known_net_groups.at(i); + if (net_group.size() < config.min_group_size) + { + continue; + } + + for (const auto* net : net_group) + { + net_to_group_index[net] = i; + } + } - for (const auto& single_ff : netlist_abstr.all_sequential_gates) + // find successors + std::unordered_map, std::unordered_set>> suc_cache; + std::unordered_map> pred_cache; + for (const auto& gate : netlist_abstr.target_gates) { cnt++; - progress_bar.print_progress(cnt / netlist_abstr.all_sequential_gates.size()); + progress_bar.print_progress(cnt / netlist_abstr.target_gates.size()); + // create sets even if there are no successors - if (netlist_abstr.gate_to_successors.find(single_ff->get_id()) == netlist_abstr.gate_to_successors.end()) + if (netlist_abstr.gate_to_successors.find(gate->get_id()) == netlist_abstr.gate_to_successors.end()) + { + netlist_abstr.gate_to_successors[gate->get_id()] = std::unordered_set(); + } + if (netlist_abstr.gate_to_predecessors.find(gate->get_id()) == netlist_abstr.gate_to_predecessors.end()) + { + netlist_abstr.gate_to_predecessors[gate->get_id()] = std::unordered_set(); + } + if (netlist_abstr.gate_to_known_successor_groups.find(gate->get_id()) == netlist_abstr.gate_to_known_successor_groups.end()) + { + netlist_abstr.gate_to_known_successor_groups[gate->get_id()] = std::unordered_set(); + } + if (netlist_abstr.gate_to_known_predecessor_groups.find(gate->get_id()) == netlist_abstr.gate_to_known_predecessor_groups.end()) { - netlist_abstr.gate_to_successors[single_ff->get_id()] = std::unordered_set(); + netlist_abstr.gate_to_known_predecessor_groups[gate->get_id()] = std::unordered_set(); } - if (netlist_abstr.gate_to_predecessors.find(single_ff->get_id()) == netlist_abstr.gate_to_predecessors.end()) + + const auto& start_fan_out_nets = gate->get_fan_out_nets(); + std::vector stack(start_fan_out_nets.cbegin(), start_fan_out_nets.cend()); // init stack with fan-out of start gate + std::unordered_set visited; + std::vector previous; // will keep track of all predecessor nets of the current net + while (!stack.empty()) { - netlist_abstr.gate_to_predecessors[single_ff->get_id()] = std::unordered_set(); + const Net* current = stack.back(); // do not pop last item yet + + if (!previous.empty() && current == previous.back()) + { + // will execute when coming back to a net along the path of predecessor nets (i.e., after finding a target gate or when unable to propagate further) + stack.pop_back(); + previous.pop_back(); + continue; + } + + visited.insert(current); + + if (const auto suc_cache_it = suc_cache.find(current); suc_cache_it != suc_cache.end()) + { + auto& suc_cache_current = std::get<1>(*suc_cache_it); + const auto& suc_cached_gates = std::get<0>(suc_cache_current); + const auto& suc_cached_net_groups = std::get<1>(suc_cache_current); + + // add cached target gates and known successor net groups to suc_cache of all predecessor nets + for (const auto* n : previous) + { + auto& suc_cache_n = suc_cache[n]; + std::get<0>(suc_cache_n).insert(suc_cached_gates.cbegin(), suc_cached_gates.cend()); + std::get<1>(suc_cache_n).insert(suc_cached_net_groups.cbegin(), suc_cached_net_groups.cend()); + } + + // add cached net groups to known successor net groups of current gate + netlist_abstr.gate_to_known_successor_groups[gate->get_id()].insert(suc_cached_net_groups.cbegin(), suc_cached_net_groups.cend()); + + stack.pop_back(); + } + else + { + if (const auto group_it = net_to_group_index.find(current); group_it != net_to_group_index.end()) + { + std::get<1>(suc_cache[current]).insert(group_it->second); + for (const auto* n : previous) + { + std::get<1>(suc_cache[n]).insert(group_it->second); + } + netlist_abstr.gate_to_known_successor_groups[gate->get_id()].insert(group_it->second); + } + + bool added = false; + for (const auto* ep : current->get_destinations()) + { + auto* g = ep->get_gate(); + if (config.gate_types.find(g->get_type()) != config.gate_types.end()) + { + // if target gate found, add to suc_cache of all nets along the predecessor path + auto& suc_cache_current = suc_cache[current]; + std::get<0>(suc_cache_current).insert(g); + for (const auto* n : previous) + { + std::get<0>(suc_cache[n]).insert(g); + } + } + else + { + // propagate further by adding successors to stack + for (const auto* n : g->get_fan_out_nets()) + { + if (visited.find(n) == visited.end()) + { + stack.push_back(n); + added = true; + } + } + } + } + + if (added) + { + // keep track of previous net whenever propagating further + previous.push_back(current); + } + else + { + // if no change to stack, go back + stack.pop_back(); + } + } } - for (const auto& suc : netlist_utils::get_next_sequential_gates(single_ff, true, cache)) + + const auto& start_fan_in_nets = gate->get_fan_in_nets(); + stack = std::vector(start_fan_in_nets.begin(), start_fan_in_nets.end()); + visited.clear(); + previous.clear(); + while (!stack.empty()) { - netlist_abstr.gate_to_successors[single_ff->get_id()].insert(suc->get_id()); - netlist_abstr.gate_to_predecessors[suc->get_id()].insert(single_ff->get_id()); + const Net* current = stack.back(); // do not pop last item yet + + if (!previous.empty() && current == previous.back()) + { + // will execute when coming back to a net along the path of predecessor nets (i.e., after finding a target gate or when unable to propagate further) + stack.pop_back(); + previous.pop_back(); + continue; + } + + visited.insert(current); + + if (const auto pred_cache_it = pred_cache.find(current); pred_cache_it != pred_cache.end()) + { + auto& pred_cached_net_groups = std::get<1>(*pred_cache_it); + + // add cached known predecessor net groups to cache of all predecessor nets + for (const auto* n : previous) + { + pred_cache[n].insert(pred_cached_net_groups.cbegin(), pred_cached_net_groups.cend()); + } + + // add cached net groups to known predecessor net groups of current gate + netlist_abstr.gate_to_known_predecessor_groups[gate->get_id()].insert(pred_cached_net_groups.cbegin(), pred_cached_net_groups.cend()); + + stack.pop_back(); + } + else + { + if (const auto group_it = net_to_group_index.find(current); group_it != net_to_group_index.end()) + { + pred_cache[current].insert(group_it->second); + for (const auto* n : previous) + { + pred_cache[n].insert(group_it->second); + } + netlist_abstr.gate_to_known_predecessor_groups[gate->get_id()].insert(group_it->second); + } + + bool added = false; + for (const auto* ep : current->get_sources()) + { + auto* g = ep->get_gate(); + if (config.gate_types.find(g->get_type()) == config.gate_types.end()) + { + // propagate further by adding predecessors to stack + for (const auto* n : g->get_fan_in_nets()) + { + if (visited.find(n) == visited.end()) + { + stack.push_back(n); + added = true; + } + } + } + } + + if (added) + { + // keep track of previous net whenever propagating further + previous.push_back(current); + } + else + { + // if no change to stack, go back + stack.pop_back(); + } + } + } + + // collect successor target gates by getting cache of all fan-out nets of start gate + std::unordered_set next_target_gates; + for (const auto* n : start_fan_out_nets) + { + if (const auto it = suc_cache.find(n); it != suc_cache.end()) + { + const auto& cached_gates = std::get<0>(std::get<1>(*it)); + next_target_gates.insert(cached_gates.cbegin(), cached_gates.cend()); + } + } + + for (const auto& suc : next_target_gates) + { + netlist_abstr.gate_to_successors[gate->get_id()].insert(suc->get_id()); + netlist_abstr.gate_to_predecessors[suc->get_id()].insert(gate->get_id()); } } progress_bar.clear(); } } // namespace - NetlistAbstraction run(Netlist* netlist, bool register_stage_identification) + NetlistAbstraction run(const dataflow::Configuration& config, std::shared_ptr& initial_grouping) { log_info("dataflow", "pre-processing netlist..."); measure_block_time("pre-processing"); - NetlistAbstraction netlist_abstr(netlist); - //remove_buffers(netlist_abstr); - identify_all_sequential_gates(netlist_abstr); - //merge_duplicated_logic_cones(netlist_abstr); - identify_all_control_signals(netlist_abstr); - identify_all_succesors_predecessors_ffs_of_all_ffs(netlist_abstr); - - if (register_stage_identification) + NetlistAbstraction netlist_abstr(config.netlist); + std::vector> known_target_groups; + std::vector> known_net_groups; + identify_all_target_gates(config, netlist_abstr); + identify_all_control_signals(config, netlist_abstr); + identify_known_groups(config, netlist_abstr, known_target_groups); + identify_successors_predecessors(config, netlist_abstr); + + if (config.enable_stages) { identify_register_stages(netlist_abstr); } + initial_grouping = std::make_shared(netlist_abstr, known_target_groups); + return netlist_abstr; } } // namespace pre_processing - } // namespace dataflow + } // namespace dataflow } // namespace hal diff --git a/plugins/dataflow_analysis/src/pre_processing/register_stage_identification.cpp b/plugins/dataflow_analysis/src/pre_processing/register_stage_identification.cpp index b71692eb853..0e046ae7d4b 100644 --- a/plugins/dataflow_analysis/src/pre_processing/register_stage_identification.cpp +++ b/plugins/dataflow_analysis/src/pre_processing/register_stage_identification.cpp @@ -39,7 +39,7 @@ namespace hal log_info("dataflow", "directional register stages: {}", ctx.name); std::unordered_set unassigned_gates; - for (const auto& g : netlist_abstr.all_sequential_gates) + for (const auto& g : netlist_abstr.target_gates) { unassigned_gates.insert(g->get_id()); } @@ -50,10 +50,10 @@ namespace hal float cnt = 0; std::unordered_map stage_index_of_gate; - for (const auto& sequential_gate : netlist_abstr.all_sequential_gates) + for (const auto& sequential_gate : netlist_abstr.target_gates) { cnt++; - progress_bar.print_progress(cnt / netlist_abstr.all_sequential_gates.size()); + progress_bar.print_progress(cnt / netlist_abstr.target_gates.size()); auto current = sequential_gate->get_id(); @@ -353,5 +353,5 @@ namespace hal } } // namespace pre_processing - } // namespace dataflow + } // namespace dataflow } // namespace hal diff --git a/plugins/dataflow_analysis/src/processing/pass_collection.cpp b/plugins/dataflow_analysis/src/processing/pass_collection.cpp index cb9c02b16e7..854299706f1 100644 --- a/plugins/dataflow_analysis/src/processing/pass_collection.cpp +++ b/plugins/dataflow_analysis/src/processing/pass_collection.cpp @@ -3,9 +3,10 @@ #include "dataflow_analysis/processing/configuration.h" #include "dataflow_analysis/processing/passes/group_by_control_signals.h" #include "dataflow_analysis/processing/passes/group_by_input_output_size.h" +#include "dataflow_analysis/processing/passes/group_by_successor_predecessor_known_groups.h" #include "dataflow_analysis/processing/passes/group_by_successors_predecessors.h" #include "dataflow_analysis/processing/passes/group_by_successors_predecessors_iteratively.h" -#include "dataflow_analysis/processing/passes/merge_successor_predecessor_groupings.h" +#include "dataflow_analysis/processing/passes/split_by_successor_predecessor_known_groups.h" #include "dataflow_analysis/processing/passes/split_by_successors_predecessors.h" #include @@ -31,7 +32,7 @@ namespace hal std::vector m_all_passes; std::vector m_intermediate_passes; std::unordered_map> m_useless_follow_ups; - bool m_initialized; + bool m_initialized = false; PassConfiguration group_by_ctrl_sigs; @@ -41,19 +42,25 @@ namespace hal PassConfiguration group_by_successors; PassConfiguration group_by_predecessors; + PassConfiguration group_by_successor_known_groups; + PassConfiguration group_by_predecessor_known_groups; + PassConfiguration group_by_successors_iteratively; PassConfiguration group_by_predecessors_iteratively; PassConfiguration split_by_successors; PassConfiguration split_by_predecessors; + PassConfiguration split_by_successor_known_groups; + PassConfiguration split_by_predecessor_known_groups; + void initialize(const Configuration& config) { using namespace std::placeholders; // start passes - group_by_ctrl_sigs = m_all_passes.emplace_back(std::bind(&group_by_control_signals::process, config, _1, true, true, true, true)); + group_by_ctrl_sigs = m_all_passes.emplace_back(std::bind(&group_by_control_signals::process, config, _1)); group_by_output_size = m_all_passes.emplace_back(std::bind(&group_by_input_output_size::process, config, _1, false)); group_by_input_size = m_all_passes.emplace_back(std::bind(&group_by_input_output_size::process, config, _1, true)); @@ -67,10 +74,20 @@ namespace hal split_by_successors = m_all_passes.emplace_back(std::bind(&split_by_successors_predecessors::process, config, _1, true)); split_by_predecessors = m_all_passes.emplace_back(std::bind(&split_by_successors_predecessors::process, config, _1, false)); + if (config.has_known_groups) + { + group_by_successor_known_groups = m_all_passes.emplace_back(std::bind(&group_by_successor_predecessor_known_groups::process, config, _1, true)); + group_by_predecessor_known_groups = m_all_passes.emplace_back(std::bind(&group_by_successor_predecessor_known_groups::process, config, _1, false)); + split_by_successor_known_groups = m_all_passes.emplace_back(std::bind(&split_by_successor_predecessor_known_groups::process, config, _1, true)); + split_by_predecessor_known_groups = m_all_passes.emplace_back(std::bind(&split_by_successor_predecessor_known_groups::process, config, _1, false)); + } + m_useless_follow_ups[group_by_successors.id].insert(split_by_successors.id); m_useless_follow_ups[group_by_predecessors.id].insert(split_by_predecessors.id); m_useless_follow_ups[group_by_successors_iteratively.id].insert(group_by_successors.id); m_useless_follow_ups[group_by_predecessors_iteratively.id].insert(group_by_predecessors.id); + m_useless_follow_ups[group_by_successor_known_groups.id].insert(split_by_successor_known_groups.id); + m_useless_follow_ups[group_by_predecessor_known_groups.id].insert(split_by_predecessor_known_groups.id); m_initialized = true; } @@ -112,7 +129,11 @@ namespace hal return passes; } + void clear() + { + m_initialized = false; + } } // namespace pass_collection - } // namespace processing - } // namespace dataflow -} \ No newline at end of file + } // namespace processing + } // namespace dataflow +} // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/src/processing/passes/group_by_control_signals.cpp b/plugins/dataflow_analysis/src/processing/passes/group_by_control_signals.cpp index 61c9ad7bbcf..f60e38931bb 100644 --- a/plugins/dataflow_analysis/src/processing/passes/group_by_control_signals.cpp +++ b/plugins/dataflow_analysis/src/processing/passes/group_by_control_signals.cpp @@ -13,7 +13,7 @@ namespace hal { namespace group_by_control_signals { - std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state, bool clock, bool clock_enable, bool reset, bool set) + std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state) { auto new_state = std::make_shared(state->netlist_abstr); @@ -22,27 +22,10 @@ namespace hal for (const auto& [group_id, gates] : state->gates_of_group) { std::set candidate_characteristic_set; - if (clock) + for (const auto& [_, signals] : state->get_control_signals_of_group(group_id)) { - auto signals = state->get_clock_signals_of_group(group_id); candidate_characteristic_set.insert(signals.begin(), signals.end()); } - if (clock_enable) - { - auto signals = state->get_control_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - if (reset) - { - auto signals = state->get_reset_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - if (set) - { - auto signals = state->get_set_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - characteristics_map[candidate_characteristic_set].insert(group_id); } @@ -97,63 +80,6 @@ namespace hal return new_state; } - - std::shared_ptr pure_control_signals_process(const processing::Configuration& config, const std::shared_ptr& state, bool clock, bool clock_enable, bool reset, bool set) - { - auto new_state = std::make_shared(state->netlist_abstr); - - /* check characteristics */ - std::map, std::unordered_set> characteristics_map; - for (const auto& [group_id, gates] : state->gates_of_group) - { - std::set candidate_characteristic_set; - if (clock) - { - auto signals = state->get_clock_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - if (clock_enable) - { - auto signals = state->get_control_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - if (reset) - { - auto signals = state->get_reset_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - if (set) - { - auto signals = state->get_set_signals_of_group(group_id); - candidate_characteristic_set.insert(signals.begin(), signals.end()); - } - - characteristics_map[candidate_characteristic_set].insert(group_id); - } - - /* merge groups */ - u32 id_counter = -1; - for (const auto& it : characteristics_map) - { - auto& groups_to_merge = it.second; - u32 new_group_id = ++id_counter; - - for (const auto& old_group : groups_to_merge) - { - auto gates = state->gates_of_group.at(old_group); - new_state->group_control_fingerprint_map[new_group_id] = new_state->netlist_abstr.gate_to_fingerprint.at(*gates.begin()); - new_state->operations_on_group_allowed[new_group_id] = state->operations_on_group_allowed.at(old_group); - new_state->gates_of_group[new_group_id].insert(gates.begin(), gates.end()); - for (const auto& g : gates) - { - new_state->parent_group_of_gate[g] = new_group_id; - } - } - } - - return new_state; - } - } // namespace group_by_control_signals - } // namespace dataflow + } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/src/processing/passes/group_by_successor_predecessor_known_groups.cpp b/plugins/dataflow_analysis/src/processing/passes/group_by_successor_predecessor_known_groups.cpp new file mode 100644 index 00000000000..26598a0dc73 --- /dev/null +++ b/plugins/dataflow_analysis/src/processing/passes/group_by_successor_predecessor_known_groups.cpp @@ -0,0 +1,109 @@ +#include "dataflow_analysis/processing/passes/group_by_successor_predecessor_known_groups.h" + +#include "dataflow_analysis/common/grouping.h" +#include "dataflow_analysis/common/netlist_abstraction.h" +#include "dataflow_analysis/processing/configuration.h" + +#include +#include +#include + +namespace hal +{ + namespace dataflow + { + namespace group_by_successor_predecessor_known_groups + { + std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state, bool successors) + { + auto new_state = std::make_shared(state->netlist_abstr); + + /* check characteristics */ + std::map, std::list> characteristics_map; + std::vector groups_with_no_characteristics; + for (const auto& [group_id, group] : state->gates_of_group) + { + std::set characteristics_of_group; + + if (successors) + { + auto successing_known_group = state->get_known_successor_groups_of_group(group_id); + characteristics_of_group.insert(successing_known_group.begin(), successing_known_group.end()); + } + else + { + auto predecessing_known_group = state->get_known_predecessor_groups_of_group(group_id); + characteristics_of_group.insert(predecessing_known_group.begin(), predecessing_known_group.end()); + } + + if (characteristics_of_group.empty()) + { + groups_with_no_characteristics.push_back(group_id); + } + else + { + characteristics_map[characteristics_of_group].push_back(group_id); + } + } + + /* check if merge is allowed */ + std::vector> merge_sets; + for (auto& merge_candidates : characteristics_map) + { + auto& work_list = merge_candidates.second; + while (!work_list.empty()) + { + auto it = work_list.begin(); + auto group_id = *it; + it = work_list.erase(it); + + std::vector merge_set = {group_id}; + + while (it != work_list.end()) + { + auto test_group_id = *it; + + if (!state->are_groups_allowed_to_merge(group_id, test_group_id, config.enforce_type_consistency)) + { + ++it; + continue; + } + + merge_set.push_back(test_group_id); + it = work_list.erase(it); + } + merge_sets.push_back(merge_set); + } + } + + /* add all groups with no characteristics as singleton merge set */ + for (const auto& group_id : groups_with_no_characteristics) + { + merge_sets.push_back({group_id}); + } + + /* merge groups */ + u32 id_counter = -1; + for (const auto& groups_to_merge : merge_sets) + { + u32 new_group_id = ++id_counter; + + for (const auto& old_group : groups_to_merge) + { + auto gates = state->gates_of_group.at(old_group); + new_state->group_control_fingerprint_map[new_group_id] = new_state->netlist_abstr.gate_to_fingerprint.at(*gates.begin()); + new_state->operations_on_group_allowed[new_group_id] = state->operations_on_group_allowed.at(old_group); + new_state->gates_of_group[new_group_id].insert(gates.begin(), gates.end()); + for (const auto& sg : gates) + { + new_state->parent_group_of_gate[sg] = new_group_id; + } + } + } + + return new_state; + } + + } // namespace group_by_successor_predecessor_known_groups + } // namespace dataflow +} // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/src/processing/passes/remove_duplicates.cpp b/plugins/dataflow_analysis/src/processing/passes/remove_duplicates.cpp index 1160f57aa0c..ddaf460f6ed 100644 --- a/plugins/dataflow_analysis/src/processing/passes/remove_duplicates.cpp +++ b/plugins/dataflow_analysis/src/processing/passes/remove_duplicates.cpp @@ -104,7 +104,7 @@ namespace hal } /* insert missing gates */ - for (auto gate : state->netlist_abstr.all_sequential_gates) + for (auto gate : state->netlist_abstr.target_gates) { u32 gate_id = gate->get_id(); if (merged_gates.find(gate_id) == merged_gates.end()) @@ -123,5 +123,5 @@ namespace hal return new_state; } } // namespace remove_duplicates - } // namespace dataflow + } // namespace dataflow } // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/src/processing/passes/split_by_successor_predecessor_known_groups.cpp b/plugins/dataflow_analysis/src/processing/passes/split_by_successor_predecessor_known_groups.cpp new file mode 100644 index 00000000000..878708df8a0 --- /dev/null +++ b/plugins/dataflow_analysis/src/processing/passes/split_by_successor_predecessor_known_groups.cpp @@ -0,0 +1,82 @@ +#include "dataflow_analysis/processing/passes/split_by_successor_predecessor_known_groups.h" + +#include "dataflow_analysis/common/grouping.h" +#include "dataflow_analysis/common/netlist_abstraction.h" +#include "dataflow_analysis/processing/configuration.h" + +#include +#include + +namespace hal +{ + namespace dataflow + { + namespace split_by_successor_predecessor_known_groups + { + std::shared_ptr process(const processing::Configuration& config, const std::shared_ptr& state, bool successors) + { + auto new_state = std::make_shared(state->netlist_abstr); + + u32 id_counter = -1; + for (const auto& [group_id, gates] : state->gates_of_group) + { + if (!state->is_group_allowed_to_split(group_id)) + { + u32 new_group_id = ++id_counter; + + new_state->group_control_fingerprint_map[new_group_id] = state->netlist_abstr.gate_to_fingerprint.at(*gates.begin()); + new_state->operations_on_group_allowed[new_group_id] = state->operations_on_group_allowed.at(group_id); + + new_state->gates_of_group[new_group_id].insert(gates.begin(), gates.end()); + for (const auto& sg : gates) + { + new_state->parent_group_of_gate[sg] = new_group_id; + } + } + else + { + std::map, std::unordered_set> characteristics_map; + for (auto gate : gates) + { + std::set characteristics_of_gate; + if (successors) + { + for (auto known_group_successors : state->netlist_abstr.gate_to_known_successor_groups.at(gate)) + { + characteristics_of_gate.insert(known_group_successors); + } + } + else + { + for (auto known_group_predecessors : state->netlist_abstr.gate_to_known_predecessor_groups.at(gate)) + { + characteristics_of_gate.insert(known_group_predecessors); + } + } + + characteristics_map[characteristics_of_gate].insert(gate); + } + + /* merge gates */ + for (auto gates_to_merge : characteristics_map) + { + u32 new_group_id = ++id_counter; + + new_state->group_control_fingerprint_map[new_group_id] = new_state->netlist_abstr.gate_to_fingerprint.at(*gates_to_merge.second.begin()); + new_state->operations_on_group_allowed[new_group_id] = state->operations_on_group_allowed.at(group_id); + + new_state->gates_of_group[new_group_id].insert(gates_to_merge.second.begin(), gates_to_merge.second.end()); + for (const auto& sg : gates_to_merge.second) + { + new_state->parent_group_of_gate[sg] = new_group_id; + } + } + } + } + + return new_state; + } + + } // namespace split_by_successor_predecessor_known_groups + } // namespace dataflow +} // namespace hal \ No newline at end of file diff --git a/plugins/dataflow_analysis/src/processing/processing.cpp b/plugins/dataflow_analysis/src/processing/processing.cpp index 5104d5d7863..7261dd4c9c9 100644 --- a/plugins/dataflow_analysis/src/processing/processing.cpp +++ b/plugins/dataflow_analysis/src/processing/processing.cpp @@ -115,7 +115,8 @@ namespace hal } } - std::vector, PassConfiguration>> generate_pass_combinations(Context& ctx, const Configuration& config, const std::shared_ptr& initial_grouping) + std::vector, PassConfiguration>> + generate_pass_combinations(Context& ctx, const Configuration& config, const std::shared_ptr& initial_grouping) { // create current layer of pass combinations; std::vector, PassConfiguration>> output; @@ -258,10 +259,14 @@ namespace hal } log_info("dataflow", " total: {} unique states", ctx.result.unique_groupings.size()); } - + return ctx.result; } + void clear() + { + pass_collection::clear(); + } } // namespace processing - } // namespace dataflow + } // namespace dataflow } // namespace hal