diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index e7c93b663..fbf1abf14 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -2627,18 +2627,18 @@ Layout::convert_cell_to_static (db::cell_index_type ci) const cell_type &org_cell = cell (ci); - std::string vn = org_cell.get_variant_name (); - if (vn == cell_name (ci)) { + if (vn == std::string (cell_name (ci), vn.size ())) { // there is a cell name conflict: give priority to the static cell, so it - // will see the variant name - std::string rename_org = uniquify_cell_name (cell_name (ci)); + // will see the variant name or at least the original disambiguated name + std::string rename_org = uniquify_cell_name (vn.c_str ()); + vn = cell_name (ci); rename_cell (ci, rename_org.c_str ()); } ret_ci = add_cell (vn.c_str ()); cell_type &new_cell = cell (ret_ci); - // Note: we convert to static cell by explicitly cloning to the db::Cell class + // Note: we convert to static cell by explicitly converting to the db::Cell class new_cell = org_cell; new_cell.set_cell_index (ret_ci); diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 2693b0bb5..774e92d40 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -698,6 +698,7 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, gsi::method ("parameters_from_shape", &PCellDeclarationImpl::parameters_from_shape_fb, "@hide") + gsi::method ("transformation_from_shape", &PCellDeclarationImpl::transformation_from_shape_fb, "@hide") + gsi::method ("display_text", &PCellDeclarationImpl::get_display_name_fb, "@hide") + + gsi::method ("cell_name", &PCellDeclarationImpl::get_cell_name_fb, "@hide") + gsi::method ("wants_lazy_evaluation", &PCellDeclarationImpl::wants_lazy_evaluation_fb, "@hide") + gsi::method ("description", &PCellDeclarationImpl::get_description_fb, "@hide") + gsi::method ("via_types", &PCellDeclarationImpl::via_types_fb, "@hide") + diff --git a/src/db/unit_tests/dbPCellsTests.cc b/src/db/unit_tests/dbPCellsTests.cc index 9304b9aff..dc41a4c8b 100644 --- a/src/db/unit_tests/dbPCellsTests.cc +++ b/src/db/unit_tests/dbPCellsTests.cc @@ -88,6 +88,13 @@ class PD cell.shapes (l_metal0).insert (db::Box (0, 0, width, height)); } + + virtual std::string get_display_name (const db::pcell_parameters_type ¶meters) const + { + db::Coord width = db::coord_traits::rounded (parameters[0].to_double () * 1000.0); + db::Coord height = db::coord_traits::rounded (parameters[1].to_double () * 1000.0); + return tl::sprintf ("PD(W=%d,H=%d)", width, height); + } }; TEST(0) @@ -252,3 +259,114 @@ TEST(1) } } +// PCell names, convert PCell to static + +class PD2 + : public PD +{ +public: + virtual std::string get_cell_name (const db::pcell_parameters_type ¶meters) const + { + db::Coord width = db::coord_traits::rounded (parameters[0].to_double () * 1000.0); + db::Coord height = db::coord_traits::rounded (parameters[1].to_double () * 1000.0); + return tl::sprintf ("PD_W%d_H%d", width, height); + } +}; + +TEST(2) +{ + db::Manager m (true); + db::Layout layout(&m); + layout.dbu (0.001); + + db::LayerProperties p; + + p.layer = 23; + p.datatype = 0; + unsigned int l_cont = layout.insert_layer (p); + + p.layer = 16; + p.datatype = 0; + unsigned int l_gate = layout.insert_layer (p); + + db::Cell &cell_a = layout.cell (layout.add_cell ("A")); + cell_a.shapes(l_cont).insert(db::Box (50, 50, 150, 150)); + cell_a.shapes(l_gate).insert(db::Box (0, 0, 200, 1000)); + + db::Cell &top = layout.cell (layout.add_cell ("TOP")); + + db::pcell_id_type pd = layout.register_pcell ("PD", new PD2 ()); + + std::vector parameters; + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + tl::Variant &width = parameters[0]; + tl::Variant &height = parameters[1]; + tl::Variant &orientation = parameters[2]; + + width = 0.5; + height = 1.0; + orientation = long (0); + + db::cell_index_type pd1 = layout.get_pcell_variant (pd, parameters); + top.insert (db::CellInstArray (db::CellInst (pd1), db::Trans (db::Vector (0, 0)))); + + EXPECT_EQ (layout.display_name (pd1), "PD(W=500,H=1000)"); + EXPECT_EQ (layout.cell_name (pd1), "PD_W500_H1000"); + EXPECT_EQ (layout.variant_name (pd1), "PD_W500_H1000"); + + width = 0.4; + height = 0.8; + + db::cell_index_type pd2 = layout.get_pcell_variant (pd, parameters); + top.insert (db::CellInstArray (db::CellInst (pd2), db::Trans (db::Vector (0, 2000)))); + + EXPECT_EQ (layout.display_name (pd2), "PD(W=400,H=800)"); + EXPECT_EQ (layout.cell_name (pd2), "PD_W400_H800"); + EXPECT_EQ (layout.variant_name (pd2), "PD_W400_H800"); + + EXPECT_NE (pd1, pd2); + + width = 0.4; + height = 0.8; + orientation = long (1); + + db::cell_index_type pd3 = layout.get_pcell_variant (pd, parameters); + auto i3 = top.insert (db::CellInstArray (db::CellInst (pd3), db::Trans (db::Vector (2000, 0)))); + + EXPECT_EQ (layout.display_name (pd3), "PD(W=400,H=800)"); + EXPECT_EQ (layout.cell_name (pd3), "PD_W400_H800$1"); + EXPECT_EQ (layout.variant_name (pd3), "PD_W400_H800"); + + EXPECT_NE (pd2, pd3); + + auto pd3_org = pd3; + pd3 = layout.convert_cell_to_static (pd3); + EXPECT_NE (pd3, pd3_org); + + auto ci3 = i3.cell_inst (); + ci3.object ().cell_index (pd3); + top.replace (i3, ci3); + + EXPECT_EQ (layout.cell (pd3_org).is_proxy (), true); + EXPECT_EQ (layout.cell (pd3).is_proxy (), false); + + EXPECT_EQ (layout.display_name (pd3_org), "PD(W=400,H=800)"); + EXPECT_EQ (layout.cell_name (pd3_org), "PD_W400_H800$2"); + EXPECT_EQ (layout.variant_name (pd3_org), "PD_W400_H800"); + + layout.do_cleanup (true); + layout.cleanup (); + + EXPECT_EQ (layout.is_valid_cell_index (pd3_org), false); + + EXPECT_EQ (layout.display_name (pd3), "PD_W400_H800$1"); + EXPECT_EQ (layout.cell_name (pd3), "PD_W400_H800$1"); + EXPECT_EQ (layout.variant_name (pd3), "PD_W400_H800$1"); + + + + CHECKPOINT (); + db::compare_layouts (_this, layout, tl::testdata () + "/gds/pcell_test20.gds", db::NoNormalization); +} diff --git a/testdata/gds/issue_1835_au.gds b/testdata/gds/issue_1835_au.gds index 8770350b0..6d0a52e9a 100644 Binary files a/testdata/gds/issue_1835_au.gds and b/testdata/gds/issue_1835_au.gds differ diff --git a/testdata/gds/pcell_test20.gds b/testdata/gds/pcell_test20.gds new file mode 100644 index 000000000..ba267e615 Binary files /dev/null and b/testdata/gds/pcell_test20.gds differ diff --git a/testdata/python/dbPCells.py b/testdata/python/dbPCells.py index 41881f415..a7283c9cc 100644 --- a/testdata/python/dbPCells.py +++ b/testdata/python/dbPCells.py @@ -27,6 +27,10 @@ class BoxPCell(pya.PCellDeclaration): # provide a descriptive text for the cell return "Box(L=" + str(parameters[0]) + ",W=" + ('%.3f' % parameters[1]) + ",H=" + ('%.3f' % parameters[2]) + ")" + def cell_name(self, parameters): + # provide a descriptive text for the cell + return "Box_L" + str(parameters[0]).replace("/", "d") + "_W" + ('%.3f' % parameters[1]).replace(".", "p") + "_H" + ('%.3f' % parameters[2]).replace(".", "p") + def get_parameters(self): # prepare a set of parameter declarations @@ -100,6 +104,10 @@ if "PCellDeclarationHelper" in pya.__dict__: # provide a descriptive text for the cell return "Box2(L=" + str(self.layer) + ",W=" + ('%.3f' % self.width) + ",H=" + ('%.3f' % self.height) + ")" + def cell_name_impl(self): + # provide a descriptive text for the cell + return "Box2_L" + str(self.layer).replace("/", "d") + "_W" + ('%.3f' % self.width).replace(".", "p") + "_H" + ('%.3f' % self.height).replace(".", "p") + def wants_lazy_evaluation(self): return True @@ -260,6 +268,8 @@ class DBPCellTests(unittest.TestCase): self.assertEqual(pcell_var.is_pcell_variant(), True) self.assertEqual(pcell_var.display_title(), "PCellTestLib.Box(L=1/0,W=1.000,H=1.000)") self.assertEqual(pcell_var.basic_name(), "Box") + self.assertEqual(pcell_var.qname(), "PCellTestLib.Box") + self.assertEqual(pcell_var.name, "Box_L1d0_W1p000_H1p000") self.assertEqual(pcell_var.pcell_declaration().wants_lazy_evaluation(), False) self.assertEqual(c1.is_pcell_variant(), False) self.assertEqual(c1.is_pcell_variant(pcell_inst), True) @@ -394,6 +404,8 @@ class DBPCellTests(unittest.TestCase): pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans())) self.assertEqual(pcell_var.basic_name(), "Box2") + self.assertEqual(pcell_var.name, "Box2_L1d0_W1p000_H1p000") + self.assertEqual(pcell_var.qname(), "PCellTestLib2.Box2") self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]") self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") diff --git a/testdata/ruby/dbPCells.rb b/testdata/ruby/dbPCells.rb index 61ca6450c..e15989b4b 100644 --- a/testdata/ruby/dbPCells.rb +++ b/testdata/ruby/dbPCells.rb @@ -39,6 +39,11 @@ class BoxPCell < RBA::PCellDeclaration # provide a descriptive text for the cell return "Box(L=#{parameters[0].to_s},W=#{'%.3f' % parameters[1].to_s},H=#{'%.3f' % parameters[2].to_s})" end + + def cell_name(parameters) + # provide a cell name for the PCell + return "Box_L#{parameters[0].to_s.gsub('/','d')}_W#{('%.3f' % parameters[1]).gsub('.','p')}_H#{('%.3f' % parameters[2]).gsub('.','p')}" + end def get_parameters @@ -129,6 +134,11 @@ if RBA.constants.member?(:PCellDeclarationHelper) return "Box2(L=" + layer.to_s + ",W=" + ('%.3f' % width) + ",H=" + ('%.3f' % height) + ")" end + def cell_name_impl + # provide a cell name for the PCell + return "Box2_L" + layer.to_s.gsub('/', 'd') + "_W" + ('%.3f' % width).gsub('.', 'p') + "_H" + ('%.3f' % height).gsub('.', 'p') + end + def produce_impl # fetch the parameters @@ -371,6 +381,9 @@ class DBPCell_TestClass < TestBase param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults pcell_var_id = ly.add_pcell_variant(lib, pcell_decl_id, param) pcell_var = ly.cell(pcell_var_id) + assert_equal(pcell_var.name, "Box_L1d0_W1p000_H1p000") + assert_equal(pcell_var.qname, "PCellTestLib.Box") + assert_equal(pcell_var.basic_name, "Box") pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new)) assert_equal(pcell_var.layout.inspect, ly.inspect) assert_equal(pcell_var.library.inspect, lib.inspect) @@ -512,6 +525,8 @@ class DBPCell_TestClass < TestBase pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new)) assert_equal(pcell_var.basic_name, "Box2") + assert_equal(pcell_var.name, "Box2_L1d0_W1p000_H1p000") + assert_equal(pcell_var.qname, "PCellTestLib2.Box2") assert_equal(pcell_var.pcell_parameters().inspect, "[<1/0>, 1.0, 1.0, 0]") assert_equal(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") assert_equal(norm_hash(pcell_var.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"secret\"=>0, \"width\"=>1.0}") @@ -908,6 +923,37 @@ class DBPCell_TestClass < TestBase end + # convert to static cell + def test_13 + + if !RBA.constants.member?(:PCellDeclarationHelper) + return + end + + # instantiate and register the library + tl = PCellTestLib2::new + + ly = RBA::Layout::new(true) + ly.dbu = 0.01 + + ci1 = ly.add_cell("c1") + c1 = ly.cell(ci1) + + lib = RBA::Library.library_by_name("PCellTestLib2") + assert_equal(lib != nil, true) + pcell_decl = lib.layout().pcell_declaration("Box2") + + param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults + pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param) + static_id = ly.convert_cell_to_static(pcell_var_id) + static = ly.cell(static_id) + assert_equal(static.basic_name, "Box2_L1d0_W1p000_H1p000") + assert_equal(static.name, "Box2_L1d0_W1p000_H1p000") + assert_equal(static.qname, "Box2_L1d0_W1p000_H1p000") + assert_equal(static.is_proxy?, false) + + end + end class DBPCellParameterStates_TestClass < TestBase