diff --git a/sky130/device_generators/mimcap_1.py b/sky130/device_generators/mimcap_1.py new file mode 100644 index 000000000..b4217f2a6 --- /dev/null +++ b/sky130/device_generators/mimcap_1.py @@ -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() diff --git a/sky130/device_generators/nmos.py b/sky130/device_generators/nmos.py new file mode 100644 index 000000000..404db7ee0 --- /dev/null +++ b/sky130/device_generators/nmos.py @@ -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() diff --git a/sky130/device_generators/nmos_5v.py b/sky130/device_generators/nmos_5v.py new file mode 100644 index 000000000..7c84a8baf --- /dev/null +++ b/sky130/device_generators/nmos_5v.py @@ -0,0 +1,281 @@ +from math import ceil, floor +import gdsfactory as gf +import numpy as np +from gdsfactory.types import Float2, LayerSpec + +@gf.cell +def nmos_5v( + diffusion_layer: LayerSpec = (65, 20), + poly_layer: LayerSpec = (66, 20), + gate_width: float = 0.75, + gate_length: float = 0.5, + 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.37 , + diff_enclosure : Float2 = (0.33,0.33) , + 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), + psdm_layer : LayerSpec = (94,20), + sdm_spacing : float = 0.13, + hvi_layer : LayerSpec= (75,20), + hvntm_layer : LayerSpec = (125,20), + hvntm_enclosure : Float2 = (0.185,0.185), + 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_5v. + + 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 + """ + + 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],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 + + nc_p = floor (gate_length / (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 = (gate_length, 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 = (gate_length + 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_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_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 + 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 + 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 - 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 - li_enclosure/2) + lip_d.movey(-contact_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 - 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 - 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]) + + # generating hvi + rect_hv = 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= hvi_layer) + dnwell = c.add_ref(rect_hv) + dnwell.movex(-diff_enclosure[0]- dnwell_enclosure[0]) + dnwell.movey(-diff_enclosure[1]- dnwell_enclosure[1]) + + + # generating hvntm for n+ implants + rect_hvn = gf.components.rectangle(size = (l_d+ 2*sdm_enclosure[0] + 2*hvntm_enclosure[0],gate_width+ 2*sdm_enclosure[1]+ 2*hvntm_enclosure[1]), layer= hvntm_layer) + hvntm = c.add_ref(rect_hvn) + hvntm.movex(-sdm_enclosure[0]- hvntm_enclosure[0]) + hvntm.movey(-sdm_enclosure[1]- hvntm_enclosure[1]) + + return c + +if __name__ == "__main__": + #c = nmos_5v(gate_length= 2, gate_width=5) + c = nmos_5v() + c.show() + diff --git a/sky130/device_generators/pmos.py b/sky130/device_generators/pmos.py new file mode 100644 index 000000000..cc24e8204 --- /dev/null +++ b/sky130/device_generators/pmos.py @@ -0,0 +1,296 @@ +from math import ceil, floor +import gdsfactory as gf +import numpy as np +from gdsfactory.types import Float2, LayerSpec + +@gf.cell +def pmos( + 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) , + diffn_layer : LayerSpec = (65,44) , + nwell_layer : LayerSpec = (64,20), + 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 PMOS. + + 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 + diffn_layer : for bulk tie + dnwell layer : for deep nwell + + + .. code:: + _______ + | poly | + _________| |_________ _ + | sd_width| | sd_width| | + |<------->| |<------->| |gate_width + |_________| |_________| | + | Lg | + |<---->| + |______| + + """ + + c = gf.Component() + + # generating poly and p+ 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_p= c.add_ref(rect_d) + + poly.movex(sd_width) + poly.movey(-end_cap) + + # generating p+ implant + rect_pm = gf.components.rectangle(size = (l_d+ 2*sdm_enclosure[0] ,gate_width+ 2*sdm_enclosure[1]), layer= psdm_layer) + psdm = c.add_ref(rect_pm) + psdm.movex(-sdm_enclosure[0]) + psdm.movey(-sdm_enclosure[1]) + + # generating contacts and local interconnect and mcon and m1 of p+ 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],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 n+ bulk tie and its contact and mcon and m1 + rect_dn = gf.components.rectangle(size = (sd_width,gate_width), layer= diffn_layer) + diff_n = c.add_ref(rect_dn) + diff_n.connect("e1",destination= diff_p.ports["e3"]) + diff_n.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_m1dn = gf.components.rectangle(size= ( contact_size[0] + 2*mcon_enclosure[0],gate_width), layer=m1_layer) + m1dn = c.add_array(rect_m1dn, 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)) + m1dn.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)) + m1dn.movex(l_d + diff_spacing + sdm_spacing + ((sd_width - contact_size[0])/2) - mcon_enclosure[0]) + + li4.movey(-li_enclosure/2) + + # generating n+ implant for bulk tie + rect_nm = gf.components.rectangle(size = (sd_width+ 2*sdm_enclosure[0],gate_width+ 2*sdm_enclosure[1]), layer= nsdm_layer) + nsdm = c.add_ref(rect_nm) + nsdm.connect("e1",destination= diff_p.ports["e3"]) + nsdm.movex(diff_spacing + sdm_spacing - sdm_enclosure[0]) + + # generating nwell + rect_nw = gf.components.rectangle(size = (2*diff_enclosure[0] + l_d + diff_spacing + sdm_spacing + sd_width , 2*diff_enclosure[1] + gate_width), layer= nwell_layer) + nwell = c.add_ref(rect_nw) + nwell.movex(-diff_enclosure[0]) + nwell.movey(-diff_enclosure[1]) + + # generating deep nwell + rect_dnw = gf.components.rectangle(size = (rect_nw.xmax - rect_nw.xmin + 2*dnwell_enclosure[0] , rect_nw.ymax - rect_nw.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 = pmos(gate_length= 2, gate_width=10, sd_width=5) + c = pmos() + c.show() + + diff --git a/sky130/device_generators/pmos_5v.py b/sky130/device_generators/pmos_5v.py new file mode 100644 index 000000000..d1cdc48ad --- /dev/null +++ b/sky130/device_generators/pmos_5v.py @@ -0,0 +1,266 @@ +from math import ceil, floor +import gdsfactory as gf +import numpy as np +from gdsfactory.types import Float2, LayerSpec + +@gf.cell +def pmos_5v( + diffusion_layer: LayerSpec = (65, 20), + poly_layer: LayerSpec = (66, 20), + gate_width: float = 0.75, + gate_length: float = 0.5, + 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.37 , + diff_enclosure : Float2 = (0.33,0.33) , + diffn_layer : LayerSpec = (65,44) , + nwell_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), + psdm_layer : LayerSpec = (94,20), + sdm_spacing : float = 0.13, + hvi_layer : LayerSpec= (75,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 PMOS_5v. + + 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 + """ + + c = gf.Component() + + # generating poly and p+ 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_p= c.add_ref(rect_d) + + poly.movex(sd_width) + poly.movey(-end_cap) + + # generating p+ implant + rect_pm = gf.components.rectangle(size = (l_d+ 2*sdm_enclosure[0] ,gate_width+ 2*sdm_enclosure[1]), layer= psdm_layer) + psdm = c.add_ref(rect_pm) + psdm.movex(-sdm_enclosure[0]) + psdm.movey(-sdm_enclosure[1]) + + # generating contacts and interconnects and mcon and m1 of p+ 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],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 of poly + + nc_p = floor (gate_length / (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 = (gate_length, 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 = (gate_length + 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- ((gate_length - 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_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 + 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 + 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 - 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 - li_enclosure/2) + lip_d.movey(-contact_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 - 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 - npc_en/2) + npc_d.movey(-pc_size[1] - npc_en - npc_spacing - npc_en/2) + + + # generaing n+ bulk tie and its contact and mcon and m1 + rect_dn = gf.components.rectangle(size = (sd_width,gate_width), layer= diffn_layer) + diff_n = c.add_ref(rect_dn) + diff_n.connect("e1",destination= diff_p.ports["e3"]) + diff_n.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_m1dn = gf.components.rectangle(size= ( contact_size[0] + 2*mcon_enclosure[0],gate_width), layer=m1_layer) + m1dn = c.add_array(rect_m1dn, 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)) + m1dn.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)) + m1dn.movex(l_d + diff_spacing + sdm_spacing + ((sd_width - contact_size[0])/2) - mcon_enclosure[0]) + + li4.movey(-li_enclosure/2) + + # generating n+ implant for bulk tie + rect_nm = gf.components.rectangle(size = (sd_width+ 2*sdm_enclosure[0],gate_width+ 2*sdm_enclosure[1]), layer= nsdm_layer) + nsdm = c.add_ref(rect_nm) + nsdm.connect("e1",destination= diff_p.ports["e3"]) + nsdm.movex(diff_spacing + sdm_spacing - sdm_enclosure[0]) + + # generating nwell + rect_nw = gf.components.rectangle(size = (2*diff_enclosure[0] + l_d + diff_spacing + sdm_spacing + sd_width , 2*diff_enclosure[1] + gate_width), layer= nwell_layer) + nwell = c.add_ref(rect_nw) + nwell.movex(-diff_enclosure[0]) + nwell.movey(-diff_enclosure[1]) + + # generating deep nwell + rect_dnw = gf.components.rectangle(size = (rect_nw.xmax - rect_nw.xmin + 2*dnwell_enclosure[0] , rect_nw.ymax - rect_nw.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]) + + # generating hvi + rect_hv = gf.components.rectangle(size = (rect_nw.xmax - rect_nw.xmin + 2*dnwell_enclosure[0] , rect_nw.ymax - rect_nw.ymin + 2*dnwell_enclosure[1]), layer= hvi_layer) + dnwell = c.add_ref(rect_hv) + dnwell.movex(-diff_enclosure[0]- dnwell_enclosure[0]) + dnwell.movey(-diff_enclosure[1]- dnwell_enclosure[1]) + + return c + +if __name__ == "__main__": + #c = pmos_5v(gate_length= 2, gate_width=10, sd_width=5 ) + c = pmos_5v() + c.show()