Skip to content

Commit

Permalink
🐛 Fixed a bug in the clear_tile function that lost track of PI and …
Browse files Browse the repository at this point in the history
…PO count (#104)

* 🐛 Fixed a bug in the clear_tile function that lost track of PI and PO count

* 🐛 Fixed further issues with clear_tile and move_node

* 🐛 Fixed output signal splitting in technology_networks and name assignment
  • Loading branch information
marcelwa committed Jan 31, 2023
1 parent 0f2d8bb commit 863b5f4
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 24 deletions.
56 changes: 33 additions & 23 deletions include/fiction/layouts/gate_level_layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ class gate_level_layout : public ClockedLayout
* Check whether tile `t` hosts a primary input.
*
* @param t Tile to be checked.
* @return `true` iff `t`he node located at tile `t` is a PI.
* @return `true` iff the node located at tile `t` is a PI.
*/
[[nodiscard]] bool is_pi_tile(const tile& t) const noexcept
{
Expand All @@ -270,7 +270,7 @@ class gate_level_layout : public ClockedLayout
* Check whether tile `t` hosts a primary output.
*
* @param t Tile to be checked.
* @return `true` iff `t`he node located at tile `t` is a PO.
* @return `true` iff the node located at tile `t` is a PO.
*/
[[nodiscard]] bool is_po_tile(const tile& t) const noexcept
{
Expand Down Expand Up @@ -524,7 +524,7 @@ class gate_level_layout : public ClockedLayout
/**
* Checks whether there are no gates or wires assigned to the layout's coordinates.
*
* @return `true` iff `t`he layout is empty.
* @return `true` iff the layout is empty.
*/
[[nodiscard]] bool is_empty() const noexcept
{
Expand Down Expand Up @@ -570,7 +570,7 @@ class gate_level_layout : public ClockedLayout
*/
[[nodiscard]] node get_node(const signal& s) const noexcept
{
if (auto it = strg->data.tile_node_map.find(s); it != strg->data.tile_node_map.cend())
if (const auto it = strg->data.tile_node_map.find(s); it != strg->data.tile_node_map.cend())
{
return it->second;
}
Expand Down Expand Up @@ -608,7 +608,7 @@ class gate_level_layout : public ClockedLayout
* if they are dangling (see the `mockturtle` API). In this layout type, nodes are also marked dead when they are
* not assigned to a tile (which is considered equivalent to dangling).
*
* @param n Node to check for lifeliness.
* @param n Node to check for liveliness.
* @return `true` iff `n` is dead.
*/
[[nodiscard]] bool is_dead(const node n) const noexcept
Expand Down Expand Up @@ -649,6 +649,13 @@ class gate_level_layout : public ClockedLayout
// clear old_t only if it is different from t (this function can also be used to simply update n's children)
if (t != old_t)
{
if (!t.is_dead())
{
// if n lived on a tile that was marked as PO, update it with the new tile t
std::replace(strg->outputs.begin(), strg->outputs.end(), static_cast<signal>(old_t),
static_cast<signal>(t));
}

// clear n's position
clear_tile(old_t);
// assign n to its new position
Expand All @@ -663,24 +670,11 @@ class gate_level_layout : public ClockedLayout
std::for_each(new_children.cbegin(), new_children.cend(),
[this](const auto& nc) { strg->nodes[get_node(nc)].data[0].h1++; });

if (t.is_dead())
{
// remove old_t from primary outputs if present
strg->outputs.erase(std::remove(strg->outputs.begin(), strg->outputs.end(), static_cast<signal>(old_t)),
strg->outputs.end());
}
else if (t != old_t)
{
// if n lived on a tile that was marked as PO, update it with the new tile t
std::replace(strg->outputs.begin(), strg->outputs.end(), static_cast<signal>(old_t),
static_cast<signal>(t));
}

return static_cast<signal>(t);
}
/**
* Connects the given signal `s` to the given node `n` as a child. The new child `s` is appended at the end of `n`'s
* list of children. Thus, if the order of children is important, `move_node` should be used instead. Otherwise,
* list of children. Thus, if the order of children is important, `move_node()` should be used instead. Otherwise,
* this function has a smaller overhead and is to be preferred.
*
* @param s New incoming signal to `n`.
Expand All @@ -699,29 +693,45 @@ class gate_level_layout : public ClockedLayout
/**
* Removes all assigned nodes from the given tile and marks them as dead.
*
* @note This function does not reduce the number of nodes in the layout nor does it reduce the number of PIs
* that are being returned via `num_pis()` even if the tile to clear is an input tile. However, the number of POs is
* reduced if the tile to clear is an output tile. While this seems counter-intuitive and inconsistent, it is in
* line with mockturtle's understanding of nodes and primary outputs.
*
* @param t Tile whose nodes are to be removed.
*/
void clear_tile(const tile& t) noexcept
{
if (auto it = strg->data.tile_node_map.find(static_cast<signal>(t)); it != strg->data.tile_node_map.end())
if (const auto it = strg->data.tile_node_map.find(static_cast<signal>(t)); it != strg->data.tile_node_map.end())
{
const auto n = it->second;

if (!t.is_dead())
{
// decrease wire count
if (is_wire(it->second))
if (is_wire(n))
{
strg->data.num_wires--;

// find PO entry and remove it if present
if (const auto po_it =
std::find_if(strg->outputs.cbegin(), strg->outputs.cend(),
[this, &n](const auto& p) { return this->get_node(p.index) == n; });
po_it != strg->outputs.cend())
{
strg->outputs.erase(po_it);
}
}
else // decrease gate count
{
strg->data.num_gates--;
}
}
// mark node as dead
kill_node(it->second);
kill_node(n);

// remove node-tile
strg->data.node_tile_map.erase(it->second);
strg->data.node_tile_map.erase(n);
// remove tile-node
strg->data.tile_node_map.erase(it);
}
Expand Down
2 changes: 1 addition & 1 deletion include/fiction/networks/technology_network.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ class technology_network : public mockturtle::klut_network
foreach_po(
[this](const auto& po, auto index)
{
if (!is_buf(get_node(po)))
if (!is_buf(get_node(po)) || is_fanout(get_node(po)))
{
// decrease ref-count
_storage->nodes[po].data[0].h1--;
Expand Down
1 change: 1 addition & 0 deletions include/fiction/utils/name_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ template <typename NtkSrc, typename NtkDest, typename T>
void restore_names(const NtkSrc& ntk_src, NtkDest& ntk_dest, mockturtle::node_map<T, NtkSrc>& old2new) noexcept
{
restore_network_name(ntk_src, ntk_dest);
restore_input_names(ntk_src, ntk_dest);
restore_signal_names(ntk_src, ntk_dest, old2new);
restore_output_names(ntk_src, ntk_dest);
}
Expand Down
21 changes: 21 additions & 0 deletions test/algorithms/physical_design/exact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,26 @@ void check_apply_lib(const GateLyt& lyt)
CHECK_NOTHROW(apply_gate_library<CellLyt, Lib>(lyt));
}

// check io names
template <typename Ntk, typename Lyt>
void check_io_names(const Ntk& ntk, const Lyt& lyt)
{
if constexpr (mockturtle::has_get_name_v<Ntk>)
{
for (auto i = 0u; i < ntk.num_pis(); ++i)
{
CHECK(lyt.get_input_name(i) == ntk.get_name(ntk.make_signal(ntk.pi_at(i))));
}
}
if constexpr (mockturtle::has_get_output_name_v<Ntk>)
{
for (auto i = 0u; i < ntk.num_pos(); ++i)
{
CHECK(lyt.get_output_name(i) == ntk.get_output_name(i));
}
}
}

template <typename CellLyt, typename Lib, typename Ntk, typename GateLyt>
void check_with_gate_library(const Ntk& ntk, const exact_physical_design_params<GateLyt>& ps)
{
Expand All @@ -237,6 +257,7 @@ void check_with_gate_library(const Ntk& ntk, const exact_physical_design_params<
check_eq(ntk, layout);
check_tp(layout, 1);
check_apply_lib<CellLyt, Lib>(layout);
check_io_names(ntk, layout);
}

template <typename Ntk, typename Lyt>
Expand Down
46 changes: 46 additions & 0 deletions test/layouts/gate_level_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,52 @@ TEST_CASE("Move nodes", "[gate-level-layout]")
CHECK(layout.num_wires() == 3); // PO is gone now
}

TEST_CASE("Clear tiles", "[gate-level-layout]")
{
using gate_layout = gate_level_layout<clocked_layout<tile_based_layout<cartesian_layout<offset::ucoord_t>>>>;

auto layout = blueprints::and_or_gate_layout<gate_layout>();

REQUIRE(layout.num_gates() == 2);
REQUIRE(layout.num_wires() == 4);
REQUIRE(layout.num_pis() == 2);
REQUIRE(layout.num_pos() == 2);

layout.clear_tile({1, 0});

CHECK(!layout.is_gate_tile({1, 0}));
CHECK(layout.num_gates() == 1);
CHECK(layout.num_wires() == 4);
CHECK(layout.num_pis() == 2);
CHECK(layout.num_pos() == 2);

layout.clear_tile({2, 1});

CHECK(!layout.is_gate_tile({2, 1}));
CHECK(layout.num_gates() == 0);
CHECK(layout.num_wires() == 4);
CHECK(layout.num_pis() == 2);
CHECK(layout.num_pos() == 2);

layout.clear_tile({2, 0});

CHECK(!layout.is_wire_tile({2, 0}));
CHECK(!layout.is_pi_tile({2, 0}));
CHECK(layout.num_gates() == 0);
CHECK(layout.num_wires() == 3);
CHECK(layout.num_pis() == 2);
CHECK(layout.num_pos() == 2);

layout.clear_tile({0, 0});

CHECK(!layout.is_wire_tile({0, 0}));
CHECK(!layout.is_po_tile({0, 0}));
CHECK(layout.num_gates() == 0);
CHECK(layout.num_wires() == 2);
CHECK(layout.num_pis() == 2);
CHECK(layout.num_pos() == 1);
}

TEST_CASE("Gate-level cardinal operations", "[gate-level-layout]")
{
using gate_layout = gate_level_layout<clocked_layout<tile_based_layout<cartesian_layout<offset::ucoord_t>>>>;
Expand Down

0 comments on commit 863b5f4

Please sign in to comment.