Replace Cells With Others
false
false
true
@hcp_context_menu.end
ruby
#
# 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.
#
# DESCRIPTION: Replace cells with other cells from another layout
#
# Install the script with
# klayout -rm replace_cells.lym ...
# or put the script as "replace_cells.lym" into the installation path
# (on Unix for version <=0.21: set $KLAYOUTPATH to the installation folder).
#
# The script installs a new menu entry at the end of the cell list context
# menu: "Replace Cells With Others". This function asks for a file containing
# a couple of other (top) cells, even with their own hierarchy. It will copy
# these cells into the existing layout and replace the corresponding cells in
# the current layout with the ones from the replacement library.
# A utility function which copies one layout into another
def copy_cells(lsrc, ltarget, lmap, pmap)
citarget = nil
# a map for the cell indices
cmap = {}
lsrc.each_cell_bottom_up do |cisrc|
# create a new cell in the target layout and add to the cell index map
csrc = lsrc.cell(cisrc)
citarget = ltarget.add_cell(lsrc.cell_name(cisrc))
ctarget = ltarget.cell(citarget)
cmap[cisrc] = citarget
# copy the shapes
lsrc.layer_indices.each do |lisrc|
shtarget = ctarget.shapes(lmap[lisrc])
csrc.shapes(lisrc).each do |shape|
# property mapping
newpid = 0 # =no properties
if shape.has_prop_id?
newpid = pmap[shape.prop_id]
if !newpid
newpid = ltarget.properties_id(lsrc.properties(shape.prop_id))
pmap[shape.prop_id] = newpid
end
end
newshape = shtarget.insert(shape)
shtarget.replace_prop_id(newshape, newpid)
end
end
# translate and copy the instances
csrc.each_inst do |inst|
# property mapping
newpid = 0 # =no properties
if inst.has_prop_id?
newpid = pmap[inst.prop_id]
if !newpid
newpid = ltarget.properties_id(lsrc.properties(inst.prop_id))
pmap[inst.prop_id] = newpid
end
end
# get the instance object and create a new one with the new cell index
i = inst.cell_inst
trans = i.is_complex? ? i.cplx_trans : i.trans
cinew = cmap[i.cell_index]
if i.is_regular_array?
newinst = ctarget.insert(RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb))
else
newinst = ctarget.insert(RBA::CellInstArray.new(cinew, trans))
end
# apply the new property id
ctarget.replace_prop_id(newinst, newpid)
end
end
return cmap
end
# Main functionality
app = RBA::Application.instance
mw = app.main_window
# get the current layout view
lv = mw.current_view
if lv == nil
raise "No view selected"
end
# get the current cell view (the one selected in the hierarchy browser)
cv = lv.cellview(lv.active_cellview_index)
if !cv.is_valid?
raise "No layout selected"
end
# fetch the name of the layout with the replacement cells
fn = RBA::FileDialog::get_open_file_name("Select replacement library", ".", "All files (*)")
if fn.has_value?
lib = RBA::Layout::new
lmap = lib.read(fn.value)
if ((lib.dbu - cv.layout.dbu).abs > 1e-6)
raise "Database units of the layouts must be identical"
end
org_layers = {}
new_layers = {}
cv.layout.layer_indices.each do |l|
info = cv.layout.get_info(l)
if lmap.is_mapped?(info)
ll = lmap.logical(info)
org_layers[l] = ll
new_layers[ll] = l
end
end
has_new_layers = false
lib.layer_indices.each do |l|
if ! new_layers[l]
ll = cv.layout.insert_layer(lib.get_info(l))
new_layers[l] = ll
org_layers[ll] = l
has_new_layers = true
end
end
tmap = {}
lib.each_top_cell do |t|
tn = lib.cell_name(t)
if cv.layout.has_cell?(tn)
tt = cv.layout.cell_by_name(tn)
tmap[tt] = t
cv.layout.rename_cell(tt, "")
cv.layout.prune_subcells(tt, -1)
end
end
pmap = {}
cmap = copy_cells(lib, cv.layout, new_layers, pmap)
cv.layout.each_cell do |c|
# change and the instances
c.each_inst do |inst|
if tmap[inst.cell_index]
# get the instance object and create a new one with the new cell index
i = inst.cell_inst
trans = i.is_complex? ? i.cplx_trans : i.trans
cinew = cmap[tmap[i.cell_index]]
if i.is_regular_array?
c.replace(inst, RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb))
else
c.replace(inst, RBA::CellInstArray.new(cinew, trans))
end
end
end
end
# delete old cells
tmap.each do |k,v|
cv.layout.prune_cell(k, -1)
end
if has_new_layers
mw.cm_lv_add_missing
end
end