mirror of https://github.com/KLayout/klayout.git
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:
parent
3c6b342448
commit
ca61d8d4af
|
|
@ -707,14 +707,12 @@ Layout::set_technology_name (const std::string &tech)
|
|||
|
||||
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);
|
||||
if (! lib_proxy) {
|
||||
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::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::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) {
|
||||
|
||||
|
|
@ -756,8 +757,6 @@ Layout::set_technology_name (const std::string &tech)
|
|||
|
||||
} 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 *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ RUBYTEST (dbNetlistReaderTests, "dbNetlistReaderTests.rb")
|
|||
RUBYTEST (dbNetlistCompare, "dbNetlistCompare.rb")
|
||||
RUBYTEST (dbPathTest, "dbPathTest.rb")
|
||||
RUBYTEST (dbPCells, "dbPCells.rb")
|
||||
RUBYTEST (dbPCellsRebind, "dbPCellsRebind.rb")
|
||||
RUBYTEST (dbPointTest, "dbPointTest.rb")
|
||||
RUBYTEST (dbPolygonTest, "dbPolygonTest.rb")
|
||||
RUBYTEST (dbRegionTest, "dbRegionTest.rb")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
Loading…
Reference in New Issue