mirror of https://github.com/KLayout/klayout.git
Via PCell samples
This commit is contained in:
parent
91946165fd
commit
e2e4c1a827
|
|
@ -19,5 +19,6 @@
|
|||
<file alias="pcell_python.lym">macro_templates/pcell_python.lym</file>
|
||||
<file alias="pcell_sample_python.lym">macro_templates/pcell_sample_python.lym</file>
|
||||
<file alias="via_pcell_sample_python.lym">macro_templates/via_pcell_sample_python.lym</file>
|
||||
<file alias="via_pcell_sample.lym">macro_templates/via_pcell_sample.lym</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pcell.lym
|
|||
# Samples
|
||||
:Samples;;
|
||||
pcell_sample.lym
|
||||
via_pcell_sample.lym
|
||||
qt_designer.lym
|
||||
qt_dialog.lym
|
||||
qt_server.lym
|
||||
|
|
|
|||
|
|
@ -0,0 +1,277 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>Via PCell sample (Ruby)\nThis sample provides a via PCell with two via types</description>
|
||||
<format>general</format>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<category>macros</category>
|
||||
<interpreter>ruby</interpreter>
|
||||
<text>import pya
|
||||
import math
|
||||
|
||||
"""
|
||||
Sample via PCell
|
||||
|
||||
This sample PCell implements a library called "MyViaLib" with a single PCell that
|
||||
provides two vias for a hypothetical technology with these layers:
|
||||
|
||||
1/0 Metal1
|
||||
2/0 Via1
|
||||
3/0 Metal2
|
||||
4/0 Via2
|
||||
5/0 Metal3
|
||||
|
||||
The sample demonstrates how to equip a PCell with the necessary declarations,
|
||||
so it can supply vias for the wire (path) tool.
|
||||
|
||||
It implements simple rectangular via arrays made from squares with a fixed size,
|
||||
pitch and enclosure.
|
||||
|
||||
NOTE: after changing the code, the macro needs to be rerun to install the new
|
||||
implementation. The macro is also set to "auto run" to install the PCell
|
||||
when KLayout is run.
|
||||
"""
|
||||
|
||||
class ViaPCell(pya.PCellDeclarationHelper):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
"""
|
||||
Constructor: provides the PCell parameter definitions
|
||||
"""
|
||||
|
||||
super(ViaPCell, self).__init__()
|
||||
|
||||
# Every via PCell should declare these parameters:
|
||||
#
|
||||
# via: the name of the via as declared in the via types
|
||||
# w_bottom: the width of the bottom box in micrometers
|
||||
# h_bottom: the height of the bottom box in micrometers
|
||||
# w_top: the width of the top box in micrometers
|
||||
# h_top: the width of the top box in micrometers
|
||||
#
|
||||
# w_bottom etc. can be zero, indicating that the via
|
||||
# does not have a specific extension in this layer.
|
||||
# The PCell may chose a dimension in that case.
|
||||
|
||||
self.param("via", self.TypeString, "Via type", hidden = False)
|
||||
self.param("w_bottom", self.TypeDouble, "Bottom width", hidden = False, default = 0.0)
|
||||
self.param("h_bottom", self.TypeDouble, "Bottom height", hidden = False, default = 0.0)
|
||||
self.param("w_top", self.TypeDouble, "Top width", hidden = False, default = 0.0)
|
||||
self.param("h_top", self.TypeDouble, "Top height", hidden = False, default = 0.0)
|
||||
|
||||
# Optional additional parameters: here we allow to override
|
||||
# the computed array dimension by setting these parameters
|
||||
# to non-zero.
|
||||
|
||||
self.param("nx", self.TypeInt, "nx", default = 0)
|
||||
self.param("ny", self.TypeInt, "ny", default = 0)
|
||||
|
||||
# Build a list of supported vias
|
||||
|
||||
self.via_type_list = []
|
||||
|
||||
# Via1
|
||||
vt = pya.ViaType("V1", "Via1 (0.2x0.2)")
|
||||
vt.wbmin = 0.4
|
||||
vt.hbmin = 0.4
|
||||
vt.wtmin = 0.5
|
||||
vt.htmin = 0.5
|
||||
vt.bottom = pya.LayerInfo(1, 0)
|
||||
vt.cut = pya.LayerInfo(2, 0)
|
||||
vt.top = pya.LayerInfo(3, 0)
|
||||
vt.bottom_grid = 0.01
|
||||
vt.top_grid = 0.01
|
||||
|
||||
# foreign attributes (not used by pya, but handy for
|
||||
# internal use):
|
||||
vt.enc_bottom = 0.1
|
||||
vt.enc_top = 0.15
|
||||
vt.vwidth = 0.2
|
||||
vt.vspace = 0.2
|
||||
|
||||
self.via_type_list.append(vt)
|
||||
|
||||
# Via2
|
||||
vt = pya.ViaType("V2", "Via2 (0.3x0.3)")
|
||||
vt.wbmin = 0.5
|
||||
vt.hbmin = 0.5
|
||||
vt.wtmin = 0.5
|
||||
vt.htmin = 0.5
|
||||
vt.bottom = pya.LayerInfo(3, 0)
|
||||
vt.cut = pya.LayerInfo(4, 0)
|
||||
vt.top = pya.LayerInfo(5, 0)
|
||||
vt.bottom_grid = 0.01
|
||||
vt.top_grid = 0.01
|
||||
|
||||
# foreign attributes (not used by pya, but handy for
|
||||
# internal use):
|
||||
vt.enc_bottom = 0.1
|
||||
vt.enc_top = 0.1
|
||||
vt.vwidth = 0.3
|
||||
vt.vspace = 0.2
|
||||
|
||||
self.via_type_list.append(vt)
|
||||
|
||||
def via_types(self):
|
||||
"""
|
||||
Implements the "via_types" method from the PCellDeclaration
|
||||
interface: delivers the vias supported by this PCell.
|
||||
"""
|
||||
return self.via_type_list
|
||||
|
||||
def via_type(self):
|
||||
"""
|
||||
Returns the via with the name given by the "via"
|
||||
PCell argument
|
||||
"""
|
||||
for vt in self.via_type_list:
|
||||
if vt.name == self.via:
|
||||
return vt
|
||||
return None
|
||||
|
||||
def display_text_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
return "Via(" + self.via + ")"
|
||||
|
||||
def coerce_parameters_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
pass
|
||||
|
||||
def can_create_from_shape_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
return false
|
||||
|
||||
def parameters_from_shape_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
pass
|
||||
|
||||
def transformation_from_shape_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
return pya.Trans()
|
||||
|
||||
def min_dim(self, a, b, da, db):
|
||||
"""
|
||||
A helper function to compute the minimum
|
||||
width or height less the enclosure
|
||||
(a = w/h_bottom, b = w/h_top,
|
||||
da/b = enclosure for a/b)
|
||||
"""
|
||||
if a < 1e-10 and b < 1e-10:
|
||||
return 0.0
|
||||
elif a < 1e-10:
|
||||
return b - 2.0 * max(da, db)
|
||||
elif b < 1e-10:
|
||||
return a - 2.0 * max(da, db)
|
||||
else:
|
||||
return min(a - 2.0 * da, b - 2.0 * db)
|
||||
|
||||
def getnxy(self, vt):
|
||||
|
||||
"""
|
||||
Computes the nx and ny as mandated by the widths and
|
||||
heights
|
||||
|
||||
w/h_top/bottom can be zero, indicating no specific
|
||||
dimension is requested. The implementation can choose
|
||||
what to do in this case. It can also decide to provide
|
||||
largher vias than given by w_ or h_ or favor square vias
|
||||
over rectangular ones.
|
||||
"""
|
||||
|
||||
mode = 2 # 1: maximum, 2: minimum
|
||||
|
||||
if mode == 1:
|
||||
|
||||
# This implementation uses the maximum size requested
|
||||
# by either top or bottom:
|
||||
|
||||
w = max(max(self.w_bottom, vt.wbmin) - 2 * vt.enc_bottom,
|
||||
max(self.w_top, vt.wtmin) - 2 * vt.enc_top)
|
||||
|
||||
h = max(max(self.h_bottom, vt.hbmin) - 2 * vt.enc_bottom,
|
||||
max(self.h_top, vt.htmin) - 2 * vt.enc_top)
|
||||
|
||||
elif mode == 2:
|
||||
|
||||
# This implementation delivers the minimum via, ignoring
|
||||
# zero dimensions:
|
||||
|
||||
w = self.min_dim(self.w_bottom, self.w_top, vt.enc_bottom, vt.enc_top)
|
||||
h = self.min_dim(self.h_bottom, self.h_top, vt.enc_bottom, vt.enc_top)
|
||||
|
||||
# parameter nx or ny override computed value if > 0
|
||||
|
||||
if self.nx > 0:
|
||||
nx = self.nx
|
||||
else:
|
||||
nx = max(1, int(math.floor((w + vt.vspace) / (vt.vwidth + vt.vspace) + 1e-10)))
|
||||
|
||||
if self.ny > 0:
|
||||
ny = self.ny
|
||||
else:
|
||||
ny = max(1, int(math.floor((h + vt.vspace) / (vt.vwidth + vt.vspace) + 1e-10)))
|
||||
|
||||
return (nx, ny)
|
||||
|
||||
def produce_impl(self):
|
||||
|
||||
"""
|
||||
Implementation of the PCell interface: generates the layouts
|
||||
"""
|
||||
|
||||
vt = self.via_type()
|
||||
if vt is None:
|
||||
return
|
||||
|
||||
(nx, ny) = self.getnxy(vt)
|
||||
|
||||
wcut = nx * vt.vwidth + (nx - 1) * vt.vspace
|
||||
hcut = ny * vt.vwidth + (ny - 1) * vt.vspace
|
||||
wbottom = max(max(self.w_bottom, vt.wbmin), vt.enc_bottom * 2.0 + wcut)
|
||||
hbottom = max(max(self.h_bottom, vt.hbmin), vt.enc_bottom * 2.0 + hcut)
|
||||
wtop = max(max(self.w_top, vt.wtmin), vt.enc_top * 2.0 + wcut)
|
||||
htop = max(max(self.h_top, vt.htmin), vt.enc_top * 2.0 + hcut)
|
||||
|
||||
lbottom = self.layout.layer(vt.bottom)
|
||||
ltop = self.layout.layer(vt.top)
|
||||
lcut = self.layout.layer(vt.cut)
|
||||
|
||||
self.cell.shapes(lbottom).insert(pya.DBox(wbottom, hbottom))
|
||||
self.cell.shapes(ltop).insert(pya.DBox(wtop, htop))
|
||||
|
||||
scut = self.cell.shapes(lcut)
|
||||
|
||||
for ix in range(0, nx):
|
||||
x = (ix - 0.5 * (nx - 1)) * (vt.vwidth + vt.vspace)
|
||||
for iy in range(0, ny):
|
||||
y = (iy - 0.5 * (ny - 1)) * (vt.vwidth + vt.vspace)
|
||||
scut.insert(pya.DBox(vt.vwidth, vt.vwidth).moved(x, y))
|
||||
|
||||
|
||||
class MyViaLib(pya.Library):
|
||||
|
||||
"""
|
||||
A declaration for a test library
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.description = "Via Test Library"
|
||||
self.layout().register_pcell("Via", ViaPCell())
|
||||
self.register("MyViaLib")
|
||||
|
||||
# instantiates the test library
|
||||
MyViaLib()
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>Via PCell sample (Python)\nThis sample provides a via PCell with two via types</description>
|
||||
<format>general</format>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<category>pymacros</category>
|
||||
<interpreter>python</interpreter>
|
||||
<text>import pya
|
||||
import math
|
||||
|
||||
"""
|
||||
Sample via PCell
|
||||
|
||||
This sample PCell implements a library called "MyViaLib" with a single PCell that
|
||||
provides two vias for a hypothetical technology with these layers:
|
||||
|
||||
1/0 Metal1
|
||||
2/0 Via1
|
||||
3/0 Metal2
|
||||
4/0 Via2
|
||||
5/0 Metal3
|
||||
|
||||
The sample demonstrates how to equip a PCell with the necessary declarations,
|
||||
so it can supply vias for the wire (path) tool.
|
||||
|
||||
It implements simple rectangular via arrays made from squares with a fixed size,
|
||||
pitch and enclosure.
|
||||
|
||||
NOTE: after changing the code, the macro needs to be rerun to install the new
|
||||
implementation. The macro is also set to "auto run" to install the PCell
|
||||
when KLayout is run.
|
||||
"""
|
||||
|
||||
class ViaPCell(pya.PCellDeclarationHelper):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
"""
|
||||
Constructor: provides the PCell parameter definitions
|
||||
"""
|
||||
|
||||
super(ViaPCell, self).__init__()
|
||||
|
||||
# Every via PCell should declare these parameters:
|
||||
#
|
||||
# via: the name of the via as declared in the via types
|
||||
# w_bottom: the width of the bottom box in micrometers
|
||||
# h_bottom: the height of the bottom box in micrometers
|
||||
# w_top: the width of the top box in micrometers
|
||||
# h_top: the width of the top box in micrometers
|
||||
#
|
||||
# w_bottom etc. can be zero, indicating that the via
|
||||
# does not have a specific extension in this layer.
|
||||
# The PCell may chose a dimension in that case.
|
||||
|
||||
self.param("via", self.TypeString, "Via type", hidden = False)
|
||||
self.param("w_bottom", self.TypeDouble, "Bottom width", hidden = False, default = 0.0)
|
||||
self.param("h_bottom", self.TypeDouble, "Bottom height", hidden = False, default = 0.0)
|
||||
self.param("w_top", self.TypeDouble, "Top width", hidden = False, default = 0.0)
|
||||
self.param("h_top", self.TypeDouble, "Top height", hidden = False, default = 0.0)
|
||||
|
||||
# Optional additional parameters: here we allow to override
|
||||
# the computed array dimension by setting these parameters
|
||||
# to non-zero.
|
||||
|
||||
self.param("nx", self.TypeInt, "nx", default = 0)
|
||||
self.param("ny", self.TypeInt, "ny", default = 0)
|
||||
|
||||
# Build a list of supported vias
|
||||
|
||||
self.via_type_list = []
|
||||
|
||||
# Via1
|
||||
vt = pya.ViaType("V1", "Via1 (0.2x0.2)")
|
||||
vt.wbmin = 0.4
|
||||
vt.hbmin = 0.4
|
||||
vt.wtmin = 0.5
|
||||
vt.htmin = 0.5
|
||||
vt.bottom = pya.LayerInfo(1, 0)
|
||||
vt.cut = pya.LayerInfo(2, 0)
|
||||
vt.top = pya.LayerInfo(3, 0)
|
||||
vt.bottom_grid = 0.01
|
||||
vt.top_grid = 0.01
|
||||
|
||||
# foreign attributes (not used by pya, but handy for
|
||||
# internal use):
|
||||
vt.enc_bottom = 0.1
|
||||
vt.enc_top = 0.15
|
||||
vt.vwidth = 0.2
|
||||
vt.vspace = 0.2
|
||||
|
||||
self.via_type_list.append(vt)
|
||||
|
||||
# Via2
|
||||
vt = pya.ViaType("V2", "Via2 (0.3x0.3)")
|
||||
vt.wbmin = 0.5
|
||||
vt.hbmin = 0.5
|
||||
vt.wtmin = 0.5
|
||||
vt.htmin = 0.5
|
||||
vt.bottom = pya.LayerInfo(3, 0)
|
||||
vt.cut = pya.LayerInfo(4, 0)
|
||||
vt.top = pya.LayerInfo(5, 0)
|
||||
vt.bottom_grid = 0.01
|
||||
vt.top_grid = 0.01
|
||||
|
||||
# foreign attributes (not used by pya, but handy for
|
||||
# internal use):
|
||||
vt.enc_bottom = 0.1
|
||||
vt.enc_top = 0.1
|
||||
vt.vwidth = 0.3
|
||||
vt.vspace = 0.2
|
||||
|
||||
self.via_type_list.append(vt)
|
||||
|
||||
def via_types(self):
|
||||
"""
|
||||
Implements the "via_types" method from the PCellDeclaration
|
||||
interface: delivers the vias supported by this PCell.
|
||||
"""
|
||||
return self.via_type_list
|
||||
|
||||
def via_type(self):
|
||||
"""
|
||||
Returns the via with the name given by the "via"
|
||||
PCell argument
|
||||
"""
|
||||
for vt in self.via_type_list:
|
||||
if vt.name == self.via:
|
||||
return vt
|
||||
return None
|
||||
|
||||
def display_text_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
return "Via(" + self.via + ")"
|
||||
|
||||
def coerce_parameters_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
pass
|
||||
|
||||
def can_create_from_shape_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
return False
|
||||
|
||||
def parameters_from_shape_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
pass
|
||||
|
||||
def transformation_from_shape_impl(self):
|
||||
"""
|
||||
PCell interface implementation
|
||||
"""
|
||||
return pya.Trans()
|
||||
|
||||
def min_dim(self, a, b, da, db):
|
||||
"""
|
||||
A helper function to compute the minimum
|
||||
width or height less the enclosure
|
||||
(a = w/h_bottom, b = w/h_top,
|
||||
da/b = enclosure for a/b)
|
||||
"""
|
||||
if a < 1e-10 and b < 1e-10:
|
||||
return 0.0
|
||||
elif a < 1e-10:
|
||||
return b - 2.0 * max(da, db)
|
||||
elif b < 1e-10:
|
||||
return a - 2.0 * max(da, db)
|
||||
else:
|
||||
return min(a - 2.0 * da, b - 2.0 * db)
|
||||
|
||||
def getnxy(self, vt):
|
||||
|
||||
"""
|
||||
Computes the nx and ny as mandated by the widths and
|
||||
heights
|
||||
|
||||
w/h_top/bottom can be zero, indicating no specific
|
||||
dimension is requested. The implementation can choose
|
||||
what to do in this case. It can also decide to provide
|
||||
largher vias than given by w_ or h_ or favor square vias
|
||||
over rectangular ones.
|
||||
"""
|
||||
|
||||
mode = 2 # 1: maximum, 2: minimum
|
||||
|
||||
if mode == 1:
|
||||
|
||||
# This implementation uses the maximum size requested
|
||||
# by either top or bottom:
|
||||
|
||||
w = max(max(self.w_bottom, vt.wbmin) - 2 * vt.enc_bottom,
|
||||
max(self.w_top, vt.wtmin) - 2 * vt.enc_top)
|
||||
|
||||
h = max(max(self.h_bottom, vt.hbmin) - 2 * vt.enc_bottom,
|
||||
max(self.h_top, vt.htmin) - 2 * vt.enc_top)
|
||||
|
||||
elif mode == 2:
|
||||
|
||||
# This implementation delivers the minimum via, ignoring
|
||||
# zero dimensions:
|
||||
|
||||
w = self.min_dim(self.w_bottom, self.w_top, vt.enc_bottom, vt.enc_top)
|
||||
h = self.min_dim(self.h_bottom, self.h_top, vt.enc_bottom, vt.enc_top)
|
||||
|
||||
# parameter nx or ny override computed value if > 0
|
||||
|
||||
if self.nx > 0:
|
||||
nx = self.nx
|
||||
else:
|
||||
nx = max(1, int(math.floor((w + vt.vspace) / (vt.vwidth + vt.vspace) + 1e-10)))
|
||||
|
||||
if self.ny > 0:
|
||||
ny = self.ny
|
||||
else:
|
||||
ny = max(1, int(math.floor((h + vt.vspace) / (vt.vwidth + vt.vspace) + 1e-10)))
|
||||
|
||||
return (nx, ny)
|
||||
|
||||
def produce_impl(self):
|
||||
|
||||
"""
|
||||
Implementation of the PCell interface: generates the layouts
|
||||
"""
|
||||
|
||||
vt = self.via_type()
|
||||
if vt is None:
|
||||
return
|
||||
|
||||
(nx, ny) = self.getnxy(vt)
|
||||
|
||||
wcut = nx * vt.vwidth + (nx - 1) * vt.vspace
|
||||
hcut = ny * vt.vwidth + (ny - 1) * vt.vspace
|
||||
wbottom = max(max(self.w_bottom, vt.wbmin), vt.enc_bottom * 2.0 + wcut)
|
||||
hbottom = max(max(self.h_bottom, vt.hbmin), vt.enc_bottom * 2.0 + hcut)
|
||||
wtop = max(max(self.w_top, vt.wtmin), vt.enc_top * 2.0 + wcut)
|
||||
htop = max(max(self.h_top, vt.htmin), vt.enc_top * 2.0 + hcut)
|
||||
|
||||
lbottom = self.layout.layer(vt.bottom)
|
||||
ltop = self.layout.layer(vt.top)
|
||||
lcut = self.layout.layer(vt.cut)
|
||||
|
||||
self.cell.shapes(lbottom).insert(pya.DBox(wbottom, hbottom))
|
||||
self.cell.shapes(ltop).insert(pya.DBox(wtop, htop))
|
||||
|
||||
scut = self.cell.shapes(lcut)
|
||||
|
||||
for ix in range(0, nx):
|
||||
x = (ix - 0.5 * (nx - 1)) * (vt.vwidth + vt.vspace)
|
||||
for iy in range(0, ny):
|
||||
y = (iy - 0.5 * (ny - 1)) * (vt.vwidth + vt.vspace)
|
||||
scut.insert(pya.DBox(vt.vwidth, vt.vwidth).moved(x, y))
|
||||
|
||||
|
||||
class MyViaLib(pya.Library):
|
||||
|
||||
"""
|
||||
A declaration for a test library
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.description = "Via Test Library"
|
||||
self.layout().register_pcell("Via", ViaPCell())
|
||||
self.register("MyViaLib")
|
||||
|
||||
# instantiates the test library
|
||||
MyViaLib()
|
||||
</text>
|
||||
</klayout-macro>
|
||||
Loading…
Reference in New Issue