Defining ID field an automatic numbering

edited September 2015 in KLayout Support
Hi guys,
I'm pretty new with layout design but I found klayout great and at the same time really intuitive.
I'm working on a lithography mask design and I was wondering if there is a way to assign automatically an ID to every structure on the mask(for example an incremental number).

Comments

  • edited September 2015

    Sure there is, via Ruby/Python script and possibly via the 'rename cells' function, depending on what you are trying to do.

    Can you give some more details about how you want to assign the number, or what you want to assign the number to. For example I could interpret your question in multiple ways, each of which has a different script associated. E.g.

    • During layout you want to place cell CELL1 1000 times; append a unique 4-digit (or whatever) number to each instance cell name (effectively creating N unique cells) or add a property with this number (effectively keeping only 1 cell that is instanced N times, each instance having different property assigned)
    • Same as above but do this every time you create a cell, no matter what the cell is, incrementally, starting at 0000
    • After layout, rename all cells to post-pend them with a unique 4-digit (or whatever) number
    • Or maybe you want to actually print the numbers on the mask itself, inside each instance

    Reframing your question like one of the above allows us to help you with a script

    Thanks,

    David

  • edited November -1
    Hi David,
    Thanls a lot for your reply. You are right. The ID has to be printed on the mask itself: I'm doing some semiconductor chip design and, once the wafer processing is performed the ID would be used to retrieve the position of the chip on the semiconductor wafer.

    Nino
  • edited September 2015

    The easiest way I think is to use "PCell array generator.lym", which is part of TRT. Once you've installed TRT per the instructions at that link, reopen KLayout. Open a new layout. Click the menu at the top and then Cells > PCell array.*

    There is an example spreadsheet file in the same "Cells" subfolder, that prints "KLAYOUT RULES" on the wafer three times, three different magnifications. Direct the dialog to point to that file and choose your other parameters then click OK to see the result.

    Caveat: That script has not undergone rigorous testing, so if you find problems let me know.

    There are other more custom ways. If this is not suitable for you, let us know a more about your requirements.

    David

    *It's not a true array, it's just some instances at some xy locations.

  • edited November -1
    Thanks a lot David,

    I'll give it a try. and let you know

    Nino
  • edited November -1
    Hi Nino,

    Did you find a good solution or implementation for this. I was thinking of doing something very similar.

    Thanks,

    Keil
  • edited November -1

    keilboring,

    Did "PCell array generator.lym" not work for you?

    David

  • edited November -1
    It works but I have multiple devices per mask. Each device has a different SN that needs incremented and each device is of different size. I am new to Klayout and VLSI in general but I was thinking of each device to have a temporary SN that I could just find and replace and not worry about coordinates. Do you know how to find a replace a text box or where I might find this information?

    Thanks again,
    Keil
  • edited November 2015

    You are right, if you want "find and replace" characteristics then this will not work. Not sure exactly how to do that without writing a quite complicated custom script.

    Perhaps the simplest quick fix, though this is a bit 'hacky':

    You could generate it using PCellArrayGenerator the first time, then whenever you want to change the text label, you first delete them all using a custom script (which you'd need to write) and then regenerate them by running PCellArrayGenerator again (but with an updated Excel file as input).

    How to write such a script that deletes all previously-placed instances? Perhaps easiest way is to modify PCellArrayGenerator so that every time it places a PCell it also applies a property. A property is some metadata attached to a cell or shape. It has a key and a value. Something like "MYPCELL" for key and #1 for value would work. ('#' signifies that '1' is an integer instead of a string, '##' signifies a float.) So then your additional custom script that you write would iterate thru all cells in the layout and delete any with property, value pair equal to "MYPCELL" : #1. Then, when they are all deleted you can add them back in again by running PCellArrayGenerator again, as I mentioned earlier.

    Anyway that requires some effort in learning Ruby scripting and going down that rabbit hole... But first it is prudent to ask: would that even solve the problem you have? Did I even understand your requirement correctly?

    David

  • edited November -1
    David,

    Nice idea with the keys. I am not starting on this project right away but will post back if i decide to make some custom scripts around this idea.

    Keil
  • edited November -1
    This is what I got so far. I insert a PCell Text into the current layout getting coordinates from a text file.
    The coordinates are just from a simple delimited text file.
    TEXT1,0,0.00,r270,
    TEXT2,5.00,10.00,r0,

    What i cant figure out is how to run this from command line successfully. I run "klayout_app.exe my_layout.gds -r CreateText.lym". I get "No view selected". How do i select a view? I tried adding Application.instance.main_window.select_view(0) to try and select the first one but get error "layMainWindow.cc:3117 index >= 0 && index < int (views ()) was not true in MainWindow::select_view" .



    Also tried "Application.instance.main_window.load_layout("my_layout.gds",0)" but got error "Internal error: dbLayout.cc:2069 ! (manager () && manager ()->transacting()) was not true".


    So how do i select the the layout from the the .gds file so this the code below will work from command line? The second one works if i run it twice but i get the error.


    Any help would be great.

    Thanks
    Keil


    [code]

    module MyMacro

    include RBA

    RBA::Application.instance.exec

    lv = Application.instance.main_window.current_view
    raise "No view selected" if lv.nil?

    app = Application.instance
    mw = app.main_window
    ly = lv.active_cellview.layout
    #dbu = ly.dbu
    #out_cell = lv.active_cellview.cell
    top = ly.top_cell.name
    # ly = RBA::Layout.new
    #top = ly.add_cell("TOP")

    lv.transaction("Insert P-cell array")
    # Find the lib
    lib = RBA::Library.library_by_name("Basic")
    lib || raise("Unknown lib 'Basic'")

    # Find the pcell
    pcell_decl = lib.layout.pcell_declaration("TEXT")
    pcell_decl || raise("Unknown PCell 'TEXT'")

    File.open("text.txt") do |file|
    file.each_line do |line|
    if line[0] != "#"
    array = line.split(",")
    string = array[0]
    # assume the coordinates are micron units
    x = (array[1].to_f / ly.dbu + 0.5).floor
    y = (array[2].to_f / ly.dbu + 0.5).floor
    rotation = array[3]
    # Set the parameters (text string, layer to 10/0, magnification to 2.5)
    param = { "text" => string, "layer" => RBA::LayerInfo::new(10, 0), "mag" => 2.5 }
    # Build a param array using the param hash as a source.
    # Fill all remaining parameter with default values.
    pv = pcell_decl.get_parameters.collect do |p|
    param[p.name] || p.default
    end

    # Create a PCell variant cell
    pcell_var = ly.add_pcell_variant(lib, pcell_decl.id, pv)

    # Instantiate that cell
    if rotation == "r0"
    t = RBA::Trans::new(RBA::Trans::r0, x, y)
    elsif rotation == "r90"
    t = RBA::Trans::new(RBA::Trans::r90, x, y)
    elsif rotation == "r180"
    t = RBA::Trans::new(RBA::Trans::r180, x, y)
    elsif rotation == "r270"
    t = RBA::Trans::new(RBA::Trans::r270, x, y)
    else
    t = RBA::Trans::new(RBA::Trans::r0, x, y)
    end
    pcell_inst = ly.cell(top).insert(RBA::CellInstArray::new(pcell_var, t))
    end
    end
    end
    lv.add_missing_layers # In case you've specified layers in the spreadsheet that don't yet exist
    # save the layout
    ly.write("my_layout.gds")
    #ensure
    #lv.commit

    end
    [/CODE]
  • edited November -1

    Hi Keil,

    You should not use "RBA::Application.instance.exec". This will basically execute the application and once you close the main window the application is in terminated state and you can't access the objects any longer. "RBA::Application.exec" is intended to be used as the final statement of certain scripts which provide some setup functionality. But there are better ways to achieve that now (the auto-run flag of macros), so that feature is no longer required.

    If you want a pure processing application, you can drop the overhead of MainWindow, LayoutView and so forth. Running KLayout is not only more efficent then, it's also easier to write scripts that way.

    Here is a basic recipe:

    Create a script that loads a layout directly. The name of the layout will will be given by a global variable that we will define on the command line:

    ly = RBA::Layout::new
    ly.read($input)
    
    # do something with the layout 
    
    ly.write($output)
    

    Save this script (for example as "myscript.rb") and execute it in batch mode (-b). Provide the input and output variables using the "-rd" option:

    ./klayout -b -r myscript.rb -rd input=in.gds -rd output=out.gds
    

    Matthias

  • edited November 2015

    Thanks for help. I ended up using this script to add a serial number to each device and change the name of the top cell. Then i use another script to merge all the files together. I am new to klayout and ruby so this might have a few bugs still.

    module MyMacro
    
    
      # Run with: klayout_app.exe -b -r addSerialNumber.lym -rd inputFile=myFileIn.gds -rd outputFile=myFileOut.gds -rd mirror=TRUE -rd rotation=r180 -rd X=-6000 -rd Y=8000 -rd layer=9 -rd dataType=210 -rd SN=ABC123 -rd magnification=600
      # Program opens a layout and adds a Serial number with given layer,dataType and magnification
      include RBA
      ly = RBA::Layout::new
      ly.read($inputFile)
    
      # create new cell TOP
      #cell_index = ly.add_cell($SN)
      cell = ly.cell(ly.top_cell.cell_index)
    
    
      # Find the lib
      lib = RBA::Library.library_by_name("Basic")
      lib || raise("Unknown lib 'Basic'")
    
      # Find the pcell
      pcell_decl = lib.layout.pcell_declaration("TEXT")
      pcell_decl || raise("Unknown PCell 'TEXT'")
    
    
      if $mirror.to_s == "TRUE" 
         mirror = TRUE
      else
         mirror = FALSE
      end
    
      # assume the coordinates are micron units
      x = ($X.to_f / ly.dbu + 0.5).floor
      y = ($Y.to_f / ly.dbu + 0.5).floor
      rotation = $rotation
    
      # Set the parameters (text string, layer to 10/0, magnification to 2.5)
      param = { "text" => $SN, "layer" => RBA::LayerInfo::new($layer.to_i, $dataType.to_i), "mag" => $magnification.to_i }
    
      # Build a param array using the param hash as a source.
      # Fill all remaining parameter with default values.
      pv = pcell_decl.get_parameters.collect do |p|
        param[p.name] || p.default
      end
    
      # Create a PCell variant cell
      pcell_var = ly.add_pcell_variant(lib, pcell_decl.id, pv)
    
      # Instantiate that cell
      if $rotation == "r0"
          t = RBA::Trans::new(RBA::Trans::r0,mirror, x, y)
      elsif $rotation == "r90" 
          t = RBA::Trans::new(RBA::Trans::r90,mirror, x, y)
      elsif $rotation == "r180"
          t = RBA::Trans::new(RBA::Trans::r180,mirror, x, y)
      elsif $rotation == "r270"
          t = RBA::Trans::new(RBA::Trans::r270,mirror, x, y)  
      else
          t = RBA::Trans::new(RBA::Trans::r0,mirror, x, y)
      end
    
      #Get top cell of file
      ly.top_cells.each { |curCell|
          pcell_inst = ly.cell(curCell.name).insert(RBA::CellInstArray::new(pcell_var, t))
          ly.rename_cell(curCell.cell_index, $SN + "_" + curCell.name) 
        break
      }
    
      #ly.rename_cell(ly.top_cell.cell_index, $SN)        
      ly.write($outputFile)
    end
    
  • edited November -1

    Nice work, it's a good example. I rarely run from command line, so E4K was lacking any examples of this. I just added it, attributed to you of course. I hope this is okay but I presume it is since you've already posted the script publicly here on the forum.

    Thanks,

    David

  • edited November -1

    Yeah anything I post on a forum is fair game. Also note i accidentally left a useless line "rotation = $rotation" above. It does nothing because i reference $rotation later instead of rotation.

Sign In or Register to comment.