From bcf14ede3e1e839bc8f057570ba54165f3e5b9f8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 5 Apr 2025 22:06:29 +0200 Subject: [PATCH] Fixed issue #2014 (strm2oas lef/def/gds collect drops cells referenced by sky130 spare) Problem was that there was the implicit assumption that substitution cells would be top cells (or at least: not child cells of other substitution cells). --- src/db/db/dbCellMapping.cc | 48 ++++++++++++++----------- src/db/unit_tests/dbCellMappingTests.cc | 35 +++++++++++++++++- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/db/db/dbCellMapping.cc b/src/db/db/dbCellMapping.cc index b3bdd4e6a..7bc3dc712 100644 --- a/src/db/db/dbCellMapping.cc +++ b/src/db/db/dbCellMapping.cc @@ -354,6 +354,13 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout & std::vector &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int); std::vector new_cells_b; + std::vector > all_a2b; + for (std::vector::const_iterator b = cell_index_b.begin (); b != cell_index_b.end (); ++b) { + auto m = m_b2a_mapping.find (*b); + tl_assert (m != m_b2a_mapping.end ()); + all_a2b.push_back (std::make_pair (m->second, *b)); + } + std::set called_b; for (std::vector::const_iterator i = cell_index_b.begin (); i != cell_index_b.end (); ++i) { layout_b.cell (*i).collect_called_cells (called_b); @@ -368,6 +375,7 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout & db::cell_index_type new_cell = layout_a.add_cell (layout_b, *b); new_cells.push_back (new_cell); new_cells_b.push_back (*b); + all_a2b.push_back (std::make_pair (new_cell, *b)); if (mapped_pairs) { mapped_pairs->push_back (std::make_pair (*b, new_cell)); @@ -378,34 +386,34 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout & } } - if (! new_cells.empty ()) { + if (all_a2b.empty ()) { + return; + } - // Note: this avoids frequent cell index table rebuilds if source and target layout are identical - db::LayoutLocker locker (&layout_a); + // Note: this avoids frequent cell index table rebuilds if source and target layout are identical + db::LayoutLocker locker (&layout_a); - // Create instances for the new cells in layout A according to their instantiation in layout B - double mag = layout_b.dbu () / layout_a.dbu (); - for (size_t i = 0; i < new_cells.size (); ++i) { + // Create instances for the new cells in layout A according to their instantiation in layout B + double mag = layout_b.dbu () / layout_a.dbu (); + for (auto i = all_a2b.begin (); i != all_a2b.end (); ++i) { - const db::Cell &b = layout_b.cell (new_cells_b [i]); - for (db::Cell::parent_inst_iterator pb = b.begin_parent_insts (); ! pb.at_end (); ++pb) { + const db::Cell &b = layout_b.cell (i->second); + for (db::Cell::parent_inst_iterator pb = b.begin_parent_insts (); ! pb.at_end (); ++pb) { - if (called_b.find (pb->parent_cell_index ()) != called_b.end ()) { + if (called_b.find (pb->parent_cell_index ()) != called_b.end ()) { - db::Cell &pa = layout_a.cell (m_b2a_mapping [pb->parent_cell_index ()]); + db::Cell &pa = layout_a.cell (m_b2a_mapping [pb->parent_cell_index ()]); - db::Instance bi = pb->child_inst (); + db::Instance bi = pb->child_inst (); - db::CellInstArray bci = bi.cell_inst (); - bci.object ().cell_index (new_cells [i]); - bci.transform_into (db::ICplxTrans (mag), &layout_a.array_repository ()); - - if (bi.has_prop_id ()) { - pa.insert (db::CellInstArrayWithProperties (bci, bi.prop_id ())); - } else { - pa.insert (bci); - } + db::CellInstArray bci = bi.cell_inst (); + bci.object ().cell_index (i->first); + bci.transform_into (db::ICplxTrans (mag), &layout_a.array_repository ()); + if (bi.has_prop_id ()) { + pa.insert (db::CellInstArrayWithProperties (bci, bi.prop_id ())); + } else { + pa.insert (bci); } } diff --git a/src/db/unit_tests/dbCellMappingTests.cc b/src/db/unit_tests/dbCellMappingTests.cc index b20c8ec66..f6ec6a767 100644 --- a/src/db/unit_tests/dbCellMappingTests.cc +++ b/src/db/unit_tests/dbCellMappingTests.cc @@ -485,8 +485,41 @@ TEST(7) cib.push_back (b1.cell_index ()); cib.push_back (b2.cell_index ()); cm.create_multi_mapping_full (h, cib, *g, cia); - EXPECT_EQ (m2s (cm, *g, h), "a0->b0;a1->b1;a2->b2;a3->a3;a4->a4;a5->a5"); + EXPECT_EQ (m2s (cm, h, *g), "b0->a0;b1->a1;b2->a2;a3->a3;a4->a4;a5->a5"); EXPECT_EQ (l2s (h), "b0#0:;b1#1:cell_index=3 r0 0,0,cell_index=4 r0 0,0;b2#2:cell_index=4 r0 0,0;a3#3:cell_index=4 r0 0,0,cell_index=5 r0 0,0;a4#4:;a5#5:"); } +// Issue #2014 +TEST(8) +{ + std::unique_ptr g (new db::Layout ()); + db::Cell &a (g->cell (g->add_cell ("a"))); + db::Cell &b (g->cell (g->add_cell ("b"))); + db::Cell &b1 (g->cell (g->add_cell ("b1"))); + db::Cell &b2 (g->cell (g->add_cell ("b2"))); + db::Cell &c (g->cell (g->add_cell ("c"))); + + b.insert (db::CellInstArray (db::CellInst (a.cell_index ()), db::Trans ())); + b.insert (db::CellInstArray (db::CellInst (c.cell_index ()), db::Trans ())); + b.insert (db::CellInstArray (db::CellInst (b1.cell_index ()), db::Trans ())); + b.insert (db::CellInstArray (db::CellInst (b2.cell_index ()), db::Trans ())); + + db::Layout h; + db::Cell &ha (h.cell (h.add_cell ("a"))); + db::Cell &hb (h.cell (h.add_cell ("b"))); + db::Cell &hc (h.cell (h.add_cell ("c"))); + + db::CellMapping cm; + std::vector cib, cia; + cia.push_back (a.cell_index ()); + cia.push_back (b.cell_index ()); + cia.push_back (c.cell_index ()); + cib.push_back (ha.cell_index ()); + cib.push_back (hb.cell_index ()); + cib.push_back (hc.cell_index ()); + cm.create_multi_mapping_full (h, cib, *g, cia); + EXPECT_EQ (m2s (cm, h, *g), "a->a;b->b;b1->b1;b2->b2;c->c"); + + EXPECT_EQ (l2s (h), "a#0:;b#1:cell_index=0 r0 0,0,cell_index=2 r0 0,0,cell_index=3 r0 0,0,cell_index=4 r0 0,0;c#2:;b1#3:;b2#4:"); +}