Skip to content

Commit 205773a

Browse files
committed
added new find carry chain function to netlist utils
1 parent c46d7b2 commit 205773a

File tree

3 files changed

+134
-2
lines changed

3 files changed

+134
-2
lines changed

include/hal_core/netlist/netlist_utils.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,18 @@ namespace hal
356356
[[deprecated("Will be removed in a future version, use NetlistModificationDecorator::replace_gate instead.")]] CORE_API Result<std::monostate>
357357
replace_gate(Gate* gate, GateType* target_type, std::map<GatePin*, GatePin*> pin_map);
358358

359+
/**
360+
* Identify carry chains in a given netlist. The user has to provide the input pin of the carry
361+
* gates and output pin that will go into the subsequent gate.
362+
* Note that this function relies on having annotated carry gates in the netlist to work.
363+
*
364+
* @param[in] nl - The netlist to detect the carry chains in.
365+
* @param[in] input_pin - The input pin through which the carries must be connected.
366+
* @param[in] output_pin - The output pin through which the carries must be connected.
367+
* @returns A vector of vector of gates that form a chain on success, an error otherwise.
368+
*/
369+
CORE_API Result<std::vector<std::vector<Gate*>>> find_carry_chains(const Netlist* nl, const const std::string input_pins, const const std::string output_pins);
370+
359371
/**
360372
* Find a sequence of identical gates that are connected via the specified input and output pins.
361373
* The start gate may be any gate within a such a sequence, it is not required to be the first or the last gate.
@@ -365,7 +377,6 @@ namespace hal
365377
* @param[in] start_gate - The gate at which to start the chain detection.
366378
* @param[in] input_pins - The input pins through which the gates must be connected. Defaults to an empty vector.
367379
* @param[in] output_pins - The output pins through which the gates must be connected. Defaults to an empty vector.
368-
* @param[in] filter - An optional filter function to be evaluated on each gate.
369380
* @returns A vector of gates that form a chain on success, an error otherwise.
370381
*/
371382
CORE_API Result<std::vector<Gate*>> get_gate_chain(Gate* start_gate,

src/netlist/netlist_utils.cpp

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ namespace hal
336336
{
337337
if (std::find(allowed_pin_types.begin(), allowed_pin_types.end(), endpoint->get_pin()->get_type()) != allowed_pin_types.end() || allowed_pin_types.empty())
338338
{
339-
auto n = endpoint->get_net();
339+
auto n = endpoint->get_net();
340340
auto suc = get_next_sequential_gates(n, get_successors, allowed_pin_types, cache);
341341
found_ffs.insert(found_ffs.end(), suc.begin(), suc.end());
342342
}
@@ -831,6 +831,96 @@ namespace hal
831831
}
832832
}
833833

834+
Result<std::vector<std::vector<Gate*>>> find_carry_chains(const Netlist* nl, const std::string input_pin, const std::string output_pin)
835+
{
836+
if (input_pin.empty() || output_pin.empty())
837+
{
838+
return ERR("input or output pin is empty");
839+
}
840+
841+
std::vector<std::vector<Gate*>> carry_chains;
842+
843+
// retrieve all carry gates
844+
std::vector<Gate*> carry_gates = nl->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_carry); });
845+
std::set<Gate*> carry_gates_set = std::set<Gate*>(carry_gates.begin(), carry_gates.end());
846+
if (carry_gates_set.empty())
847+
{
848+
return ERR("no carry gates in netlists");
849+
}
850+
851+
// collect carry chains until all carry gates have been analyzed
852+
while (!carry_gates_set.empty())
853+
{
854+
Gate* current_gate = *carry_gates_set.begin();
855+
const GateType* carry_type = current_gate->get_type();
856+
857+
auto input_pin_type = carry_type->get_pin_by_name(input_pin);
858+
if (input_pin_type == nullptr)
859+
{
860+
return ERR("could not get input pin type, is nullptr");
861+
}
862+
863+
auto output_pin_type = carry_type->get_pin_by_name(output_pin);
864+
if (output_pin_type == nullptr)
865+
{
866+
return ERR("could not get output pin type, is nullptr");
867+
}
868+
869+
// get carry chains by defining appropriate filter function
870+
auto chain_res = netlist_utils::get_gate_chain(current_gate, {input_pin_type}, {output_pin_type});
871+
if (chain_res.is_error())
872+
{
873+
return ERR(chain_res.get_error());
874+
}
875+
std::vector<Gate*> carry_chain = chain_res.get();
876+
877+
// remove shift register gates from candidate set
878+
for (Gate* g : carry_chain)
879+
{
880+
carry_gates_set.erase(g);
881+
}
882+
883+
// only consider carry chains with more than 2 gates for now
884+
if (carry_chain.size() >= 2)
885+
{
886+
log_debug("netlist_utils", "\tcarry_gate: {}", carry_chain.front()->get_name());
887+
carry_chains.push_back(carry_chain);
888+
}
889+
}
890+
891+
// check whether a carry chain is a subset of another one
892+
std::vector<std::vector<Gate*>> filtered_carry_chains;
893+
for (u32 i = 0; i < carry_chains.size(); i++)
894+
{
895+
auto& c_test = carry_chains.at(i);
896+
std::set<Gate*> test_set = {c_test.begin(), c_test.end()};
897+
898+
bool is_subset = false;
899+
for (u32 j = 0; j < carry_chains.size(); j++)
900+
{
901+
if (i == j)
902+
{
903+
continue;
904+
}
905+
906+
auto& c_other = carry_chains.at(j);
907+
std::set<Gate*> other_set = {c_other.begin(), c_other.end()};
908+
909+
if (std::includes(other_set.begin(), other_set.end(), test_set.begin(), test_set.end()))
910+
{
911+
is_subset = true;
912+
break;
913+
}
914+
}
915+
916+
if (!is_subset)
917+
{
918+
filtered_carry_chains.push_back(c_test);
919+
}
920+
}
921+
return OK(filtered_carry_chains);
922+
}
923+
834924
Result<std::vector<Gate*>>
835925
get_gate_chain(Gate* start_gate, const std::vector<const GatePin*>& input_pins, const std::vector<const GatePin*>& output_pins, const std::function<bool(const Gate*)>& filter)
836926
{

src/python_bindings/bindings/netlist_utils.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,37 @@ namespace hal
401401
:rtype: bool
402402
)");
403403

404+
py_netlist_utils.def(
405+
"find_carry_chains",
406+
[](const Netlist* nl, const std::string input_pin, const std::string output_pin)
407+
-> std::vector<std::vector<Gate*>> {
408+
auto res = netlist_utils::find_carry_chains(nl, input_pin, output_pin);
409+
if (res.is_ok())
410+
{
411+
return res.get();
412+
}
413+
else
414+
{
415+
log_error("python_context", "error encountered while detecting gate chain:\n{}", res.get_error().get());
416+
return {};
417+
}
418+
},
419+
py::arg("nl"),
420+
py::arg("input_pin") = std::string(),
421+
py::arg("output_pin") = std::string(),
422+
R"(
423+
Identify carry chains in a given netlist. The user has to provide the input pin of the carry
424+
gates and output pin that will go into the subsequent gate.
425+
Note that this function relies on having annotated carry gates in the netlist to work.
426+
427+
428+
:param hal_py.Netlist nl: The netlist to detect the carry chains in.
429+
:param list[hal_py.GatePin] input_pin: The input through which the gates must be connected.
430+
:param set[hal_py.GatePin] output_pin: The output through which the gates must be connected.
431+
@returns A vector of vector of gates that form a chain on success, an error otherwise.
432+
:rtype: list[list[hal_py.Gate]]
433+
)");
434+
404435
py_netlist_utils.def(
405436
"get_gate_chain",
406437
[](Gate* start_gate, const std::vector<const GatePin*>& input_pins = {}, const std::vector<const GatePin*>& output_pins = {}, const std::function<bool(const Gate*)>& filter = nullptr)

0 commit comments

Comments
 (0)