# This code is part of KQCircuits
# Copyright (C) 2021 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/developers/osstmpolicy). IQM welcomes contributions to the code. Please see our contribution agreements
# for individuals (meetiqm.com/developers/clas/individual) and organizations (meetiqm.com/developers/clas/organization).
from kqcircuits.pya_resolver import pya
from kqcircuits.util.parameters import Param, pdt
from kqcircuits.elements.element import Element
[docs]class MaskMarkerFc(Element):
"""The PCell declaration for a MaskMarkerFc.
Mask alignment marker for flip-chip masks
"""
window = Param(pdt.TypeBoolean, "Window in airbridge flyover and UBM layer", False)
arrow_number = Param(pdt.TypeInt, "Number of arrow pairs in the marker", 3)
[docs] @staticmethod
def create_cross(arm_length, arm_width):
m = arm_length / 2
n = arm_width / 2
cross = pya.DPolygon([
pya.DPoint(-n, -m),
pya.DPoint(-n, -n),
pya.DPoint(-m, -n),
pya.DPoint(-m, n),
pya.DPoint(-n, n),
pya.DPoint(-n, m),
pya.DPoint(n, m),
pya.DPoint(n, n),
pya.DPoint(m, n),
pya.DPoint(m, -n),
pya.DPoint(n, -n),
pya.DPoint(n, -m)
])
return cross
[docs] def build(self):
arrow = pya.DPolygon([
pya.DPoint(0, 0),
pya.DPoint(-20, 20),
pya.DPoint(-11, 25),
pya.DPoint(-5, 19),
pya.DPoint(-5, 62),
pya.DPoint(5, 62),
pya.DPoint(5, 19),
pya.DPoint(11, 25),
pya.DPoint(20, 20)
])
layer_gap = self.get_layer("base_metal_gap_wo_grid")
layer_pads = self.get_layer("airbridge_pads")
layer_flyover = self.get_layer("airbridge_flyover")
layer_ubm = self.get_layer("underbump_metallization")
layer_indium_bump = self.get_layer("indium_bump")
layer_protection = self.get_layer("ground_grid_avoidance")
def insert_to_main_layers(shape):
self.cell.shapes(layer_gap).insert(shape)
if not self.window:
self.cell.shapes(layer_flyover).insert(shape)
# protection for the box
protection_box = pya.DBox(
pya.DPoint(200, 350),
pya.DPoint(-200, -350)
)
self.cell.shapes(layer_protection).insert(protection_box)
negative_layer = pya.Region([protection_box.to_itype(self.layout.dbu)])
# crosses
arm_widths = [20, 35, 70]
arm_lengths = [70, 124, 250]
offset_width = [30, 43, 85]
offset_length = [80, 132, 265]
shift = pya.DPoint(0, 250)
dislocation = 0
for i, (cross_width, cross_length) in enumerate(zip(arm_widths, arm_lengths)):
if i != 0:
dislocation = arm_lengths[i - 1] + arm_lengths[i] + 100
shift += pya.DPoint(0, -dislocation / 2)
inner_shapes = pya.DCplxTrans(1, 0, False,
pya.DVector(shift)) * self.create_cross(offset_length[i], offset_width[i])
insert_to_main_layers(inner_shapes)
inner_corner_shape = pya.DCplxTrans(1, 0, False,
pya.DVector(shift)) * self.create_cross(cross_length, cross_width)
for layer_insert in [layer_pads]:
self.cell.shapes(layer_insert).insert(inner_corner_shape)
negative_offset = pya.DCplxTrans(1, 0, False,
pya.DVector(shift)) * self.create_cross(arm_lengths[i], arm_widths[i])
negative_layer -= pya.Region([negative_offset.to_itype(self.layout.dbu)])
inner_shapes_offset = pya.DCplxTrans(1, 0, False,
pya.DVector(shift)) * self.create_cross(arm_lengths[i], arm_widths[i])
self.cell.shapes(layer_indium_bump).insert(inner_shapes_offset)
self.cell.shapes(layer_ubm).insert(negative_layer)
# marker arrow
for i in range(self.arrow_number):
for j in [-1, 1]:
arrows_shape = pya.DCplxTrans(1, 0, j != 1,
j * pya.DVector(0, 200 * i + 400)) * arrow
insert_to_main_layers(arrows_shape)
for layer_insert in [layer_pads, layer_indium_bump]:
self.cell.shapes(layer_insert).insert(arrows_shape)