Skip to content

Commit

Permalink
function to get next combinational gates until other gates hit
Browse files Browse the repository at this point in the history
  • Loading branch information
SJulianS committed May 10, 2024
1 parent b3beac6 commit f168f70
Show file tree
Hide file tree
Showing 3 changed files with 258 additions and 2 deletions.
28 changes: 26 additions & 2 deletions include/hal_core/netlist/decorators/netlist_traversal_decorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,6 @@ namespace hal
Result<std::set<Gate*>>
get_next_sequential_gates(const Gate* gate, bool successors, const std::set<PinType>& forbidden_pins, std::unordered_map<const Net*, std::set<Gate*>>* cache = nullptr) const;

// TODO implement get_next_combinational_gates (get all combinational successor gates until sequential (non-combinational) gates are hit)

/**
* Get the next sequential gates for all sequential gates in the netlist by traversing through remaining logic (e.g., combinational logic).
* Compute a map from a sequential gate to all its successors.
Expand All @@ -199,6 +197,32 @@ namespace hal
*/
Result<std::map<Gate*, std::set<Gate*>>> get_next_sequential_gates_map(bool successors, const std::set<PinType>& forbidden_pins) const;

/**
* Starting from the given net, traverse the netlist and return all combinational successor/predecessor gates.
* Continue traversal as long as further combinational gates are found and stop at gates that are not combinational.
* All combinational gates found during traversal are added to the result.
* Provide a cache to speed up traversal when calling this function multiple times on the same netlist.
*
* @param[in] net - Start net.
* @param[in] successors - Set `true` to get successors, set `false` to get predecessors.
* @param[inout] cache - An optional cache that can be used for better performance on repeated calls. Defaults to a `nullptr`.
* @returns The next combinational gates on success, an error otherwise.
*/
Result<std::set<Gate*>> get_next_combinational_gates(const Net* net, bool successors, std::unordered_map<const Net*, std::set<Gate*>>* cache = nullptr) const;

/**
* Starting from the given gate, traverse the netlist and return all combinational successor/predecessor gates.
* Continue traversal as long as further combinational gates are found and stop at gates that are not combinational.
* All combinational gates found during traversal are added to the result.
* Provide a cache to speed up traversal when calling this function multiple times on the same netlist.
*
* @param[in] gate - Start gate.
* @param[in] successors - Set `true` to get successors, set `false` to get predecessors.
* @param[inout] cache - An optional cache that can be used for better performance on repeated calls. Defaults to a `nullptr`.
* @returns The next combinational gates on success, an error otherwise.
*/
Result<std::set<Gate*>> get_next_combinational_gates(const Gate* gate, bool successors, std::unordered_map<const Net*, std::set<Gate*>>* cache = nullptr) const;

// TODO move get_path and get_shortest_path here

// TODO move get_gate_chain and get_complex_gate_chain here
Expand Down
118 changes: 118 additions & 0 deletions src/netlist/decorators/netlist_traversal_decorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,4 +481,122 @@ namespace hal

return OK(std::move(seq_gate_map));
}

Result<std::set<Gate*>> NetlistTraversalDecorator::get_next_combinational_gates(const Net* net, bool successors, std::unordered_map<const Net*, std::set<Gate*>>* cache) 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");
}

std::unordered_set<const Net*> visited;
std::vector<const Net*> stack = {net};
std::vector<const Net*> previous;
std::set<Gate*> 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);

if (cache)
{
if (const auto it = cache->find(current); it != cache->end())
{
const auto& cached_gates = std::get<1>(*it);

// append cached gates to result
res.insert(cached_gates.begin(), cached_gates.end());

// pop net from stack as it has been dealt with
stack.pop_back();

continue;
}
}

bool added = false;
for (const auto* entry_ep : successors ? current->get_destinations() : current->get_sources())
{
auto* gate = entry_ep->get_gate();
if (!gate->get_type()->has_property(GateTypeProperty::combinational))
{
// stop traversal if not combinational
continue;
}

// add to result if gate is combinational
res.insert(gate);

// update cache
if (cache)
{
(*cache)[current].insert(gate);
for (const auto* n : previous)
{
(*cache)[n].insert(gate);
}
}

for (const auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints())
{
const Net* n = exit_ep->get_net();
if (visited.find(n) == visited.end())
{
stack.push_back(n);
added = true;
}
}
}

if (added)
{
previous.push_back(current);
}
else
{
stack.pop_back();
}
}

return OK(res);
}

Result<std::set<Gate*>> NetlistTraversalDecorator::get_next_combinational_gates(const Gate* gate, bool successors, std::unordered_map<const Net*, std::set<Gate*>>* cache) 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");
}

std::set<Gate*> res;
for (const auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints())
{
const auto next_res = this->get_next_combinational_gates(exit_ep->get_net(), successors, cache);
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
114 changes: 114 additions & 0 deletions src/python_bindings/bindings/netlist_traversal_decorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,119 @@ namespace hal
:returns: A dict from each sequential gate to all its sequential successors on success, ``None`` otherwise.
:rtype: dict[hal_py.Gate,set[hal_py.Gate]] or None
)");

py_netlist_traversal_decorator.def(
"get_next_combinational_gates",
[](NetlistTraversalDecorator& self, const Net* net, bool successors) -> std::optional<std::set<Gate*>> {
auto res = self.get_next_combinational_gates(net, successors, nullptr);
if (res.is_ok())
{
return res.get();
}
else
{
log_error("python_context", "error encountered while getting next combinational gates:\n{}", res.get_error().get());
return std::nullopt;
}
},
py::arg("net"),
py::arg("successors"),
R"(
Starting from the given net, traverse the netlist and return all combinational successor/predecessor gates.
Continue traversal as long as further combinational gates are found and stop at gates that are not combinational.
All combinational gates found during traversal are added to the result.
:param hal_py.Net net: Start net.
:param bool successors: Set ``True`` to get successors, set ``False`` to get predecessors.
:returns: The next combinational gates on success, ``None`` otherwise.
:rtype: set[hal_py.Gate] or None
)");

py_netlist_traversal_decorator.def(
"get_next_combinational_gates",
[](NetlistTraversalDecorator& self, const Net* net, bool successors, std::unordered_map<const Net*, std::set<Gate*>>* cache) -> std::optional<std::set<Gate*>> {
auto res = self.get_next_combinational_gates(net, successors, cache);
if (res.is_ok())
{
return res.get();
}
else
{
log_error("python_context", "error encountered while getting next combinational gates:\n{}", res.get_error().get());
return std::nullopt;
}
},
py::arg("net"),
py::arg("successors"),
py::arg("cache"),
R"(
Starting from the given net, traverse the netlist and return all combinational successor/predecessor gates.
Continue traversal as long as further combinational gates are found and stop at gates that are not combinational.
All combinational gates found during traversal are added to the result.
Provide a cache to speed up traversal when calling this function multiple times on the same netlist.
:param hal_py.Net net: Start net.
:param bool successors: Set ``True`` to get successors, set ``False`` to get predecessors.
:param dict[hal_py.Net, set[hal_py.Gate]] cache: A cache that can be used for better performance on repeated calls.
:returns: The next combinational gates on success, ``None`` otherwise.
:rtype: set[hal_py.Gate] or None
)");

py_netlist_traversal_decorator.def(
"get_next_combinational_gates",
[](NetlistTraversalDecorator& self, const Gate* gate, bool successors) -> std::optional<std::set<Gate*>> {
auto res = self.get_next_combinational_gates(gate, successors, nullptr);
if (res.is_ok())
{
return res.get();
}
else
{
log_error("python_context", "error encountered while getting next combinational gates:\n{}", res.get_error().get());
return std::nullopt;
}
},
py::arg("gate"),
py::arg("successors"),
R"(
Starting from the given gate, traverse the netlist and return all combinational successor/predecessor gates.
Continue traversal as long as further combinational gates are found and stop at gates that are not combinational.
All combinational gates found during traversal are added to the result.
:param hal_py.Gate gate: Start gate.
:param bool successors: Set ``True`` to get successors, set ``False`` to get predecessors.
:returns: The next combinational gates on success, ``None`` otherwise.
:rtype: set[hal_py.Gate] or None
)");

py_netlist_traversal_decorator.def(
"get_next_combinational_gates",
[](NetlistTraversalDecorator& self, const Gate* gate, bool successors, std::unordered_map<const Net*, std::set<Gate*>>* cache) -> std::optional<std::set<Gate*>> {
auto res = self.get_next_combinational_gates(gate, successors, cache);
if (res.is_ok())
{
return res.get();
}
else
{
log_error("python_context", "error encountered while getting next combinational gates:\n{}", res.get_error().get());
return std::nullopt;
}
},
py::arg("gate"),
py::arg("successors"),
py::arg("cache"),
R"(
Starting from the given gate, traverse the netlist and return all combinational successor/predecessor gates.
Continue traversal as long as further combinational gates are found and stop at gates that are not combinational.
All combinational gates found during traversal are added to the result.
Provide a cache to speed up traversal when calling this function multiple times on the same netlist.
:param hal_py.Gate gate: Start gate.
:param bool successors: Set ``True`` to get successors, set ``False`` to get predecessors.
:param dict[hal_py.Net, set[hal_py.Gate]] cache: A cache that can be used for better performance on repeated calls.
:returns: The next combinational gates on success, ``None`` otherwise.
:rtype: set[hal_py.Gate] or None
)");
}
} // namespace hal

0 comments on commit f168f70

Please sign in to comment.