Source code for ihp.cells.bondpads

"""Bondpad components for IHP PDK."""

import math
from typing import Literal

import gdsfactory as gf
from gdsfactory import Component
from gdsfactory.typings import LayerSpec


def regular_octagon_points(diameter: float):
    """Create a regular octagon"""
    side = diameter / (1 + math.sqrt(2))
    R = side / (2 * math.sin(math.pi / 8))
    start_angle = math.pi / 8
    return [
        (
            R * math.cos(start_angle + i * math.pi / 4),
            R * math.sin(start_angle + i * math.pi / 4),
        )
        for i in range(8)
    ]


@gf.cell
def bondpad(
    shape: Literal["octagon", "square", "circle"] = "octagon",
    diameter: float = 80.0,
    layer_top_metal: LayerSpec = "TopMetal2drawing",
    layer_passiv: LayerSpec = "Passivpillar",
    layer_dfpad: LayerSpec = "dfpaddrawing",
    bbox_offsets: tuple[float, ...] | None = (-2.1, 0),
    flip_chip: bool = False,
) -> gf.Component:
    """Create a bondpad for wire bonding or flip-chip connection.

    Args:
        shape: Shape of the top-metal bondpad ("octagon", "square", or "circle").
        diameter: Interpreted as across-flats for octagons / squares, and diameter for circles.
        layer_top_metal: Top metal layer.
        layer_passiv: Passivation-opening layer.
        layer_dfpad: Deep-fill or density-fill support layer.
        bbox_offsets: Per-layer expansion distances in micrometers, applied to the passivation and dfpad layers.
        flip_chip: If True, suppress passivation opening for flip-chip bumps.

    Returns:
        Component containing the complete bondpad stack.
    """

    c = gf.Component()
    d = float(diameter)

    # Add top metal layer
    if shape == "square":
        c.add_ref(
            gf.components.rectangle(size=(d, d), layer=layer_top_metal, centered=True)
        )

    elif shape == "octagon":
        pts = regular_octagon_points(d)
        c.add_polygon(points=pts, layer=layer_top_metal)

    elif shape == "circle":
        c.add_ref(gf.components.circle(radius=d / 2, layer=layer_top_metal))

    else:
        raise ValueError(f"Unknown shape: {shape}")

    # Add additional layers
    if flip_chip:
        # Skip passivation opening for flip-chip
        bbox_layers = (layer_dfpad,)
        bbox_offsets = (bbox_offsets or ())[1:]
    else:
        bbox_layers = (layer_passiv, layer_dfpad)

    for layer, offset in zip(bbox_layers, bbox_offsets or ()):
        new_d = d + float(offset * 2)

        if shape == "square":
            c.add_ref(
                gf.components.rectangle(size=(new_d, new_d), layer=layer, centered=True)
            )
        elif shape == "circle":
            c.add_ref(gf.components.circle(radius=new_d / 2, layer=layer))
        elif shape == "octagon":
            c.add_polygon(points=regular_octagon_points(new_d), layer=layer)

    # Add port
    c.add_port(
        name="pad",
        center=(0, 0),
        width=d,
        orientation=0,
        layer=layer_top_metal,
        port_type="electrical",
    )

    # Add metadata
    c.info["shape"] = shape
    c.info["diameter"] = diameter
    c.info["top_metal"] = layer_top_metal
    return c


[docs] @gf.cell def bondpad_array( n_pads: int = 4, pad_pitch: float = 100.0, pad_diameter: float = 80.0, shape: Literal["octagon", "square", "circle"] = "octagon", layer_top_metal: LayerSpec = "TopMetal2drawing", layer_passiv: LayerSpec = "Passivpillar", layer_dfpad: LayerSpec = "dfpaddrawing", bbox_offsets: tuple[float, ...] | None = (-2.1, 0), ) -> Component: """Create an array of bondpads. Args: n_pads: Number of bondpads. pad_pitch: Pitch between bondpad centers in micrometers. pad_diameter: Diameter of each bondpad in micrometers. shape: Shape of the bondpads. layer_top_metal: Top metal layer for the bondpad. layer_passiv: Passivation layer. layer_dfpad: Deep fill pad layer. bbox_offsets: Offsets for each additional layer. Returns: Component with bondpad array. """ c = Component() for i in range(n_pads): pad = bondpad( shape=shape, diameter=pad_diameter, layer_top_metal=layer_top_metal, layer_passiv=layer_passiv, layer_dfpad=layer_dfpad, bbox_offsets=bbox_offsets, ) pad_ref = c.add_ref(pad) pad_ref.movex(i * pad_pitch) # Add port for each pad c.add_port( name=f"pad_{i + 1}", center=(i * pad_pitch, 0), width=pad_diameter, orientation=0, layer=pad.ports["pad"].layer, port_type="electrical", ) c.info["n_pads"] = n_pads c.info["pad_pitch"] = pad_pitch c.info["pad_diameter"] = pad_diameter return c
if __name__ == "__main__": from gdsfactory.difftest import xor from ihp import PDK from ihp.cells import fixed PDK.activate() # Test the components c0 = fixed.bondpad() # original c1 = bondpad(shape="octagon") # new c = xor(c0, c1) c.show() # c2 = bondpad(shape="square", flip_chip=True) # c2.show() # c3 = bondpad_array(n_pads=6) # c3.show()