Dummy Filling during Layout design

This sample illustrates how to perform dummy filling on a layout. Dummy filling is crucial for controlling the density of certain layers, which helps prevent issues during fabrication steps.

In IPKISS, dummy filling can be performed directly on your layout by using ipkiss3.all.dummy_fill_layout, or on a gds file by using ipkiss3.all.dummy_fill_gdsii.

This example demonstrates how to:

  • Define a test structure and a design containing a routed splitter tree.

  • Add a frame to simulate a realistic design boundary.

  • Apply dummy filling to the layout using a specified fill cell, while ignoring certain layers (e.g., the documentation layer).

Disclaimer: Dummy filling here is done on the silicon layer only, since no metal was used in this device.

plot dummy filling
import pteam_library_si_fab.all as lib
import si_fab.all as pdk

import ipkiss3.all as i3

DESIGN_SIZE = (1000, 1000)


class TestStructure(i3.PCell):
    total_length = i3.PositiveNumberProperty(
        default=DESIGN_SIZE[0] - 100,
        doc="Total length of the test structure",
    )

    class Layout(i3.LayoutView):
        def generate(self, layout):
            gc = pdk.GratingCoupler()
            layout += i3.place_and_route(
                insts={"gc_in": gc.Layout(), "gc_out": gc.Layout()},
                specs=[
                    i3.Place("gc_in@CW", (0, 0)),
                    i3.Place("gc_out@CE", (self.total_length, 0), angle=180),
                    i3.ConnectManhattan("gc_in:out", "gc_out:out"),
                ],
            )
            return layout


class Design(i3.PCell):
    class Layout(i3.LayoutView):
        def generate(self, layout):
            # We instantiate the splitter tree
            splitter_tree = lib.SplitterTree(levels=5)
            # We pass the splitter tree to the routed splitter tree
            routed_splitter_tree = lib.RoutedSplitterTree(splitter_tree=splitter_tree, length_of_out_wg=120)
            length = routed_splitter_tree.Layout().size_info().get_width()
            layout += i3.place_and_route(
                insts={
                    "DUT": routed_splitter_tree,
                    "test_structure": TestStructure(total_length=length),
                },
                specs=[
                    i3.Place.X("test_structure", x=50),
                    i3.Place.X("DUT@W", x=50),
                    i3.Place.Y("test_structure@S", y=50),
                    i3.Place.Y("DUT@S", y=50, relative_to="test_structure@N"),
                ],
            )

            # add a frame, such it replicates a realistic design
            layout += i3.Box(
                layer=pdk.TECH.PPLAYER.DOC, box_size=DESIGN_SIZE, center=(DESIGN_SIZE[0] / 2, DESIGN_SIZE[1] / 2)
            )

            # Now we want to perform dummy filling on the layout directly -> this makes it easier to iterate
            # For this example, we don't have metal layers to fill, so we fill the silicon layers to control density
            # and prevent problems during litho and wet etch.

            # We create a square using i3.Box to serve as the dummy fill cell.
            fill_cell = i3.Box(layer=pdk.TECH.PPLAYER.SI, box_size=(4, 4))

            # Now we dummy fill our current layout, given the fill_cell
            # Since the frame covers the design, we specify it in the ignore argument.
            # Otherwise, the dummy fill will try to avoid overlapping it.
            dummy_elements = i3.dummy_fill_layout(layout, fill_cell=fill_cell, ignore=[pdk.TECH.PPLAYER.DOC])

            # if you want more control over the dummy filling you can specify more of the parameters
            # dummy_elements = i3.dummy_fill_layout(
            #     layout,
            #     fill_cell=fill_cell,
            #     target=pdk.TECH.PPLAYER.DOC, # target is the layer which defines the area to do the dummy filling in
            #     ignore=[pdk.TECH.PPLAYER.DOC], # the frame is perfect target layer, but we want to ignore it here
            #     density=0.75,
            #     design_buffer=5,
            #     edge_buffer=20,
            # )
            #
            layout += dummy_elements

            return layout


Design().Layout().visualize()

# if you want to do dummy filling on a gds, that is also possible using the other function
# i3.dummy_fill_gdsii(filename, fill_cell, ...)