Fixing issue #2392 (PCell rebinding fails aber technology change)

The bug was that the rebinding by name did not happen
because the name was looked up in the wrong layout.

A testcase has been added to test proper PCell rebinding
in case of technology switches.
This commit is contained in:
Matthias Koefferlein 2026-07-18 15:44:25 +02:00
parent 3c6b342448
commit ca61d8d4af
3 changed files with 208 additions and 6 deletions

View File

@ -707,14 +707,12 @@ Layout::set_technology_name (const std::string &tech)
for (db::Layout::iterator c = begin (); c != end (); ++c) { for (db::Layout::iterator c = begin (); c != end (); ++c) {
std::map<db::lib_id_type, db::lib_id_type>::const_iterator m;
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c); db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
if (! lib_proxy) { if (! lib_proxy) {
continue; continue;
} }
if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { if (mapping.find (lib_proxy->lib_id ()) != mapping.end ()) {
db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ()); db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ());
@ -745,7 +743,10 @@ Layout::set_technology_name (const std::string &tech)
db::cell_index_type ci = lp->first->Cell::cell_index (); db::cell_index_type ci = lp->first->Cell::cell_index ();
db::PCellVariant *lib_pcell = lp->second; db::PCellVariant *lib_pcell = lp->second;
std::pair<bool, pcell_id_type> pn = lib_pcell->layout ()->pcell_by_name (lp->first->get_basic_name ().c_str ()); db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
tl_assert (new_lib != 0);
std::pair<bool, pcell_id_type> pn = new_lib->layout ().pcell_by_name (lp->first->get_basic_name ().c_str ());
if (! pn.first) { if (! pn.first) {
@ -756,8 +757,6 @@ Layout::set_technology_name (const std::string &tech)
} else { } else {
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ()); const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ());
const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second); const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
if (! old_pcell_decl || ! new_pcell_decl) { if (! old_pcell_decl || ! new_pcell_decl) {

View File

@ -129,6 +129,7 @@ RUBYTEST (dbNetlistReaderTests, "dbNetlistReaderTests.rb")
RUBYTEST (dbNetlistCompare, "dbNetlistCompare.rb") RUBYTEST (dbNetlistCompare, "dbNetlistCompare.rb")
RUBYTEST (dbPathTest, "dbPathTest.rb") RUBYTEST (dbPathTest, "dbPathTest.rb")
RUBYTEST (dbPCells, "dbPCells.rb") RUBYTEST (dbPCells, "dbPCells.rb")
RUBYTEST (dbPCellsRebind, "dbPCellsRebind.rb")
RUBYTEST (dbPointTest, "dbPointTest.rb") RUBYTEST (dbPointTest, "dbPointTest.rb")
RUBYTEST (dbPolygonTest, "dbPolygonTest.rb") RUBYTEST (dbPolygonTest, "dbPolygonTest.rb")
RUBYTEST (dbRegionTest, "dbRegionTest.rb") RUBYTEST (dbRegionTest, "dbRegionTest.rb")

202
testdata/ruby/dbPCellsRebind.rb vendored Normal file
View File

@ -0,0 +1,202 @@
# encoding: UTF-8
# KLayout Layout Viewer
# Copyright (C) 2006-2026 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
if !$:.member?(File::dirname($0))
$:.push(File::dirname($0))
end
load("test_prologue.rb")
class PCellRebindVar < RBA::PCellDeclaration
def initialize(name, layer, w_name, w_default)
@name = name
@layer = layer
@w_name = w_name
@w_default = w_default
end
def display_text(parameters)
return "#{@name}(L=#{@layer},#{@w_name}=#{parameters[0].to_s},H=#{parameters[1].to_s})"
end
def get_parameters
# prepare a set of parameter declarations
param = []
param.push(RBA::PCellParameterDeclaration.new(@w_name, RBA::PCellParameterDeclaration::TypeDouble, "Width", @w_default))
param.push(RBA::PCellParameterDeclaration.new("H", RBA::PCellParameterDeclaration::TypeDouble, "Height", 1.0))
return param
end
def get_layers(parameters)
return [ RBA::LayerInfo::new(@layer, 0) ]
end
def produce(layout, layers, parameters, cell)
# fetch the parameters
w = parameters[0]
h = parameters[1]
# create the shape
cell.shapes(layout.layer(@layer, 0)).insert(RBA::DBox.new(-w / 2, -h / 2, w / 2, h / 2))
end
end
class RebindTestLib < RBA::Library
def initialize(var)
# set the description
self.description = "PCell rebind test lib"
# create the PCell declarations
if var == 0
layout.register_pcell("Box0", PCellRebindVar::new("Box0", 0, "W", 3.0))
layout.register_pcell("Box1", PCellRebindVar::new("Box1", 1, "W", 2.0))
layout.register_pcell("Box2A", PCellRebindVar::new("Box2A", 2, "W", 1.0))
else
layout.register_pcell("Box2B", PCellRebindVar::new("Box2B", 12, "W", 1.5))
layout.register_pcell("Box1", PCellRebindVar::new("Box1", 11, "WW", 2.5))
layout.register_pcell("Box0", PCellRebindVar::new("Box0", 10, "W", 3.5))
end
self.technology = (var == 0 ? "T0" : "T1")
register("RebindTestLib")
end
end
def c2s(cell)
ly = cell.layout
s = []
ly.layer_indexes.collect { |li| ly.get_info(li) }.sort { |a,b| [ a.layer, a.datatype ] <=> [ b.layer, b.datatype ] }.each do |lp|
bbox = cell.dbbox(ly.layer(lp))
bbox.empty? || (s << lp.to_s + ":" + bbox.to_s)
end
s.join(";")
end
class DBPCellRebind_TestClass < TestBase
def test_1
tl0 = RebindTestLib::new(0)
tl1 = RebindTestLib::new(1)
assert_equal(tl0.is_for_technology("T0"), true)
assert_equal(tl0.is_for_technology("T1"), false)
assert_equal(tl1.is_for_technology("T0"), false)
assert_equal(tl1.is_for_technology("T1"), true)
ly = RBA::Layout::new
ly.technology_name = "T0"
top = ly.create_cell("TOP")
# in T0:
# Box0 -> on layer 0, w parameter is "W" with default 3.0
# Box1 -> on layer 1, w parameter is "W" with default 2.0
# Box2A -> on layer 2, w parameter is "W" with default 1.0
# Box2B does not exist
c0 = ly.create_cell("Box0", "RebindTestLib", { "W" => 0.3, "H" => 0.5 })
c1 = ly.create_cell("Box1", "RebindTestLib", { "W" => 0.4, "H" => 0.6 })
c2 = ly.create_cell("Box2A", "RebindTestLib", { "W" => 0.5, "H" => 0.7 })
top.insert(RBA::CellInstArray::new(c0.cell_index(), RBA::Trans::new))
top.insert(RBA::CellInstArray::new(c1.cell_index(), RBA::Trans::new))
top.insert(RBA::CellInstArray::new(c2.cell_index(), RBA::Trans::new))
assert_equal(c0.display_title, "RebindTestLib.Box0(L=0,W=0.3,H=0.5)")
assert_equal(c2s(c0), "0/0:(-0.15,-0.25;0.15,0.25)")
assert_equal(c1.display_title, "RebindTestLib.Box1(L=1,W=0.4,H=0.6)")
assert_equal(c2s(c1), "1/0:(-0.2,-0.3;0.2,0.3)")
assert_equal(c2.display_title, "RebindTestLib.Box2A(L=2,W=0.5,H=0.7)")
assert_equal(c2s(c2), "2/0:(-0.25,-0.35;0.25,0.35)")
# in T0:
# Box0 -> on layer 0, w parameter is "W" with default 3.5
# Box1 -> on layer 1, w parameter is "WW" with default 2.5
# Box2A does not exist
# Box2B -> on layer 2, w parameter is "W" with default 1.5
ly.technology_name = "T1"
assert_equal(c0.destroyed, false)
assert_equal(c1.destroyed, false)
assert_equal(c2.destroyed, true) # becomes a cold proxy
c0 = ly.cell("Box0")
c1 = ly.cell("Box1")
c2 = ly.cell("Box2A")
# layer changed, but parameters can be translated
assert_equal(c0.display_title, "RebindTestLib.Box0(L=10,W=0.3,H=0.5)")
assert_equal(c2s(c0), "10/0:(-0.15,-0.25;0.15,0.25)")
# Layer changed and "W" parameter can't be translated as the name changed to "WW"
assert_equal(c1.display_title, "RebindTestLib.Box1(L=11,WW=2.5,H=0.6)")
assert_equal(c2s(c1), "11/0:(-1.25,-0.3;1.25,0.3)")
# Box2A does no longer exist -> cold proxy
assert_equal(c2.display_title, "<defunct>RebindTestLib.Box2A")
assert_equal(c2s(c2), "2/0:(-0.25,-0.35;0.25,0.35)")
ly.technology_name = "T0"
assert_equal(c0.destroyed, false)
assert_equal(c1.destroyed, false)
assert_equal(c2.destroyed, true) # became an active PCell variant again
c0 = ly.cell("Box0")
c1 = ly.cell("Box1")
c2 = ly.cell("Box2A")
# layer changed, but parameters can be translated
assert_equal(c0.display_title, "RebindTestLib.Box0(L=0,W=0.3,H=0.5)")
assert_equal(c2s(c0), "0/0:(-0.15,-0.25;0.15,0.25)")
# Layer changed and "WW" parameter can't be translated as the name changed back to "W"
assert_equal(c1.display_title, "RebindTestLib.Box1(L=1,W=2.0,H=0.6)")
assert_equal(c2s(c1), "1/0:(-1,-0.3;1,0.3)")
# Box2A is back to normal as the cold proxy kept the information
assert_equal(c2.display_title, "RebindTestLib.Box2A(L=2,W=0.5,H=0.7)")
assert_equal(c2s(c2), "2/0:(-0.25,-0.35;0.25,0.35)")
tl0._destroy
tl1._destroy
end
end
load("test_epilogue.rb")