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