from math import ceil
import gdsfactory as gf
from gdsfactory.typings import Float2, LayerSpec
[docs]
@gf.cell
def p_p_poly(
p_poly_width: float = 0.35,
p_poly_length: float = 0.5,
poly_res_layer: LayerSpec = (66, 13),
poly_layer: LayerSpec = (66, 20),
psdm_layer: LayerSpec = (94, 20),
sdm_enclosure: Float2 = (0.125, 0.125),
contact_size: Float2 = (0.17, 0.17),
contact_spacing: Float2 = (0.17, 0.17),
licon_slots_size: Float2 = (0.19, 2),
licon_slots_spacing: Float2 = (0.51, 0.51),
contact_layer: LayerSpec = (66, 44),
contact_enclosure: Float2 = (0.06, 0.06),
li_layer: LayerSpec = (67, 20),
li_enclosure: float = 0.08,
mcon_layer: LayerSpec = (67, 44),
mcon_enclosure: Float2 = (0.09, 0.09),
m1_layer: LayerSpec = (68, 20),
rpm_layer: LayerSpec = (86, 20),
rpm_min_width: float = 1.27,
rpm_enclosure: Float2 = (0.2, 0.2),
npc_layer: LayerSpec = (95, 20),
npc_enclosure: Float2 = (0.095, 0.095),
) -> gf.Component:
"""Return p+ poly resistor with sheet resistance of 300 ohms/square.
Args:
p_poly_width: in um.
p_poly_length: in um.
poly_res_layer: layer of the p+ poly resistor.
poly_layer: layer of the polysilicon.
psdm_layer: layer of the p+ implants.
sdm_enclosure: enclosure of the p+ implants.
contact_size: size of the contact.
contact_spacing: spacing between the contacts.
licon_slots_size: size of the licon slots.
licon_slots_spacing: spacing between the licon slots.
contact_layer: layer of the contacts.
contact_enclosure: enclosure of the contacts.
li_layer: layer of the local interconnects.
li_enclosure: enclosure of the local interconnects.
mcon_layer: layer of the mcon.
mcon_enclosure: enclosure of the mcon.
m1_layer: layer of the m1.
rpm_layer: layer of the poly resistor implant.
rpm_min_width: minimum width of the poly resistor implant.
rpm_enclosure: enclosure of the poly resistor implant.
npc_layer: layer of the nitride poly cut.
npc_enclosure: enclosure of the nitride poly cut.
.. plot::
:include-source:
import sky130
c = sky130.pcells.p_p_poly(p_poly_width= 5.73, p_poly_length=2)
c.plot()
"""
c = gf.Component()
# generate poly res R1
rect_r = gf.components.rectangle(
size=(p_poly_width, p_poly_length), layer=poly_res_layer
)
c.add_ref(rect_r)
# generate polysilicon R0
p_length = licon_slots_size[1] + 2 * contact_enclosure[1]
rect_p = gf.components.rectangle(
size=(p_poly_width, p_poly_length + 2 * p_length), layer=poly_layer
)
R_0 = c.add_ref(rect_p)
R_0.dmovey(-p_length)
# generate contacts (licon )
rect_lc = gf.components.rectangle(size=licon_slots_size, layer=contact_layer)
# nr = ceil((p_length / (licon_slots_size[1]+licon_slots_spacing[1])))
# if (p_length- nr*licon_slots_size[1] - (nr-1)*licon_slots_spacing[1])/2 < contact_enclosure[1] :
# nr-=1
nc = ceil(p_poly_width / (licon_slots_size[0] + licon_slots_spacing[0]))
if (
p_poly_width - nc * licon_slots_size[0] - (nc - 1) * licon_slots_spacing[0]
) / 2 < contact_enclosure[0]:
nc -= 1
lic_sp = (
licon_slots_size[0] + licon_slots_spacing[0],
licon_slots_size[1] + licon_slots_spacing[1],
)
for i in range(2):
cont_arr = c.add_ref(rect_lc, rows=1, columns=nc, spacing=lic_sp)
cont_arr.dmovex(
(
p_poly_width
- nc * licon_slots_size[0]
- (nc - 1) * licon_slots_spacing[0]
)
/ 2
)
cont_arr.dmovey(
i * (p_poly_length + (p_length - licon_slots_size[1]) / 2)
- (1 - i) * (licon_slots_size[1] + (p_length - licon_slots_size[1]) / 2)
)
# generate li (local interconnects) and m1
rect_layer = [m1_layer, li_layer]
for i in range(2):
rect_li_m1 = gf.components.rectangle(
size=(
p_poly_width + 2 * (1 - i) * (mcon_enclosure[0] - li_enclosure),
licon_slots_size[1]
+ 2 * i * li_enclosure
+ 2 * (1 - i) * mcon_enclosure[1],
),
layer=rect_layer[i],
)
li_m1 = c.add_ref(
rect_li_m1,
rows=2,
columns=1,
spacing=(
0,
p_poly_length
+ 2 * contact_enclosure[1]
+ licon_slots_size[1]
- (1 - i) * (mcon_enclosure[1] - li_enclosure),
),
)
li_m1.dmovey(
-licon_slots_size[1]
- contact_enclosure[1]
- i * li_enclosure
- (1 - i) * mcon_enclosure[1]
)
li_m1.dmovex((1 - i) * (-mcon_enclosure[0] + li_enclosure))
# generate mcon
rect_mc = gf.components.rectangle(size=contact_size, layer=mcon_layer)
nr_m = ceil(
(rect_li_m1.dymax - rect_li_m1.dymin) / (contact_size[1] + contact_spacing[1])
)
if (
rect_li_m1.dymax
- rect_li_m1.dymin
- nr_m * contact_size[1]
- (nr_m - 1) * contact_spacing[1]
) / 2 < contact_enclosure[1]:
nr_m -= 1
nc_m = ceil(
(rect_li_m1.dxmax - rect_li_m1.dxmin) / (contact_size[0] + contact_spacing[0])
)
if (
rect_li_m1.dxmax
- rect_li_m1.dxmin
- nc_m * contact_size[0]
- (nc_m - 1) * contact_spacing[0]
) < contact_enclosure[0]:
nc_m -= 1
con_sp = (
contact_size[0] + contact_spacing[0],
contact_size[1] + contact_spacing[1],
)
for i in range(2):
mcon_arr = c.add_ref(rect_mc, rows=nr_m, columns=nc_m, spacing=con_sp)
# mcon_arr.dmovex((p_poly_width - nc*licon_slots_size[0] - (nc-1)*licon_slots_spacing[0] - 2*li_enclosure )/2)
mcon_arr.dmovey(
(1 - i) * (-licon_slots_size[1] - contact_enclosure[1] - li_enclosure)
+ i * (p_poly_length)
)
mcon_arr.dmovex(
(
rect_li_m1.dxmax
- rect_li_m1.dxmin
- nc_m * contact_size[0]
- (nc_m - 1) * contact_spacing[0]
)
/ 2
)
mcon_arr.dmovey(
(
rect_li_m1.dymax
- rect_li_m1.dymin
- nr_m * contact_size[1]
- (nr_m - 1) * contact_spacing[1]
)
/ 2
)
# generate npc (nitride poly cut)
rect_npc = gf.components.rectangle(
size=(
p_poly_width + 2 * npc_enclosure[0],
p_poly_length + 2 * p_length + 2 * npc_enclosure[1],
),
layer=npc_layer,
)
npc = c.add_ref(rect_npc)
npc.connect(
"e1", R_0.ports["e1"], allow_layer_mismatch=True, allow_width_mismatch=True
)
npc.dmovex(p_poly_width + npc_enclosure[0])
# generate rpm (poly resistor implant)
if p_poly_width <= rpm_min_width:
rpm_width = rpm_min_width + 2 * rpm_enclosure[0]
else:
rpm_width = p_poly_width + 2 * rpm_enclosure[0]
rpm_length = p_poly_length + 2 * p_length + 2 * rpm_enclosure[1]
rect_rpm = gf.components.rectangle(size=(rpm_width, rpm_length), layer=rpm_layer)
rpm = c.add_ref(rect_rpm)
rpm.connect(
"e1", R_0.ports["e1"], allow_layer_mismatch=True, allow_width_mismatch=True
)
rpm.dmovex(p_poly_width + ((rpm_width - p_poly_width) / 2))
# generate p+ implants
rect_psdm = gf.components.rectangle(
size=(rpm_width + 2 * sdm_enclosure[0], rpm_length + 2 * sdm_enclosure[1]),
layer=psdm_layer,
)
psdm = c.add_ref(rect_psdm)
psdm.connect(
"e1", rpm.ports["e3"], allow_layer_mismatch=True, allow_width_mismatch=True
)
psdm.dmovex(rpm_width + sdm_enclosure[0])
return c
if __name__ == "__main__":
# c = p_p_poly(p_poly_width= 5.73, p_poly_length=2)
c = p_p_poly()
c.show()