Skip to content

Commit

Permalink
Merge pull request #2 from mabrains/device_gen
Browse files Browse the repository at this point in the history
Device gen
  • Loading branch information
RehabSayed-G authored Aug 29, 2022
2 parents 8bb0629 + ffa288c commit d67acf7
Show file tree
Hide file tree
Showing 5 changed files with 1,234 additions and 0 deletions.
87 changes: 87 additions & 0 deletions sky130/device_generators/mimcap_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from math import ceil, floor
import gdsfactory as gf
import numpy as np
from gdsfactory.types import Float2, LayerSpec

@gf.cell
def mimcap_1(
m3_layer : LayerSpec = (70,20),
via3_size : float = (0.2,0.2),
via3_layer : LayerSpec = (70,44),
via3_enclosure : Float2 = (0.09,0.09),
via3_spacing : Float2 = (0.2,0.2),#(0.2,0.35),
m4_spacing : float = 0.4,
m4_r_length : float = 0.4,
m4_layer : LayerSpec = (71,20),
m4_length : float = 1.2,
m4_width : float = 1.2,
capm_layer : LayerSpec = (89,44),
m4_enclosure : float = (0.14,0.14),
capm_enclosure : float = (0.5,0.5)




) -> gf.Component:

"""Return mimcap_1
mim cap between metal 3 and 4
"""
c = gf.Component()

en = (0.02,0.04) # for enclosure
#generating m3 plate
m3_length = capm_enclosure[0] + 2*m4_enclosure[0] + m4_length + m4_spacing + m4_r_length +en[0]
m3_width = 2*capm_enclosure[1] + 2*m4_enclosure[1] + m4_width + en[1]
rect_m3 = gf.components.rectangle(size= (m3_length,m3_width) , layer= m3_layer)
m3 = c.add_ref(rect_m3)

# generate m4 plates

rect_m4_r = gf.components.rectangle(size= (m4_r_length,m3_width- en[1] ), layer= m4_layer)
m4_r = c.add_ref(rect_m4_r)
m4_r.movex (m3_length - m4_r_length- en[0]/2)
m4_r.movey (en[1]/2)

rect_m4_l = gf.components.rectangle(size= (m4_length,m4_width), layer= m4_layer)
m4_l = c.add_ref(rect_m4_l)
m4_l.connect("e3", destination= m3.ports["e1"])
m4_l.movex(m4_length + capm_enclosure[0] + m4_enclosure[0] + en[0]/2 )

# generate capm
rect_capm = gf.components.rectangle(size= (m4_length + 2*m4_enclosure[0] ,m4_width + 2*m4_enclosure[1]) , layer= capm_layer)
capm = c.add_ref(rect_capm)
capm.connect("e3", destination= m4_l.ports["e1"])
capm.movex(m4_length + m4_enclosure[0])


# generat3 via3
rect_via3 = gf.components.rectangle(size= via3_size, layer= via3_layer)

# for the left m4 plate
nc1 = floor ((m4_length) / (via3_size[0] + via3_spacing[0]))
nr1 = floor ((m4_width) / (via3_size[1] + via3_spacing[1]))
via3_arr1 = c.add_array(rect_via3 , rows= nr1 , columns= nc1 , spacing= (via3_spacing[0]+ via3_size[0], via3_spacing[1]+ via3_size[1]))
via3_arr1.movex (capm_enclosure[0] + m4_enclosure[0] + ((m4_length - nc1*via3_size[0] - (nc1-1)*via3_spacing[0])/2))
via3_arr1.movey(capm_enclosure[1] + m4_enclosure[1] + ((m4_width - nr1*via3_size[1] - (nr1-1)*via3_spacing[1])/2 ))

# for the right m4 plate
nr2 = floor ((m3_width - en[1]) / (via3_size[1]+ via3_spacing[1]))
nc2 = floor ((m4_r_length) / (via3_size[0]+via3_spacing[0]))
via3_arr2 = c.add_array(rect_via3 , rows= nr2 , columns= nc2 , spacing= (via3_spacing[0]+ via3_size[0], via3_spacing[1]+ via3_size[1]))
via3_arr2.movex(m3_length - en[0]/2 - m4_r_length)
via3_arr2.movex((m4_r_length - nc2*via3_size[0] - (nc2-1)*via3_spacing[0])/2)
via3_arr2.movey((m3_width - en[1]/2 - nr2*via3_size[1] - (nr2 - 1)*via3_spacing[1])/2 )



return c

if __name__ == "__main__":

c = mimcap_1()
#c = mimcap_1 (m4_length=1.8, m4_width=1.8 , m4_r_length=0.5)
c.show()
304 changes: 304 additions & 0 deletions sky130/device_generators/nmos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
from math import ceil, floor
import gdsfactory as gf
import numpy as np
from gdsfactory.types import Float2, LayerSpec

@gf.cell
def nmos(
diffusion_layer: LayerSpec = (65, 20),
poly_layer: LayerSpec = (66, 20),
gate_width: float = 0.42,
gate_length: float = 0.15,
sd_width: float = 0.3,
end_cap: float = 0.13,
contact_size: Float2 = (0.17, 0.17),
contact_spacing: Float2 = (0.17, 0.17),
contact_layer: LayerSpec = (66, 44),
contact_enclosure: float = (0.06,0.06),
diff_spacing : float = 0.27 ,
diff_enclosure : Float2 = (0.18,0.18) ,
diffp_layer : LayerSpec = (65,44) ,
pwell_layer : LayerSpec = (64,22),
dnwell_enclosure: float = (0.4,0.4),
dnwell_layer : LayerSpec = (64,18) ,
nf : int = 1 ,
sdm_enclosure : Float2 = (0.125,0.125) ,
nsdm_layer : LayerSpec = (93,44),
sdm_spacing : float = 0.13,
psdm_layer : LayerSpec = (94,20),
li_width : float = 0.17 ,
li_spacing : float = 0.17 ,
li_layer : LayerSpec = (67,20),
li_enclosure : float = 0.08,
mcon_layer : LayerSpec = (67,44) ,
mcon_enclosure : Float2 = (0.03,0.06),
m1_layer : LayerSpec = (68,20),
npc_layer : LayerSpec = (95,20),
npc_spacing : float = 0.09

) -> gf.Component:

"""Return NMOS.
Args:
diffusion_layer: spec.
poly_layer: spec.
gate_width: for poly.
gate_length: for poly.
sd_width: source drain length.
end_cap : end cap length.
contact_size : contact dimension (length and width)
contact_layer : for contacts
contact_enclosure : for contacts within diffusion or poly
diff_spacing : for two adjacent diffusions
diff_enclosure : for diffusion within well
diffp_layer : for bulk tie
dnwell layer : for deep nwell
nf : for finger option
.. code::
_______
| poly |
_________| |_________ _
| sd_width| | sd_width| |
|<------->| |<------->| |gate_width
|_________| |_________| |
| Lg |
|<---->|
|______|
"""
c = gf.Component()

# generating poly and n+ diffusion
w_p = end_cap + gate_width + end_cap # poly total width
rect_p = gf.components.rectangle(size = (gate_length,w_p), layer= poly_layer)

# adding fingers
#poly = c.add_ref(rect_p)
poly = c.add_array(rect_p, rows= 1 , columns= nf , spacing= [sd_width+gate_length, 0 ])


l_d = (nf + 1)*(sd_width + gate_length ) - gate_length # n diffution total length
rect_d = gf.components.rectangle(size = (l_d,gate_width), layer= diffusion_layer)
diff_n= c.add_ref(rect_d)

poly.movex(sd_width)
poly.movey(-end_cap)

# generating n+ implant
rect_nm = gf.components.rectangle(size = (l_d+ 2*sdm_enclosure[0] ,gate_width+ 2*sdm_enclosure[1]), layer= nsdm_layer)
nsdm = c.add_ref(rect_nm)
nsdm.movex(-sdm_enclosure[0])
nsdm.movey(-sdm_enclosure[1])

# generating contacts and local interconnects and mcon and m1 of n+ diffusion
rect_c = gf.components.rectangle(size = contact_size, layer = contact_layer)
rect_mc = gf.components.rectangle(size = contact_size, layer = mcon_layer)


nr = floor (gate_width / (2* contact_size[1]))
nc = floor (sd_width / (2* contact_size[0]))

con_sp = list(contact_spacing)
con_sp[0] = con_sp[1] = contact_spacing[0] + contact_size[0]

min_gate_len , min_gate_wid , sd_width_min = 0.15 , 0.42 , 0.3

cont_arr1 = c.add_array(rect_c, rows= nr , columns= nc , spacing= con_sp)
cont_arr2 = c.add_array(rect_c, rows= nr , columns= nc , spacing= con_sp)

cont_arr1.movey((min_gate_wid - contact_size[1])/2)
cont_arr2.movey((min_gate_wid - contact_size[1])/2)

mcont_arr1 = c.add_array(rect_mc, rows= nr , columns= nc , spacing= con_sp)
mcont_arr2 = c.add_array(rect_mc, rows= nr , columns= nc , spacing= con_sp)

mcont_arr1.movey((min_gate_wid - contact_size[1])/2)
mcont_arr2.movey((min_gate_wid - contact_size[1])/2)

rect_lid = gf.components.rectangle(size= (li_width , gate_width+ li_enclosure), layer= li_layer)
li1 = c.add_array(rect_lid, rows= 1 , columns= nc , spacing= con_sp)
li2 = c.add_array(rect_lid, rows= 1 , columns= nc , spacing= con_sp)

#rect_m1d = gf.components.rectangle(size= ( contact_size[0] + 2*mcon_enclosure[0], cont_arr1.ymax - cont_arr1.ymin + contact_size[1] + 2*mcon_enclosure[1]), layer= m1_layer)
rect_m1d = gf.components.rectangle(size= ( contact_size[0] + 2*mcon_enclosure[0],gate_width), layer=m1_layer)
m1d1 = c.add_array(rect_m1d, rows= 1 , columns= nc , spacing= con_sp)
m1d2 = c.add_array(rect_m1d, rows= 1 , columns= nc , spacing= con_sp)



if nc > 1 :
cont_arr1.movex ((sd_width - (cont_arr1.xmax - cont_arr1.xmin))/2)
cont_arr2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - (cont_arr2.xmax - cont_arr2.xmin))/2))
mcont_arr1.movex ((sd_width - (cont_arr1.xmax - cont_arr1.xmin))/2)
mcont_arr2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - (cont_arr2.xmax - cont_arr2.xmin))/2))
li1.movex ((sd_width - (cont_arr1.xmax - cont_arr1.xmin))/2)
li2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - (cont_arr2.xmax - cont_arr2.xmin))/2))
m1d1.movex ((sd_width - (cont_arr1.xmax - cont_arr1.xmin))/2 - mcon_enclosure[0])
m1d2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - (cont_arr2.xmax - cont_arr2.xmin))/2) - mcon_enclosure[0])

else :
cont_arr1.movex ((sd_width - contact_size[0])/2)
cont_arr2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - contact_size[0])/2) )
mcont_arr1.movex ((sd_width - contact_size[0])/2)
mcont_arr2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - contact_size[0])/2) )
li1.movex ((sd_width - contact_size[0])/2)
li2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - contact_size[0])/2) )
m1d1.movex ((sd_width - contact_size[0])/2 - mcon_enclosure[0])
m1d2.movex((nf*(sd_width+ gate_length) )+ ((sd_width - contact_size[0])/2) - mcon_enclosure[0] )

li1.movey(-li_enclosure/2)
li2.movey(-li_enclosure/2)



# generating contacts and local interconnects and mcon and m1 of poly


if (gate_length <= contact_size[0]) :
pc_x = contact_enclosure[0] +contact_size[0] + contact_enclosure[0]
cont_p = c.add_array(rect_c, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
cont_p.movex(sd_width- ((pc_x - gate_length)/2) + contact_enclosure[0])
cont_p.movey(gate_width + end_cap + contact_enclosure[1] )
cont_p2 = c.add_array(rect_c, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
cont_p2.movex(sd_width- ((pc_x - gate_length)/2) + contact_enclosure[0])
cont_p2.movey(-end_cap - contact_enclosure[1] - contact_size[1])

mcont_p = c.add_array(rect_mc, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
mcont_p.movex(sd_width- ((pc_x - gate_length)/2) + contact_enclosure[0])
mcont_p.movey(gate_width + end_cap + contact_enclosure[1] )
mcont_p2 = c.add_array(rect_mc, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
mcont_p2.movex(sd_width- ((pc_x - gate_length)/2) + contact_enclosure[0])
mcont_p2.movey(-end_cap - contact_enclosure[1] - contact_size[1])


else :
pc_x = gate_length
nc_p = floor (pc_x / (2* contact_size[0]))
for i in range(nf):
cont_arr3 = c.add_array(rect_c, rows= 1 , columns= nc_p , spacing= con_sp)
cont_arr3.movex(sd_width + ((gate_length - (cont_arr3.xmax - cont_arr3.xmin))/2)+ (i* (gate_length + sd_width)) )
cont_arr3.movey(gate_width + end_cap + contact_enclosure[1] )
cont_arr5 = c.add_array(rect_c, rows= 1 , columns= nc_p , spacing= con_sp)
cont_arr5.movex(sd_width + ((gate_length - (cont_arr5.xmax - cont_arr5.xmin))/2)+ (i* (gate_length + sd_width)) )
cont_arr5.movey(-contact_size[1] - end_cap - contact_enclosure[1] )
mcont_arr3 = c.add_array(rect_mc, rows= 1 , columns= nc_p , spacing= con_sp)
mcont_arr3.movex(sd_width + ((gate_length - (cont_arr3.xmax - cont_arr3.xmin))/2)+ (i* (gate_length + sd_width)) )
mcont_arr3.movey(gate_width + end_cap + contact_enclosure[1] )
mcont_arr5 = c.add_array(rect_mc, rows= 1 , columns= nc_p , spacing= con_sp)
mcont_arr5.movex(sd_width + ((gate_length - (cont_arr5.xmax - cont_arr5.xmin))/2)+ (i* (gate_length + sd_width)) )
mcont_arr5.movey(-contact_size[1] - end_cap - contact_enclosure[1] )


pc_size = (pc_x, contact_enclosure[1] +contact_size[1]+contact_enclosure[1]) # poly size to contain contact
rect_pc = gf.components.rectangle(size = pc_size, layer = poly_layer)
rect_m1p = gf.components.rectangle(size = (pc_x + 2*mcon_enclosure[0] - 2*contact_enclosure[0],contact_size[1]+2*mcon_enclosure[1]), layer = m1_layer)

pc_u = c.add_array(rect_pc, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
pc_u.movex(sd_width- ((pc_x - gate_length)/2))
pc_u.movey(gate_width + end_cap)

pc_d = c.add_array(rect_pc, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
pc_d.movex(sd_width- ((pc_x - gate_length)/2))
pc_d.movey(-pc_size[1]- end_cap)

m1p_u = c.add_array(rect_m1p, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
m1p_u.movex(sd_width- ((pc_x - gate_length)/2) + contact_enclosure[0] - mcon_enclosure[0])
m1p_u.movey(gate_width + end_cap + contact_enclosure[1] - mcon_enclosure[1])

m1p_d = c.add_array(rect_m1p, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
m1p_d.movex(sd_width- ((pc_x - gate_length)/2) + contact_enclosure[0] - mcon_enclosure[0])
m1p_d.movey(-pc_size[1]- end_cap + contact_enclosure[1] - contact_enclosure[1])

rect_lip = gf.components.rectangle(size = (pc_size[0]+ li_enclosure, li_width), layer = li_layer)
lip_u = c.add_array(rect_lip, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
lip_u.movex(sd_width- ((pc_x - gate_length)/2) - li_enclosure/2)
lip_u.movey(gate_width + end_cap + contact_enclosure[1])

lip_d = c.add_array(rect_lip, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
lip_d.movex(sd_width- ((pc_x - gate_length)/2) - li_enclosure/2)
lip_d.movey(-pc_size[1]- end_cap + contact_enclosure[1])

# generating npc for poly contacts

npc_en = end_cap - npc_spacing
rect_npc = gf.components.rectangle(size = (pc_size[0] + npc_en, pc_size[1] + npc_en), layer = npc_layer)

npc_u = c.add_array(rect_npc, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
npc_u.movex(sd_width- ((pc_x - gate_length)/2) - npc_en/2)
npc_u.movey(gate_width + npc_spacing + npc_en/2)

npc_d = c.add_array(rect_npc, rows= 1 , columns= nf , spacing= [sd_width + gate_length, 0] )
npc_d.movex(sd_width- ((pc_x - gate_length)/2) - npc_en/2)
npc_d.movey(-pc_size[1] - npc_en - npc_spacing - npc_en/2)



# generaing p+ bulk tie and its contact and mcon and m1
rect_dp = gf.components.rectangle(size = (sd_width,gate_width), layer= diffp_layer)
diff_p = c.add_ref(rect_dp)
diff_p.connect("e1",destination= diff_n.ports["e3"])
diff_p.movex(diff_spacing+ sdm_spacing)

cont_arr4 = c.add_array(rect_c, rows= nr , columns= nc , spacing= con_sp)
cont_arr4.movey((min_gate_wid - contact_size[1])/2 )

mcont_arr4 = c.add_array(rect_mc, rows= nr , columns= nc , spacing= con_sp)
mcont_arr4.movey((min_gate_wid - contact_size[1])/2 )

rect_m1dp = gf.components.rectangle(size= ( contact_size[0] + 2*mcon_enclosure[0],gate_width), layer=m1_layer)
m1dp = c.add_array(rect_m1dp, rows= 1 , columns= nc , spacing= con_sp)



# generate its local interconnects
li4 = c.add_array(rect_lid, rows= 1 , columns= nc , spacing= con_sp)


if nc > 1 :
cont_arr4.movex(l_d + diff_spacing + sdm_spacing + ((sd_width - (cont_arr4.xmax - cont_arr4.xmin))/2))
mcont_arr4.movex(l_d + diff_spacing + sdm_spacing + ((sd_width - (cont_arr4.xmax - cont_arr4.xmin))/2))
li4.movex(l_d + diff_spacing + sdm_spacing + ((sd_width - (cont_arr4.xmax - cont_arr4.xmin))/2))
m1dp.movex(l_d + diff_spacing + sdm_spacing + ((sd_width - (cont_arr4.xmax - cont_arr4.xmin))/2) - mcon_enclosure[0])

else :
cont_arr4.movex(l_d + diff_spacing+ sdm_spacing + ((sd_width - contact_size[0])/2))
mcont_arr4.movex(l_d + diff_spacing+ sdm_spacing + ((sd_width - contact_size[0])/2))
li4.movex(l_d + diff_spacing+ sdm_spacing + ((sd_width - contact_size[0])/2))
m1dp.movex(l_d + diff_spacing+ sdm_spacing + ((sd_width - contact_size[0])/2) - mcon_enclosure[0])

li4.movey(-li_enclosure/2)



# generating p+ implant for bulk tie
rect_pm = gf.components.rectangle(size = (sd_width+ 2*sdm_enclosure[0],gate_width+ 2*sdm_enclosure[1]), layer= psdm_layer)
psdm = c.add_ref(rect_pm)
psdm.connect("e1",destination= diff_n.ports["e3"])
psdm.movex(diff_spacing+ sdm_spacing - sdm_enclosure[0])


# generating pwell
rect_pw = gf.components.rectangle(size = (2*diff_enclosure[0] + l_d + diff_spacing + sdm_spacing+ sd_width , 2*diff_enclosure[1] + gate_width), layer= pwell_layer)
pwell = c.add_ref(rect_pw)
pwell.movex(-diff_enclosure[0])
pwell.movey(-diff_enclosure[1])

# generating deep nwell
rect_dnw = gf.components.rectangle(size = (rect_pw.xmax - rect_pw.xmin + 2*dnwell_enclosure[0] , rect_pw.ymax - rect_pw.ymin + 2*dnwell_enclosure[1]), layer= dnwell_layer)
dnwell = c.add_ref(rect_dnw)
dnwell.movex(-diff_enclosure[0]- dnwell_enclosure[0])
dnwell.movey(-diff_enclosure[1]- dnwell_enclosure[1])



return c


if __name__ == "__main__":

#c = nmos(gate_length= 2, gate_width=10)
c = nmos()
c.show()
Loading

0 comments on commit d67acf7

Please sign in to comment.