From 8c9ce51a12270a6d3598958cf049becc7ac1b269 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 4 Nov 2024 18:10:14 +0100 Subject: [PATCH] more funcitonality added to netlist traversal and netlist abstraction decorators --- .../netlist_abstraction_decorator.h | 148 +++++- .../decorators/netlist_traversal_decorator.h | 120 +++-- .../netlist_abstraction_decorator.cpp | 286 +++++++++- .../netlist_traversal_decorator.cpp | 497 ++++++++++-------- 4 files changed, 779 insertions(+), 272 deletions(-) diff --git a/include/hal_core/netlist/decorators/netlist_abstraction_decorator.h b/include/hal_core/netlist/decorators/netlist_abstraction_decorator.h index dd0f470355b..28184c5cca1 100644 --- a/include/hal_core/netlist/decorators/netlist_abstraction_decorator.h +++ b/include/hal_core/netlist/decorators/netlist_abstraction_decorator.h @@ -33,6 +33,8 @@ #include "hal_core/netlist/netlist.h" #include "hal_core/utilities/result.h" +#include + namespace hal { /** @@ -42,7 +44,7 @@ namespace hal * This struct holds an abstraction of a netlist by focusing on a subset of gates and their connections. * It provides methods to retrieve predecessors and successors within the abstraction. */ - struct NetlistAbstraction + struct NETLIST_API NetlistAbstraction { public: /** @@ -121,7 +123,7 @@ namespace hal std::vector get_unique_successors(const Endpoint* endpoint) const; /** - * @brief Gets the global input nets that are predecessors of an endpoint within the abstraction. + * @brief Gets the global input nets that are predecessors of an endpoint. * * @param[in] endpoint - The endpoint to get global input predecessors for. * @returns A vector of global input nets. @@ -129,7 +131,7 @@ namespace hal std::vector get_global_input_predecessors(const Endpoint* endpoint) const; /** - * @brief Gets the global output nets that are successors of an endpoint within the abstraction. + * @brief Gets the global output nets that are successors of an endpoint. * * @param[in] endpoint - The endpoint to get global output successors for. * @returns A vector of global output nets. @@ -210,6 +212,108 @@ namespace hal const std::function& exit_endpoint_filter = nullptr, const std::function& entry_endpoint_filter = nullptr) const; + /** + * @brief Finds the length of the shortest path connecting the start gate to a target matching the given filter. + * If there is no such path, an empty optional is returned. + * Computing only the shortest distance is faster than computing the actual path, as it does not keep track of the path to each gate. + * + * @param[in] start - The starting gate. + * @param[in] target_gate - The target gate. + * @param[in] direction - The direction to search in (`PinDirection::input`, `PinDirection::output`, or `PinDirection::inout`). + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and an optional unsigned integer representing the shortest distance on success, an error otherwise. + */ + Result> get_shortest_path_distance(const Gate* start, + const Gate* target_gate, + const PinDirection& direction, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + + /** + * @brief Starting from the given endpoint, traverse the netlist abstraction and return the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`. + * Traverse over gates that do not meet the `target_gate_filter` condition. + * Stop traversal if (1) `continue_on_match` is `false` and the `target_gate_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint, or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint. + * Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. + * + * @param[in] endpoint - The starting endpoint. + * @param[in] direction - The direction to search in (`PinDirection::input` or `PinDirection::output`). + * @param[in] target_gate_filter - Filter condition that must be met for the target gates. + * @param[in] continue_on_match - Set `true` to continue even if `target_gate_filter` evaluates to `true`, `false` otherwise. Defaults to `false`. + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and a set of gates fulfilling the `target_gate_filter` condition on success, an error otherwise. + */ + Result> get_next_matching_gates(const Endpoint* endpoint, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_match = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + + /** + * @brief Starting from the given gate, traverse the netlist abstraction and return the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`. + * Traverse over gates that do not meet the `target_gate_filter` condition. + * Stop traversal if (1) `continue_on_match` is `false` and the `target_gate_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint, or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint. + * Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. + * + * @param[in] gate - The starting gate. + * @param[in] direction - The direction to search in (`PinDirection::input` or `PinDirection::output`). + * @param[in] target_gate_filter - Filter condition that must be met for the target gates. + * @param[in] continue_on_match - Set `true` to continue even if `target_gate_filter` evaluates to `true`, `false` otherwise. Defaults to `false`. + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and a set of gates fulfilling the `target_gate_filter` condition on success, an error otherwise. + */ + Result> get_next_matching_gates(const Gate* gate, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_match = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + + /** + * @brief Starting from the given endpoint, traverse the netlist abstraction and return the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`. + * Continue traversal regardless of whether `target_gate_filter` evaluates to `true` or `false`. + * Stop traversal if (1) `continue_on_mismatch` is `false` and the `target_gate_filter` evaluates to `false`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint, or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint. + * Both `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. + * + * @param[in] endpoint - The starting endpoint. + * @param[in] direction - The direction to search in (`PinDirection::input` or `PinDirection::output`). + * @param[in] target_gate_filter - Filter condition that must be met for the target gates. + * @param[in] continue_on_mismatch - Set `true` to continue even if `target_gate_filter` evaluates to `false`, `false` otherwise. Defaults to `false`. + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and a set of gates fulfilling the `target_gate_filter` condition on success, an error otherwise. + */ + Result> get_next_matching_gates_until(const Endpoint* endpoint, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_mismatch = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + + /** + * @brief Starting from the given gate, traverse the netlist abstraction and return the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`. + * Continue traversal regardless of whether `target_gate_filter` evaluates to `true` or `false`. + * Stop traversal if (1) `continue_on_mismatch` is `false` and the `target_gate_filter` evaluates to `false`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint, or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint. + * Both `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. + * + * @param[in] gate - The starting gate. + * @param[in] direction - The direction to search in (`PinDirection::input` or `PinDirection::output`). + * @param[in] target_gate_filter - Filter condition that must be met for the target gates. + * @param[in] continue_on_mismatch - Set `true` to continue even if `target_gate_filter` evaluates to `false`, `false` otherwise. Defaults to `false`. + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and a set of gates fulfilling the `target_gate_filter` condition on success, an error otherwise. + */ + Result> get_next_matching_gates_until(const Gate* gate, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_mismatch = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + private: /** * @brief Internal method to find the shortest path distance from a set of starting endpoints. @@ -221,12 +325,48 @@ namespace hal * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. * @returns OK() and an optional unsigned integer representing the shortest distance on success, an error otherwise. */ - Result> get_shortest_path_distance_internal(const std::vector start, + Result> get_shortest_path_distance_internal(const std::vector& start, const std::function& target_filter, const PinDirection& direction, const std::function& exit_endpoint_filter = nullptr, const std::function& entry_endpoint_filter = nullptr) const; + /** + * @brief Internal method to traverse the netlist abstraction and return matching gates based on the provided filters. + * + * @param[in] start - The starting endpoints. + * @param[in] direction - The direction to search in. + * @param[in] target_gate_filter - Filter condition that must be met for the target gates. + * @param[in] continue_on_match - Determines whether to continue traversal after a match. + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and a set of gates fulfilling the `target_gate_filter` condition on success, an error otherwise. + */ + Result> get_next_matching_gates_internal(const std::vector& start, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_match, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const; + + /** + * @brief Internal method to traverse the netlist abstraction and return matching gates until certain conditions are met. + * + * @param[in] start - The starting endpoints. + * @param[in] direction - The direction to search in. + * @param[in] target_gate_filter - Filter condition that must be met for the target gates. + * @param[in] continue_on_mismatch - Determines whether to continue traversal after a mismatch. + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and a set of gates fulfilling the `target_gate_filter` condition on success, an error otherwise. + */ + Result> get_next_matching_gates_until_internal(const std::vector& start, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_mismatch = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + /** * @brief The netlist abstraction to operate on. */ diff --git a/include/hal_core/netlist/decorators/netlist_traversal_decorator.h b/include/hal_core/netlist/decorators/netlist_traversal_decorator.h index fd832a89106..1860d87bb19 100644 --- a/include/hal_core/netlist/decorators/netlist_traversal_decorator.h +++ b/include/hal_core/netlist/decorators/netlist_traversal_decorator.h @@ -164,6 +164,48 @@ namespace hal */ Result> get_next_matching_gates_until_depth(const Gate* gate, bool successors, u32 max_depth, const std::function& target_gate_filter = nullptr) const; + /** + * Starting from the given net, traverse the netlist and return only the successor/predecessor endpoints for which the `target_endpoint_filter` evaluates to `true`. + * Traverse over gates that do not meet the `target_endpoint_filter` condition. + * Stop traversal if (1) `continue_on_match` is `false` the `target_endpoint_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint (i.e., when exiting the current gate during traversal), or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint (i.e., when entering the next gate during traversal). + * Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. + * + * @param[in] net - Start net. + * @param[in] successors - Set `true` to get successors, set `false` to get predecessors. + * @param[in] target_endpoint_filter - Filter condition that must be met for the target endpoints. + * @param[in] continue_on_match - Set `true` to continue even if `target_endpoint_filter` evaluated to `true`, `false` otherwise. Defaults to `false`. + * @param[in] exit_endpoint_filter - Filter condition that determines whether to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint. + * @returns The next endpoints fulfilling the target endpoint filter condition on success, an error otherwise. + */ + Result> get_next_matching_endpoints(const Net* net, + bool successors, + const std::function& target_endpoint_filter, + bool continue_on_match = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + + /** + * Starting from the given gate, traverse the netlist and return only the successor/predecessor endpoints for which the `target_endpoint_filter` evaluates to `true`. + * Traverse over gates that do not meet the `target_endpoint_filter` condition. + * Stop traversal if (1) `continue_on_match` is `false` the `target_endpoint_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint (i.e., when exiting the current gate during traversal), or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint (i.e., when entering the next gate during traversal). + * Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. + * + * @param[in] gate - Start gate. + * @param[in] successors - Set `true` to get successors, set `false` to get predecessors. + * @param[in] target_endpoint_filter - Filter condition that must be met for the target endpoints. + * @param[in] continue_on_match - Set `true` to continue even if `target_endpoint_filter` evaluated to `true`, `false` otherwise. Defaults to `false`. + * @param[in] exit_endpoint_filter - Filter condition that determines whether to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint. + * @returns The next endpoints fulfilling the target gate filter condition on success, an error otherwise. + */ + Result> get_next_matching_endpoints(const Gate* gate, + bool successors, + const std::function& target_endpoint_filter, + bool continue_on_match = false, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + /** * Starting from the given net, traverse the netlist and return only the next layer of sequential successor/predecessor gates. * Traverse over gates that are not sequential until a sequential gate is found. @@ -233,6 +275,42 @@ namespace hal Result> get_next_combinational_gates(const Gate* gate, bool successors, const std::set& forbidden_pins = {}, std::unordered_map>* cache = nullptr) const; + /** + * Find the length of the shortest path connecting the start endpoint to a target matching the given filter. + * If there is no such path, an empty optional is returned. + * Computing only the shortest distance is faster than computing the actual path, as it does not keep track of the path to each gate. + * + * @param[in] start - The starting endpoint. + * @param[in] target_filter - A filter function to determine the target endpoints. + * @param[in] direction - The direction to search in (`PinDirection::input`, `PinDirection::output`, or `PinDirection::inout`). + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and an optional unsigned integer representing the shortest distance on success, an error otherwise. + */ + Result> get_shortest_path_distance(Endpoint* start, + const std::function& target_filter, + const PinDirection& direction, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + + /** + * Find the length of the shortest path connecting the start gate to a target matching the given filter. + * If there is no such path, an empty optional is returned. + * Computing only the shortest distance is faster than computing the actual path, as it does not keep track of the path to each gate. + * + * @param[in] start - The starting gate. + * @param[in] target_filter - A filter function to determine the target endpoints. + * @param[in] direction - The direction to search in (`PinDirection::input`, `PinDirection::output`, or `PinDirection::inout`). + * @param[in] exit_endpoint_filter - Filter condition to stop traversal on a fan-in/out endpoint. + * @param[in] entry_endpoint_filter - Filter condition to stop traversal on a successor/predecessor endpoint. + * @returns OK() and an optional unsigned integer representing the shortest distance on success, an error otherwise. + */ + Result> get_shortest_path_distance(const Gate* start, + const std::function& target_filter, + const PinDirection& direction, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; + /** * Find the length of shortest path (i.e., the result set with the lowest number of gates) that connects the start gate with the end gate. * If there is no such path an empty optional is returned. @@ -269,48 +347,6 @@ namespace hal const std::function& exit_endpoint_filter = nullptr, const std::function& entry_endpoint_filter = nullptr) const; - /** - * Starting from the given net, traverse the netlist and return only the successor/predecessor endpoints for which the `target_endpoint_filter` evaluates to `true`. - * Traverse over gates that do not meet the `target_endpoint_filter` condition. - * Stop traversal if (1) `continue_on_match` is `false` the `target_endpoint_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint (i.e., when exiting the current gate during traversal), or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint (i.e., when entering the next gate during traversal). - * Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. - * - * @param[in] net - Start net. - * @param[in] successors - Set `true` to get successors, set `false` to get predecessors. - * @param[in] target_endpoint_filter - Filter condition that must be met for the target endpoints. - * @param[in] continue_on_match - Set `true` to continue even if `target_endpoint_filter` evaluated to `true`, `false` otherwise. Defaults to `false`. - * @param[in] exit_endpoint_filter - Filter condition that determines whether to stop traversal on a fan-in/out endpoint. - * @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint. - * @returns The next endpoints fulfilling the target endpoint filter condition on success, an error otherwise. - */ - Result> get_next_matching_endpoints(const Net* net, - bool successors, - const std::function& target_endpoint_filter, - bool continue_on_match = false, - const std::function& exit_endpoint_filter = nullptr, - const std::function& entry_endpoint_filter = nullptr) const; - - /** - * Starting from the given gate, traverse the netlist and return only the successor/predecessor endpoints for which the `target_endpoint_filter` evaluates to `true`. - * Traverse over gates that do not meet the `target_endpoint_filter` condition. - * Stop traversal if (1) `continue_on_match` is `false` the `target_endpoint_filter` evaluates to `true`, (2) the `exit_endpoint_filter` evaluates to `false` on a fan-in/out endpoint (i.e., when exiting the current gate during traversal), or (3) the `entry_endpoint_filter` evaluates to `false` on a successor/predecessor endpoint (i.e., when entering the next gate during traversal). - * Both the `entry_endpoint_filter` and the `exit_endpoint_filter` may be omitted. - * - * @param[in] gate - Start gate. - * @param[in] successors - Set `true` to get successors, set `false` to get predecessors. - * @param[in] target_endpoint_filter - Filter condition that must be met for the target endpoints. - * @param[in] continue_on_match - Set `true` to continue even if `target_endpoint_filter` evaluated to `true`, `false` otherwise. Defaults to `false`. - * @param[in] exit_endpoint_filter - Filter condition that determines whether to stop traversal on a fan-in/out endpoint. - * @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint. - * @returns The next endpoints fulfilling the target gate filter condition on success, an error otherwise. - */ - Result> get_next_matching_endpoints(const Gate* gate, - bool successors, - const std::function& target_endpoint_filter, - bool continue_on_match = false, - const std::function& exit_endpoint_filter = nullptr, - const std::function& entry_endpoint_filter = nullptr) const; - // TODO move get_gate_chain and get_complex_gate_chain here private: diff --git a/src/netlist/decorators/netlist_abstraction_decorator.cpp b/src/netlist/decorators/netlist_abstraction_decorator.cpp index d43bed29fae..a7f6314cf4e 100644 --- a/src/netlist/decorators/netlist_abstraction_decorator.cpp +++ b/src/netlist/decorators/netlist_abstraction_decorator.cpp @@ -8,7 +8,6 @@ namespace hal { - NetlistAbstraction::NetlistAbstraction(const std::vector& gates, const std::function& exit_endpoint_filter, const std::function& entry_endpoint_filter) @@ -224,7 +223,9 @@ namespace hal return m_global_output_successors.at(endpoint); } - Result> NetlistAbstractionDecorator::get_shortest_path_distance_internal(const std::vector start, + NetlistAbstractionDecorator::NetlistAbstractionDecorator(const hal::NetlistAbstraction& abstraction) : m_abstraction(abstraction) {}; + + Result> NetlistAbstractionDecorator::get_shortest_path_distance_internal(const std::vector& start, const std::function& target_filter, const PinDirection& direction, const std::function& exit_endpoint_filter, @@ -240,7 +241,6 @@ namespace hal if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(start_ep, distance)) { continue; - ; } if (target_filter(start_ep, m_abstraction)) @@ -311,13 +311,13 @@ namespace hal if (direction == PinDirection::inout) { - const auto res_backward = get_shortest_path_distance_internal(start, target_filter, PinDirection::input); + const auto res_backward = get_shortest_path_distance_internal(start, target_filter, PinDirection::input, exit_endpoint_filter, entry_endpoint_filter); if (res_backward.is_error()) { return res_backward; } - const auto res_forward = get_shortest_path_distance_internal(start, target_filter, PinDirection::output); + const auto res_forward = get_shortest_path_distance_internal(start, target_filter, PinDirection::output, exit_endpoint_filter, entry_endpoint_filter); if (res_forward.is_error()) { return res_forward; @@ -376,4 +376,280 @@ namespace hal return get_shortest_path_distance_internal(start_endpoints, target_filter, direction, exit_endpoint_filter, entry_endpoint_filter); } + + Result> NetlistAbstractionDecorator::get_shortest_path_distance(const Gate* start, + const Gate* target, + const PinDirection& direction, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + return get_shortest_path_distance( + start, + [target](const auto* ep, const auto& _abstraction) { + UNUSED(_abstraction); + return ep->get_gate() == target; + }, + direction, + exit_endpoint_filter, + entry_endpoint_filter); + } + + Result> NetlistAbstractionDecorator::get_next_matching_gates_internal(const std::vector& start, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_match, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + std::unordered_set visited; + std::vector stack = start; + std::vector previous; + std::set res; + while (!stack.empty()) + { + const Endpoint* current = stack.back(); + + if (!previous.empty() && current == previous.back()) + { + stack.pop_back(); + previous.pop_back(); + continue; + } + + visited.insert(current); + + bool added = false; + for (const auto* entry_ep : (direction == PinDirection::output) ? m_abstraction.get_successors(current) : m_abstraction.get_predecessors(current)) + { + if (entry_endpoint_filter != nullptr && !entry_endpoint_filter(entry_ep, previous.size() + 1)) + { + continue; + } + + auto* gate = entry_ep->get_gate(); + + if (target_gate_filter(gate)) + { + res.insert(gate); + + if (!continue_on_match) + { + continue; + } + } + + for (const auto* exit_ep : (direction == PinDirection::output) ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) + { + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, previous.size() + 1)) + { + continue; + } + + if (visited.find(exit_ep) == visited.end()) + { + stack.push_back(exit_ep); + added = true; + } + } + } + + if (added) + { + previous.push_back(current); + } + else + { + stack.pop_back(); + } + } + + return OK(res); + } + + Result> NetlistAbstractionDecorator::get_next_matching_gates(const Endpoint* endpoint, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_match, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (endpoint == nullptr) + { + return ERR("nullptr given as endpoint"); + } + + if (!target_gate_filter) + { + return ERR("no target gate filter specified"); + } + + if (endpoint->get_pin()->get_direction() != direction) + { + return get_next_matching_gates(endpoint->get_gate(), direction, target_gate_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter); + } + + return get_next_matching_gates_internal({endpoint}, direction, target_gate_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter); + } + + Result> NetlistAbstractionDecorator::get_next_matching_gates(const Gate* gate, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_match, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (gate == nullptr) + { + return ERR("nullptr given as gate"); + } + + if (!target_gate_filter) + { + return ERR("no target gate filter specified"); + } + + std::vector start; + for (const auto* exit_ep : (direction == PinDirection::output) ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) + { + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, 0)) + { + continue; + } + + start.push_back(exit_ep); + } + + return get_next_matching_gates_internal(start, direction, target_gate_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter); + } + + Result> NetlistAbstractionDecorator::get_next_matching_gates_until_internal(const std::vector& start, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_mismatch, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + std::unordered_set visited; + std::vector stack = start; + std::vector previous; + std::set res; + while (!stack.empty()) + { + const Endpoint* current = stack.back(); + + if (!previous.empty() && current == previous.back()) + { + stack.pop_back(); + previous.pop_back(); + continue; + } + + visited.insert(current); + + bool added = false; + for (const auto* entry_ep : (direction == PinDirection::output) ? m_abstraction.get_successors(current) : m_abstraction.get_predecessors(current)) + { + if (entry_endpoint_filter != nullptr && !entry_endpoint_filter(entry_ep, previous.size() + 1)) + { + continue; + } + + auto* g = entry_ep->get_gate(); + + if (target_gate_filter(g)) + { + res.insert(g); + } + else + { + if (!continue_on_mismatch) + { + continue; + } + } + + for (const auto* exit_ep : (direction == PinDirection::output) ? g->get_fan_out_endpoints() : g->get_fan_in_endpoints()) + { + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, previous.size() + 1)) + { + continue; + } + + if (visited.find(exit_ep) == visited.end()) + { + stack.push_back(exit_ep); + added = true; + } + } + } + + if (added) + { + previous.push_back(current); + } + else + { + stack.pop_back(); + } + } + + return OK(res); + } + + Result> NetlistAbstractionDecorator::get_next_matching_gates_until(const Endpoint* endpoint, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_mismatch, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (endpoint == nullptr) + { + return ERR("nullptr given as endpoint"); + } + + if (!target_gate_filter) + { + return ERR("no target gate filter specified"); + } + + if (endpoint->get_pin()->get_direction() != direction) + { + return get_next_matching_gates_until(endpoint->get_gate(), direction, target_gate_filter, continue_on_mismatch, exit_endpoint_filter, entry_endpoint_filter); + } + + return get_next_matching_gates_until_internal({endpoint}, direction, target_gate_filter, continue_on_mismatch, exit_endpoint_filter, entry_endpoint_filter); + } + + Result> NetlistAbstractionDecorator::get_next_matching_gates_until(const Gate* gate, + const PinDirection& direction, + const std::function& target_gate_filter, + bool continue_on_mismatch, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (gate == nullptr) + { + return ERR("nullptr given as gate"); + } + + if (!target_gate_filter) + { + return ERR("no target gate filter specified"); + } + + std::vector start; + for (const auto* exit_ep : (direction == PinDirection::output) ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) + { + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, 0)) + { + continue; + } + + start.push_back(exit_ep); + } + + return get_next_matching_gates_internal(start, direction, target_gate_filter, continue_on_mismatch, exit_endpoint_filter, entry_endpoint_filter); + } + } // namespace hal \ No newline at end of file diff --git a/src/netlist/decorators/netlist_traversal_decorator.cpp b/src/netlist/decorators/netlist_traversal_decorator.cpp index cf7a1bd5a5e..2bc4c9dc9cc 100644 --- a/src/netlist/decorators/netlist_traversal_decorator.cpp +++ b/src/netlist/decorators/netlist_traversal_decorator.cpp @@ -363,6 +363,157 @@ namespace hal return OK(res); } + Result> NetlistTraversalDecorator::get_next_matching_endpoints(const Net* net, + bool successors, + const std::function& target_endpoint_filter, + bool continue_on_match, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (net == nullptr) + { + return ERR("nullptr given as net"); + } + + if (!m_netlist.is_net_in_netlist(net)) + { + return ERR("net does not belong to netlist"); + } + + if (!target_endpoint_filter) + { + return ERR("no target endpoint filter specified"); + } + + std::unordered_set visited; + std::vector stack = {net}; + std::vector previous; + std::set res; + while (!stack.empty()) + { + const Net* current = stack.back(); + + if (!previous.empty() && current == previous.back()) + { + stack.pop_back(); + previous.pop_back(); + continue; + } + + visited.insert(current); + + bool added = false; + for (auto* entry_ep : successors ? current->get_destinations() : current->get_sources()) + { + if (entry_endpoint_filter != nullptr && !entry_endpoint_filter(entry_ep, previous.size() + 1)) + { + continue; + } + + if (target_endpoint_filter(entry_ep)) + { + res.insert(entry_ep); + + if (!continue_on_match) + { + continue; + } + } + + auto* gate = entry_ep->get_gate(); + + for (auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) + { + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, previous.size() + 1)) + { + continue; + } + + if (target_endpoint_filter(exit_ep)) + { + res.insert(exit_ep); + + if (!continue_on_match) + { + continue; + } + } + + const Net* exit_net = exit_ep->get_net(); + + if (visited.find(exit_net) == visited.end()) + { + stack.push_back(exit_net); + added = true; + } + } + } + + if (added) + { + previous.push_back(current); + } + else + { + stack.pop_back(); + } + } + + return OK(res); + } + + Result> NetlistTraversalDecorator::get_next_matching_endpoints(const Gate* gate, + bool successors, + const std::function& target_endpoint_filter, + bool continue_on_match, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (gate == nullptr) + { + return ERR("nullptr given as gate"); + } + + if (!m_netlist.is_gate_in_netlist(gate)) + { + return ERR("net does not belong to netlist"); + } + + if (!target_endpoint_filter) + { + return ERR("no target endpoint filter specified"); + } + + std::set res; + for (auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) + { + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, 0)) + { + continue; + } + + if (target_endpoint_filter(exit_ep)) + { + res.insert(exit_ep); + + if (!continue_on_match) + { + continue; + } + } + + const auto* exit_net = exit_ep->get_net(); + const auto next_res = this->get_next_matching_endpoints(exit_net, successors, target_endpoint_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter); + if (next_res.is_error()) + { + return ERR(next_res.get_error()); + } + auto next = next_res.get(); + res.insert(next.begin(), next.end()); + } + return OK(res); + } + Result> NetlistTraversalDecorator::get_next_sequential_gates(const Net* net, bool successors, const std::set& forbidden_pins, std::unordered_map>* cache) const { @@ -701,34 +852,43 @@ namespace hal return OK(res); } - Result> NetlistTraversalDecorator::get_shortest_path_distance(const Gate* start_gate, - const Gate* end_gate, - const PinDirection& direction, - const std::function& exit_endpoint_filter, - const std::function& entry_endpoint_filter) const + namespace { - if (direction == PinDirection::output || direction == PinDirection::input) + Result> get_shortest_path_distance_internal(const std::vector& start, + const std::function& target_filter, + const PinDirection& direction, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) { - std::unordered_set visited; - u32 distance = 0; - - Gate* _start_gate = start_gate->get_netlist()->get_gate_by_id(start_gate->get_id()); - std::vector current = {_start_gate}; - std::vector next; - - while (true) + if (direction == PinDirection::output || direction == PinDirection::input) { - distance++; + u32 distance = 0; - for (const auto& curr_g : current) + // check whether start already fullfills target or exit filter + for (auto* start_ep : start) { - for (const auto& exit_ep : (direction == PinDirection::output) ? curr_g->get_fan_out_endpoints() : curr_g->get_fan_in_endpoints()) + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(start_ep, distance)) { - if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, distance)) - { - continue; - } + continue; + } + if (target_filter(start_ep)) + { + return OK(distance); + } + } + + std::unordered_set visited; + + std::vector current = start; + std::vector next; + + while (true) + { + distance++; + + for (const auto& exit_ep : current) + { for (const auto& entry_ep : (direction == PinDirection::output) ? exit_ep->get_net()->get_destinations() : exit_ep->get_net()->get_sources()) { if (entry_endpoint_filter != nullptr && !entry_endpoint_filter(entry_ep, distance)) @@ -736,78 +896,124 @@ namespace hal continue; } - const auto next_g = entry_ep->get_gate(); - - if (const auto it = visited.find(next_g); it != visited.end()) + if (target_filter(entry_ep)) { - continue; + return OK(distance); } - visited.insert(next_g); - if (next_g == end_gate) + const auto next_g = entry_ep->get_gate(); + + for (const auto& next_ep : (direction == PinDirection::output) ? next_g->get_fan_out_endpoints() : next_g->get_fan_in_endpoints()) { - return OK(distance); - } + if (const auto it = visited.find(next_ep); it != visited.end()) + { + continue; + } + visited.insert(next_ep); - next.push_back(next_g); + if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(next_ep, distance)) + { + continue; + } + + if (target_filter(next_ep)) + { + return OK(distance); + } + + next.push_back(next_ep); + } } } + + if (next.empty()) + { + break; + } + + current = next; + next.clear(); } - if (next.empty()) + return OK({}); + } + + if (direction == PinDirection::inout) + { + const auto res_backward = get_shortest_path_distance_internal(start, target_filter, PinDirection::input, exit_endpoint_filter, entry_endpoint_filter); + if (res_backward.is_error()) { - break; + return res_backward; } - current = next; - next.clear(); - } + const auto res_forward = get_shortest_path_distance_internal(start, target_filter, PinDirection::output, exit_endpoint_filter, entry_endpoint_filter); + if (res_forward.is_error()) + { + return res_forward; + } - return OK({}); - } + const auto distance_backward = res_backward.get(); + const auto distance_forward = res_forward.get(); - if (direction == PinDirection::inout) - { - const auto res_backward = get_shortest_path_distance(start_gate, end_gate, PinDirection::input); - if (res_backward.is_error()) - { - return res_backward; - } + if (!distance_forward.has_value() && !distance_backward.has_value()) + { + return OK({}); + } - const auto res_forward = get_shortest_path_distance(start_gate, end_gate, PinDirection::output); - if (res_forward.is_error()) - { - return res_forward; - } + if (!distance_backward.has_value()) + { + return OK(distance_forward); + } - const auto distance_backward = res_backward.get(); - const auto distance_forward = res_forward.get(); + if (!distance_forward.has_value()) + { + return OK(distance_backward); + } - if (!distance_forward.has_value() && !distance_backward.has_value()) - { - return OK({}); - } + if (distance_backward.value() < distance_forward.value()) + { + return OK(distance_backward); + } - if (!distance_backward.has_value()) - { return OK(distance_forward); } - if (!distance_forward.has_value()) - { - return OK(distance_backward); - } - - if (distance_backward.value() < distance_forward.value()) - { - return OK(distance_backward); - } + return ERR("cannot get shortest path distance between endpoints and given target filter condition: pin direction " + enum_to_string(direction) + " is not supported"); + } + } // namespace - return OK(distance_forward); + Result> NetlistTraversalDecorator::get_shortest_path_distance(Endpoint* start, + const std::function& target_filter, + const PinDirection& direction, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + if (start->get_pin()->get_direction() != direction) + { + return get_shortest_path_distance(start->get_gate(), target_filter, direction, exit_endpoint_filter, entry_endpoint_filter); } - return ERR("cannot get shortest path distance between Gate " + start_gate->get_name() + " with ID " + std::to_string(start_gate->get_id()) + " and Gate " + end_gate->get_name() + " with ID " - + std::to_string(end_gate->get_id()) + ": pin direction " + enum_to_string(direction) + " is not supported"); + return get_shortest_path_distance_internal({start}, target_filter, direction, exit_endpoint_filter, entry_endpoint_filter); + } + + Result> NetlistTraversalDecorator::get_shortest_path_distance(const Gate* start, + const std::function& target_filter, + const PinDirection& direction, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + const auto start_endpoints = (direction == PinDirection::output) ? start->get_fan_out_endpoints() : start->get_fan_in_endpoints(); + + return get_shortest_path_distance_internal(start_endpoints, target_filter, direction, exit_endpoint_filter, entry_endpoint_filter); + } + + Result> NetlistTraversalDecorator::get_shortest_path_distance(const Gate* start_gate, + const Gate* end_gate, + const PinDirection& direction, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const + { + return get_shortest_path_distance(start_gate, [end_gate](const auto* ep) { return ep->get_gate() == end_gate; }, direction, exit_endpoint_filter, entry_endpoint_filter); } Result>> NetlistTraversalDecorator::get_shortest_path(const Gate* start_gate, @@ -945,155 +1151,4 @@ namespace hal + std::to_string(end_gate->get_id()) + ": pin direction " + enum_to_string(direction) + " is not supported"); } - Result> NetlistTraversalDecorator::get_next_matching_endpoints(const Net* net, - bool successors, - const std::function& target_endpoint_filter, - bool continue_on_match, - const std::function& exit_endpoint_filter, - const std::function& entry_endpoint_filter) const - { - if (net == nullptr) - { - return ERR("nullptr given as net"); - } - - if (!m_netlist.is_net_in_netlist(net)) - { - return ERR("net does not belong to netlist"); - } - - if (!target_endpoint_filter) - { - return ERR("no target endpoint filter specified"); - } - - std::unordered_set visited; - std::vector stack = {net}; - std::vector previous; - std::set res; - while (!stack.empty()) - { - const Net* current = stack.back(); - - if (!previous.empty() && current == previous.back()) - { - stack.pop_back(); - previous.pop_back(); - continue; - } - - visited.insert(current); - - bool added = false; - for (auto* entry_ep : successors ? current->get_destinations() : current->get_sources()) - { - if (entry_endpoint_filter != nullptr && !entry_endpoint_filter(entry_ep, previous.size() + 1)) - { - continue; - } - - if (target_endpoint_filter(entry_ep)) - { - res.insert(entry_ep); - - if (!continue_on_match) - { - continue; - } - } - - auto* gate = entry_ep->get_gate(); - - for (auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) - { - if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, previous.size() + 1)) - { - continue; - } - - if (target_endpoint_filter(exit_ep)) - { - res.insert(exit_ep); - - if (!continue_on_match) - { - continue; - } - } - - const Net* exit_net = exit_ep->get_net(); - - if (visited.find(exit_net) == visited.end()) - { - stack.push_back(exit_net); - added = true; - } - } - } - - if (added) - { - previous.push_back(current); - } - else - { - stack.pop_back(); - } - } - - return OK(res); - } - - Result> NetlistTraversalDecorator::get_next_matching_endpoints(const Gate* gate, - bool successors, - const std::function& target_endpoint_filter, - bool continue_on_match, - const std::function& exit_endpoint_filter, - const std::function& entry_endpoint_filter) const - { - if (gate == nullptr) - { - return ERR("nullptr given as gate"); - } - - if (!m_netlist.is_gate_in_netlist(gate)) - { - return ERR("net does not belong to netlist"); - } - - if (!target_endpoint_filter) - { - return ERR("no target endpoint filter specified"); - } - - std::set res; - for (auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) - { - if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, 0)) - { - continue; - } - - if (target_endpoint_filter(exit_ep)) - { - res.insert(exit_ep); - - if (!continue_on_match) - { - continue; - } - } - - const auto* exit_net = exit_ep->get_net(); - const auto next_res = this->get_next_matching_endpoints(exit_net, successors, target_endpoint_filter, continue_on_match, exit_endpoint_filter, entry_endpoint_filter); - if (next_res.is_error()) - { - return ERR(next_res.get_error()); - } - auto next = next_res.get(); - res.insert(next.begin(), next.end()); - } - return OK(res); - } - -} // namespace hal \ No newline at end of file +} // namespace hal