Skip to content

Instantly share code, notes, and snippets.

@s910324
Created April 17, 2023 07:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save s910324/693ba2d1a25b0d2309b3fe6f01edddbf to your computer and use it in GitHub Desktop.
Save s910324/693ba2d1a25b0d2309b3fe6f01edddbf to your computer and use it in GitHub Desktop.
import pya
import math
class Toolkit(object):
def __init__(self):
super(Toolkit, self).__init__()
def sin(deg):
return math.sin(Toolkit.deg_2_arc(deg))
def cos(deg):
return math.cos(Toolkit.deg_2_arc(deg))
def tan(deg):
return math.tan(Toolkit.deg_2_arc(deg))
def deg_2_arc(deg):
return (deg / 360) * 2 * math.pi
def arc_2_deg(arc):
return (arc / 2 / math.pi) * 360
def circle(x, y, r, p = 64, deg1 = 0, unit = 1, checker = None):
pts = []
if isinstance(checker, (float, int)):
if ((x ** 2 + y ** 2) ** (0.5) > (checker - r)):
return pts
if isinstance(checker, (list, tuple)):
if ((x ** 2 + y ** 2)**(0.5) > (max(checker) - r)) or ((x ** 2 + y ** 2) ** (0.5) < (min(checker) - r)):
return pts
for i in range(p):
ccx = x + r * Toolkit.cos(deg1 + (360 / p) * i)
ccy = y + r * Toolkit.sin(deg1 + (360 / p) * i)
pts.append(pya.DPoint(ccx / unit, ccy / unit))
return pts + [pts[0]]
def rect(x, y, w, h, unit = 1):
return [
pya.DPoint((x + (w/2)) / unit, (y + (h/2)) / unit),
pya.DPoint((x - (w/2)) / unit, (y + (h/2)) / unit),
pya.DPoint((x - (w/2)) / unit, (y - (h/2)) / unit),
pya.DPoint((x + (w/2)) / unit, (y - (h/2)) / unit),
pya.DPoint((x + (w/2)) / unit, (y + (h/2)) / unit),
]
class Wafer(pya.PCellDeclarationHelper):
def __init__(self):
super(Wafer, self).__init__()
self.param("name", self.TypeString, "Name", default = "")
self.param("lg", self.TypeLayer, "Layer for guideline", default = pya.LayerInfo(1, 0))
self.param("lw", self.TypeLayer, "Layer for wafer", default = pya.LayerInfo(1, 0))
self.param("le", self.TypeLayer, "Layer for edge exclusion", default = pya.LayerInfo(1, 0))
wafer_size_option = self.param( "wafer_size_option", self.TypeString, "Wafer Size", default=2)
wafer_size_option.add_choice(" 2 inch", 0)
wafer_size_option.add_choice(" 4 inch", 1)
wafer_size_option.add_choice(" 6 inch", 2)
wafer_size_option.add_choice(" 8 inch", 3)
wafer_size_option.add_choice("12 inch", 4)
self.param("edge_exclude", self.TypeDouble, "Edge exclusion", default = 3.0, unit = "mm")
self.param("circle_dots", self.TypeInt, "Points per circle", default = 128)
self.param("place_chip", self.TypeBoolean, "Place Chip", default = False)
self.param("lc", self.TypeLayer, "Layer for good chips", default = pya.LayerInfo(1, 0))
self.param("lcp", self.TypeLayer, "Layer for partial chips", default = pya.LayerInfo(1, 0))
self.param("chip_w", self.TypeDouble, "Chip width", default = 5000, unit = "um")
self.param("chip_h", self.TypeDouble, "Chip height", default = 5000, unit = "um")
self.param("scribe_w", self.TypeDouble, "Scribeline width", default = 250, unit = "um")
self.param("scribe_h", self.TypeDouble, "Scribeline height", default = 250, unit = "um")
self.param("chip_offset_x", self.TypeDouble, "Chip offset X", default = 0, unit = "um")
self.param("chip_offset_y", self.TypeDouble, "Chip offset Y", default = 0, unit = "um")
def display_text_impl(self):
class_name = self.__class__.__name__
custom_name = (self.name + "--" if self.name else "")
wafer_size = {0:" 2 inch", 1:" 4 inch", 2:" 6 inch", 3:" 8 inch", 4:"12 inch"}[self.wafer_size_option]
return "%s%s(%s, EBR: %.2f mm)" % (custom_name, class_name, wafer_size, self.edge_exclude)
def coerce_parameters_impl(self):
unit = self.layout.dbu
mm = 1000
self.wafer_diameter = 0
self.primary_flat = 0
self.primary_notch = 0
if self.wafer_size_option == 0: #2 unch
self.wafer_diameter = 50.80 * mm
self.primary_flat = 15.88 * mm
if self.wafer_size_option == 1: #4 unch
self.wafer_diameter = 100.0 * mm
self.primary_flat = 32.50 * mm
if self.wafer_size_option == 2: #6 unch
self.wafer_diameter = 150.0 * mm
self.primary_flat = 57.50 * mm
if self.wafer_size_option == 3: #8 unch
self.wafer_diameter = 200.0 * mm
self.primary_notch = [3.0 * mm, 1.0 * mm, 0.5 * mm] # w&h, rounding, y-offset
if self.wafer_size_option == 4: #12 unch
self.wafer_diameter = 300.0 * mm
self.primary_notch = [3.0 * mm, 1.0 * mm, 0.5 * mm] # w&h, rounding, y-offset
self.circle_dots = 32 if self.circle_dots <= 32 else self.circle_dots
self.edge_exclude_mm = 0 if self.edge_exclude <= 0 else self.edge_exclude * mm / unit
def can_create_from_shape_impl(self):
return self.shape.is_box() or self.shape.is_polygon() or self.shape.is_path()
def parameters_from_shape_impl(self):
self.l = self.layout.get_info(self.layer)
def transformation_from_shape_impl(self):
return pya.Trans(self.shape.bbox().center())
def produce_impl(self):
unit = self.layout.dbu
self.wafer_radius = self.wafer_diameter/2
wafer_circle_dots = Toolkit.circle(0, 0, self.wafer_radius, p = self.circle_dots, unit = unit)
circle_poly_reg = pya.Region(pya.Polygon(wafer_circle_dots))
circle_path_reg = pya.Region(pya.Path(wafer_circle_dots, 1))
flat_notch_reg = pya.Region()
if self.primary_flat != 0:
h = 2*(self.wafer_radius - (self.wafer_radius ** 2 - (self.primary_flat/2) ** 2 ) ** (0.5))
flat_notch_reg = pya.Region(pya.Polygon(Toolkit.rect(0, -self.wafer_radius, self.wafer_diameter, h, unit = unit)))
if self.primary_notch != 0:
width, rounding, offset = self.primary_notch
pts = Toolkit.rect(0, 0, width, width, self.layout.dbu)
rect_poly = pya.Polygon(pts).round_corners(rounding, rounding/unit, self.circle_dots)
rect_poly.transform(pya.DCplxTrans (1.0, 45, False, 0, (-self.wafer_radius-offset)/unit))
flat_notch_reg = pya.Region(rect_poly)
wafer_reg = circle_poly_reg - flat_notch_reg
ebr_reg = wafer_reg.sized(-self.edge_exclude_mm)
self.cell.shapes(self.lg_layer).insert(circle_path_reg)
self.cell.shapes(self.lw_layer).insert(wafer_reg)
self.cell.shapes(self.le_layer).insert(ebr_reg)
if self.place_chip and (self.chip_w * self.chip_h > 0):
pitch_x = self.chip_w + self.scribe_w
pitch_y = self.chip_h + self.scribe_h
offset_x = self.chip_offset_x % pitch_x
offset_y = self.chip_offset_y % pitch_y
chip_column = (int(self.wafer_radius/pitch_x) + 2) * 2
chip_row = (int(self.wafer_radius/pitch_y) + 2) * 2
origin_x = -1 * (chip_column ) / 2 * pitch_x
origin_y = -1 * (chip_row ) / 2 * pitch_y
chip_array = []
for c in range(chip_column):
for r in range(chip_row):
chip_x = origin_x + (c * pitch_x) + offset_x
chip_y = origin_y + (r * pitch_y) + offset_y
chip_array.append(pya.Polygon(Toolkit.rect(chip_x, chip_y, self.chip_w, self.chip_h, self.layout.dbu)))
chip_reg = pya.Region()
chip_part_reg = pya.Region()
chip_reg.merged_semantics = False
chip_part_reg.merged_semantics = False
ebr_reg.merged_semantics = False
chip_reg.insert(chip_array)
chip_good_reg = chip_reg.inside(ebr_reg)
for rect in chip_reg.not_inside(ebr_reg):
chip_part_reg.insert(ebr_reg & rect)
self.cell.shapes(self.lc_layer).insert(chip_good_reg)
self.cell.shapes(self.lcp_layer).insert(chip_part_reg)
chip_count_txt = "chip: %d" % (chip_good_reg.count())
chip_count_trans = pya.DTrans (-self.wafer_radius/unit + 200/unit, -self.wafer_radius/unit + 200/unit)
self.cell.shapes(self.lc_layer).insert(pya.Text(chip_count_txt, chip_count_trans))
class gdsToolkit(pya.Library):
def __init__(self):
self.description = "Toolkit"
self.layout().register_pcell("Wafer", Wafer())
self.register("Toolkit")
gdsToolkit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment