fill multiorigin and manufacturing grid

So I'm calling something like M4Fil.fill(pattern_m4s, hstep(width_m4s + distance_m4s), vstep(height_m4s + distance_m4s), multiorigin) to generate a fill pattern.
But how can I ensure that the selected origin matches the manufacturing grid of 5 nm ? Where do I set that ?

Comments

  • The multiorigin feature will align the fill pattern to existing features - either original ones or residuals which are left from previous fill steps. Provided the original features are on-grid and the fill pattern is too (pattern dimensions and step vectors), the fill function should always generate on-grid pattern.

    Matthias

  • We are currently trying both the auto_origin and multi_origin options. They are giving very good fill density results, yet parts of the pattern are off-grid. Most of them are off by 2nm. We are using KLayout 0.30.2 with IHP's 130nm open PDK and the following Ruby script:

    https://github.com/IHP-GmbH/IHP-Open-PDK/blob/main/ihp-sg13g2/libs.tech/klayout/tech/macros/sg13g2_filler_Metal.lym

    We added the options only to metal1-3 on the second fill iteration (using the small pattern).

    Is the enhanced option of the GUI tool the same as multi_origin? How can we enable this enhanced version from a Ruby script?

  • Hi @tbenz,

    Could you provide some sample layout?

    The fill itself does not imply a grid, but it takes original layout vertexes as reference points. If all of them are on-grid, the fill should be on-grid as well.

    The fill script you are using is not ideal. There is some room for improvement. You should wait for 0.30.4 and rewrite the script.

    Matthias

  • edited September 2

    This is our current chip before filling: https://iis-people.ee.ethz.ch/~tbenz/hati/hati_chip_sealring.gds.gz
    And after M1-M5 filling with the following script: https://iis-people.ee.ethz.ch/~tbenz/hati/sg13g2_filler_Metal.lym

    Resulting in: https://iis-people.ee.ethz.ch/~tbenz/hati/hati_chip_sealring_filled.gds.gz with many off-grid violations on Metal1 and Metal3.

    We are using the default filling scripts from IHP. Do you know if they are planning to adapt their flow to 0.30.4?

  • edited September 14

    Hi Thomas,

    I am not quite sure how the actual fill rules need to look like. The Magic-based fill uses a threefold fill pattern, which I have tried to replicate. Here is my script for Metal 1 which I tested on Greyhound and which uses 0.30.4 features and tiled mode parallel on 4 cores:

    verbose
    
    ncpu = 4
    tile_size = 500
    
    # Should be 189/4, but it seems not always to be drawn
    chip = extent
    
    # Prepare a hierarchy below the top cell to hold the fill pattern later
    top_cell = source.cell_obj
    
    # for metal1
    metal1_fill_top = source.layout.create_cell("METAL1_FILL")
    top_cell.insert(RBA::CellInstArray::new(metal1_fill_top, RBA::Trans::new))
    
    # Preparation is done in deep mode for efficiency
    
    deep
    
    # Find the sealring so we can exclude everything outside
    # NOTE: this must not happen in tiled mode as the sealring
    # is only visible as a whole in flat mode
    sealring_name = nil
    source.cell_obj.each_child_cell do |cc| 
      cn = source.layout.cell_name(cc)
      if cn =~ /^sealring/
        sealring_name = cn
      end
    end
    
    if sealring_name
      sealring = source.cell(sealring_name)
      metal1_seal = sealring.input(8, 0)
      metal1_seal_inner = metal1_seal.holes
      metal1_seal_outer = chip.interacting(metal1_seal_inner) - metal1_seal_inner
    else
      # NOTE: metal1_seal_outer is empty if there is no sealring ->
      # the full chip will be filled
      metal1_seal_outer = polygons
    end
    
    # switch to the output cell for the metal1 fill
    output_cell(metal1_fill_top.name)
    
    metal1 = input(8, 0)
    metal1_nofill = input(8, 23) + metal1_seal_outer
    
    metal1_fill_layer = [ 8, 22 ]
    
    metal1_dist = 0.42
    
    # compute the metal1 fill area
    [ 
      # Cell name, dimension, hstep, vstep
      [ "METAL1_FILL", 5.0, hstep(7.0, 0),  vstep(1.5, 7.0)   ],
      [ "METAL2_FILL", 2.0, hstep(2.42, 0), vstep(0.65, 2.42) ],
      [ "METAL3_FILL", 1.2, hstep(1.62, 0), vstep(0.3, 1.62)  ]
    ].each do |fill_def|
    
      (cell_name, dim, hs, vs) = fill_def
    
      # Preparation is done in deep mode
      deep 
    
      to_fill = chip
      metal1_fill = input(*metal1_fill_layer)
      fill_excl = metal1 + metal1_fill + metal1_nofill
    
      # Fill can be done in tiled mode
      tiles(tile_size)
      tile_borders(0.0)
      threads(ncpu)
    
      pattern = fill_pattern(cell_name)
      pattern.shape(*metal1_fill_layer, box(0.0, 0.0, dim, dim))
      pattern.dim(dim, dim)
      pattern.margin(metal1_dist, metal1_dist)
    
      fill_origin = origin(0, 0)
      to_fill = to_fill.fill_with_left(pattern, hs, vs, fill_origin, fill_exclude(fill_excl))
    
      # try another origin
      d = dim * 0.5 + metal1_dist
      fill_origin = origin(d, d)
      to_fill.fill(pattern, hs, vs, fill_origin)
    
    end 
    

    I am not happy with multi_origin and auto_origin. Both are pretty dumb implementations and in tiled mode, they create visible tile border artefacts. Instead I am using two origins for each fill pattern. That gives a pretty decent homogeneous fill, but also increases your capacitive coupling. Also, with a fixed origin, offgrids should not be an issue. Here is a screenshot:

    The script runs a few minutes with your design and greyhound. It's an interactive script (run it after loading the layout) and can be easily extended to cover the other metals and diffusion or poly.

    Matthias

Sign In or Register to comment.