Extract or Replace a cell with it's hierarchy via RBA

edited July 2012 in General
Hi Matthias,

Is there a way to extract a cell with it's hierarchy(like the "Save Current Cell As" function in Cells list) via RBA ? currently a possible code I think is the following steps:
1. Open the original database
2. New a layout database
3. Copy the cell we want from original to new
4. Save the new layout to a GDS/OASIS

For the replace action:
1. Open the original database
2. Open the cell database
3. Delete the cell(maybe "A") from original
4. Copy "A" from cell to original
5. Save original

Is that correct?

Best Regards,
--
chhung

Comments

  • edited July 2012

    Hi Matthias,

    I referenced the following code you wrote and trying to implement the cell extraction function via RBA code, however it failed with the error message, I guess the copy_cells could not be used in this condition, could you please give me some hints ?

    Error message:
    *** ERROR: ./test.rb:38: Ruby error: 'No method with matching arguments for method new, class CellInstArray' (RuntimeError)

    # Code:
    
    def copy_cells(lsrc, ltarget, lmap, srccellname)
    
      citarget = nil
    
      # a map for the cell indices
      cmap = {}
    
      lsrc.each_cell_bottom_up do |cisrc|
      if lsrc.cell_name(cisrc) == srccellname
        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|
            newshape = shtarget.insert(shape)
            shtarget.replace_prop_id(newshape, 0) #  clear properties
          end
        end
    
        # translate and copy the instances
        csrc.each_inst do |inst|
    
          # 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?
            ctarget.insert(RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb))
          else
            ctarget.insert(RBA::CellInstArray.new(cinew, trans))
          end
    
        end
    
      end
      end
      return citarget
    
    end
    
    (read Source / open Target / copy layers)...
    
    SourceCellName="Cell1"
    
    TargetTop = copy_cells(Source, Target, lmap_Source2Target, SourceCellName)
    
    Target.write("output.gds")
    

    If I remark lines about CellInstArray, the code works and output correct patterns, however the extracted cell would not contain the instances.

    Ref:
    http://klayout.de/forum/comments.php?DiscussionID=103&page=1#Item_0

  • edited August 2012

    Hi chunng,

    the problem is caused by the test for the cell name:

    lsrc.each_cell_bottom_up do |cisrc|
      if lsrc.cell_name(cisrc) == srccellname 
        ...
      end
    end
    

    is not confining the copy to a subtree. Instead it will only select the cell with srccellname and that is why there are not copies of child cells when the function is trying to map the cell instances.

    Instead the code should look like that:

    srccellindex = lsrc.cell_by_name(srccellname)
    
    # create a hash holding indexes for all cells that are direct or indirect children of 
    # the root cell of the tree to copy. Also add the root cell
    called_cells = { scrcellindex => true }
    ldrc.cell(srccellindex).called_cells.map { |ci| called_cells[ci] = true }
    
    # Now process all (but only these) cells which are part of that subtree bottom-up
    lsrc.each_cell_bottom_up do |cisrc|
      if called_cells[cisrc] 
        ...
      end
    end
    

    This code should process all cells which need to be copied. Doing that bottom-up ensures that child cells are available when they are required to map instanced.

    Lacking the complete code I have not tested that, but I am confident it works.

    Best regards,

    Matthias

  • edited August 2012

    Hi Matthias,

    I modified the code and try to run it again, however the result didn't fit our request, it still contains all the cells in the original database(just like copy), not extracted cell with sub cells.

    The whole RBA code:

    def copy_cells(lsrc, ltarget, lmap, srccellname)
    
      citarget = nil
    
      # a map for the cell indices
      cmap = {}
    
      srccellindex = lsrc.cell_by_name(srccellname)
    
      # create a hash holding indexes for all cells that are direct or indirect children of 
      # the root cell of the tree to copy. Also add the root cell
      called_cells = { srccellindex => true }
      lsrc.cell(srccellindex).called_cells.map { |ci| called_cells[ci] = true }
    
      lsrc.each_cell_bottom_up do |cisrc|
        if called_cells[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|
              newshape = shtarget.insert(shape)
              shtarget.replace_prop_id(newshape, 0) # clear properties
            end
          end
    
          # translate and copy the instances
          csrc.each_inst do |inst|
    
            # 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?
              ctarget.insert(RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb))
            else
              ctarget.insert(RBA::CellInstArray.new(cinew, trans))
            end
    
          end
    
        end
      end
    
      # Return the last cell's index which (because we iterated bottom up) is a top cell
      return citarget
    
    end
    
    Source = RBA::Layout.new
    Source.read("test.gds")
    
    Target = RBA::Layout.new
    Target.dbu = Source.dbu
    
    lmap_Source2Target = {}
    linfo_to_index = {}
    
    Source.layer_indices.each do |layer|
      linfo = Source.get_info(layer)
      TargetLayer = Target.insert_layer(linfo)
      lmap_Source2Target[layer] = TargetLayer;
      linfo_to_index[linfo.to_s] = TargetLayer
    end
    
    SourceCellName="Cell5"
    
    TargetTop = copy_cells(Source, Target, lmap_Source2Target, SourceCellName)
    
    Target.write("out.gds")
    

    Best Regards,

    chhung

  • edited August 2012

    Hi chhung,

    your script is missing a tiny but important detail: the "if" inside the "lsrc.each_cell_bottom_up do |cisrc| ..." loop is missing.

    See my code above:

    # Now process all (but only these) cells which are part of that subtree bottom-up
    lsrc.each_cell_bottom_up do |cisrc|
    
      if called_cells[cisrc]  # <--- please add that "if" to your script!
        ...
      end
    
    end
    

    with this, the script should only copy should be confined to the subtree of the given cell (I can't edit your reply otherwise I would have corrected that :-) )

    Best regards,

    Matthias

  • edited 11:13PM

    Hi Matthias,

    You are right, I missed the "if called_cells[cisrc]" statement...

    I modified the code and confirmed it works fine now, and I edited/corrected the code in the above post for others who interesting in it.

    Really appreciate your kindly support~ :-)

    Best Regards,

    chhung

Sign In or Register to comment.