diff --git a/cells/klayout/pymacros/cells/__init__.py b/cells/klayout/pymacros/cells/__init__.py index 7ed55fcb..4ee61221 100644 --- a/cells/klayout/pymacros/cells/__init__.py +++ b/cells/klayout/pymacros/cells/__init__.py @@ -46,16 +46,15 @@ def __init__(self): "pfet", pfet() ) # pfet_03v3 , pfet_05v0 , pfet_06v0 self.layout().register_pcell("nfet_06v0_nvt", nfet_06v0_nvt()) - + # BJT self.layout().register_pcell( "npn_bjt", npn_bjt() ) # npn_10p00x10p00 , npn_05p00x05p00 , npn_00p54x16p00 , - # npn_00p54x08p00 , npn_00p54x04p00 , npn_00p54x02p00 + # npn_00p54x08p00 , npn_00p54x04p00 , npn_00p54x02p00 self.layout().register_pcell( "pnp_bjt", pnp_bjt() ) # pnp_10p00x10p00 , pnp_05p00x05p00 , pnp_10p00x00p42 , pnp_05p00x00p42 - # Register us with the name "gf180mcu". self.register("gf180mcu") diff --git a/cells/klayout/pymacros/cells/bjt.py b/cells/klayout/pymacros/cells/bjt.py index c7c96bb0..d3e82ec1 100644 --- a/cells/klayout/pymacros/cells/bjt.py +++ b/cells/klayout/pymacros/cells/bjt.py @@ -29,7 +29,9 @@ def __init__(self): # Important: initialize the super class super(npn_bjt, self).__init__() - self.Type_handle = self.param("Type", self.TypeList, "Type", default= "npn_10p00x10p00") + self.Type_handle = self.param( + "Type", self.TypeList, "Type", default="npn_10p00x10p00" + ) self.Type_handle.add_choice("npn_10p00x10p00", "npn_10p00x10p00") self.Type_handle.add_choice("npn_05p00x05p00", "npn_05p00x05p00") self.Type_handle.add_choice("npn_00p54x16p00", "npn_00p54x16p00") @@ -98,7 +100,9 @@ def __init__(self): # Important: initialize the super class super(pnp_bjt, self).__init__() - self.Type_handle = self.param("Type", self.TypeList, "Type", default= "pnp_10p00x10p00") + self.Type_handle = self.param( + "Type", self.TypeList, "Type", default="pnp_10p00x10p00" + ) self.Type_handle.add_choice("pnp_10p00x10p00", "pnp_10p00x10p00") self.Type_handle.add_choice("pnp_05p00x05p00", "pnp_05p00x05p00") self.Type_handle.add_choice("pnp_10p00x00p42", "pnp_10p00x00p42") diff --git a/cells/klayout/pymacros/cells/draw_cap_mim.py b/cells/klayout/pymacros/cells/draw_cap_mim.py index 70db8990..7f51395c 100644 --- a/cells/klayout/pymacros/cells/draw_cap_mim.py +++ b/cells/klayout/pymacros/cells/draw_cap_mim.py @@ -20,14 +20,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ---------- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ---------- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/cells/draw_cap_mos.py b/cells/klayout/pymacros/cells/draw_cap_mos.py index 111dd4e6..4d1055d0 100644 --- a/cells/klayout/pymacros/cells/draw_cap_mos.py +++ b/cells/klayout/pymacros/cells/draw_cap_mos.py @@ -20,14 +20,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ---------- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ---------- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/cells/draw_diode.py b/cells/klayout/pymacros/cells/draw_diode.py index 631d19a8..d549cdad 100644 --- a/cells/klayout/pymacros/cells/draw_diode.py +++ b/cells/klayout/pymacros/cells/draw_diode.py @@ -20,14 +20,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ----- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ----- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/cells/draw_fet.py b/cells/klayout/pymacros/cells/draw_fet.py index a1b1ebe7..ae349b6a 100644 --- a/cells/klayout/pymacros/cells/draw_fet.py +++ b/cells/klayout/pymacros/cells/draw_fet.py @@ -93,9 +93,7 @@ def draw_nfet( lvpwell_enc_pcmp = 0.12 sd_l_con = ( - ((sd_con_col) * con_size) - + ((sd_con_col - 1) * con_sp) - + 2 * con_comp_enc + ((sd_con_col) * con_size) + ((sd_con_col - 1) * con_sp) + 2 * con_comp_enc ) sd_l = sd_l_con @@ -109,9 +107,7 @@ def draw_nfet( if interdig == 1 and nf > 1 and nf != len(patt) and patt != "": nf = len(patt) - l_d = ( - nf * l + (nf - 1) * inter_sd_l + 2 * (con_comp_enc) - ) # diffution total length + l_d = nf * l + (nf - 1) * inter_sd_l + 2 * (con_comp_enc) # diffution total length rect_d_intr = gf.components.rectangle(size=(l_d, w), layer=comp_layer) sd_diff_intr = c_inst.add_ref(rect_d_intr) @@ -133,9 +129,7 @@ def draw_nfet( ) sd_diff.xmin = sd_diff_intr.xmin - cmpc_size[0] - sd_diff.ymin = ( - sd_diff_intr.ymin - (sd_diff.size[1] - sd_diff_intr.size[1]) / 2 - ) + sd_diff.ymin = sd_diff_intr.ymin - (sd_diff.size[1] - sd_diff_intr.size[1]) / 2 sd_con = via_stack( x_range=(sd_diff.xmin, sd_diff_intr.xmin), @@ -182,9 +176,7 @@ def draw_nfet( c_pc = gf.Component("poly con") - rect_pc = c_pc.add_ref( - gf.components.rectangle(size=pc_size, layer=poly2_layer) - ) + rect_pc = c_pc.add_ref(gf.components.rectangle(size=pc_size, layer=poly2_layer)) poly_con = via_stack( x_range=(rect_pc.xmin, rect_pc.xmax), @@ -197,9 +189,7 @@ def draw_nfet( if nf == 1: poly = c_inst.add_ref( - gf.components.rectangle( - size=(l, w + 2 * end_cap), layer=poly2_layer - ) + gf.components.rectangle(size=(l, w + 2 * end_cap), layer=poly2_layer) ) poly.xmin = sd_diff_intr.xmin + con_comp_enc poly.ymin = sd_diff_intr.ymin - end_cap @@ -233,14 +223,7 @@ def draw_nfet( w_p2 = w_p1 e_c = 0.2 else: - w_p2 = ( - w_p1 - + con_pl_enc - + con_size - + con_pl_enc - + poly2_spacing - + 0.1 - ) + w_p2 = w_p1 + con_pl_enc + con_size + con_pl_enc + poly2_spacing + 0.1 e_c = 0 if gate_con_pos == "bottom": @@ -378,8 +361,7 @@ def draw_nfet( ( ( pc2.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - pc2.ymin ), @@ -398,9 +380,7 @@ def draw_nfet( x_range=(m1.xmin, m1.xmax), y_range=( m2_arru.ymin + i * (m2_y + m2_spacing), - m2_arru.ymin - + i * (m2_y + m2_spacing) - + m2_y, + m2_arru.ymin + i * (m2_y + m2_spacing) + m2_y, ), via_enclosure=via_enc, via_layer=via1_layer, @@ -428,8 +408,7 @@ def draw_nfet( ( ( pc1.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - pc1.ymin ), @@ -447,9 +426,7 @@ def draw_nfet( via1_dr = via_generator( x_range=(m1.xmin, m1.xmax), y_range=( - m2_arrb.ymax - - i * (m2_spacing + m2_y) - - m2_y, + m2_arrb.ymax - i * (m2_spacing + m2_y) - m2_y, m2_arrb.ymax - i * (m2_spacing + m2_y), ), via_enclosure=via_enc, @@ -477,18 +454,14 @@ def draw_nfet( m2_join_b = c_inst.add_ref( gf.components.rectangle( size=( - m2_y - + (i + 1) * (m3_spacing + m3_x), + m2_y + (i + 1) * (m3_spacing + m3_x), m2_y, ), layer=m2_layer, ).move( ( m2_arrb.xmin - - ( - m2_y - + (i + 1) * (m3_spacing + m3_x) - ), + - (m2_y + (i + 1) * (m3_spacing + m3_x)), m2_arrb.ymax - i * (m2_spacing + m2_y) - m2_y, @@ -498,20 +471,15 @@ def draw_nfet( m2_join_u = c_inst.add_ref( gf.components.rectangle( size=( - m2_y - + (i + 1) * (m3_spacing + m3_x), + m2_y + (i + 1) * (m3_spacing + m3_x), m2_y, ), layer=m2_layer, ).move( ( m2_arru.xmin - - ( - m2_y - + (i + 1) * (m3_spacing + m3_x) - ), - m2_arru.ymin - + j * (m2_spacing + m2_y), + - (m2_y + (i + 1) * (m3_spacing + m3_x)), + m2_arru.ymin + j * (m2_spacing + m2_y), ) ) ) @@ -563,8 +531,7 @@ def draw_nfet( ( ( pc2.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - ((1 - j % 2) * pc1.ymin) - (j % 2) * pc2.ymin @@ -577,14 +544,7 @@ def draw_nfet( ( ( sd_l - - ( - ( - poly_con.xmax - - poly_con.xmin - - l - ) - / 2 - ) + - ((poly_con.xmax - poly_con.xmin - l) / 2) + j * (l + inter_sd_l) ), (1 - j % 2) * (pc1.ymin + 0.06) @@ -595,9 +555,7 @@ def draw_nfet( x_range=(m1.xmin, m1.xmax), y_range=( m2_arr.ymin + i * (m2_spacing + m2_y), - m2_arr.ymin - + i * (m2_spacing + m2_y) - + m2_y, + m2_arr.ymin + i * (m2_spacing + m2_y) + m2_y, ), via_enclosure=via_enc, via_layer=via1_layer, @@ -635,8 +593,7 @@ def draw_nfet( ( ( pc1.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - (j % 2) * pc1.ymin - (1 - j % 2) * pc2.ymin @@ -649,14 +606,7 @@ def draw_nfet( ( ( sd_l - - ( - ( - poly_con.xmax - - poly_con.xmin - - l - ) - / 2 - ) + - ((poly_con.xmax - poly_con.xmin - l) / 2) + j * (l + inter_sd_l) ), -(m1.ymax - m1.ymin) @@ -667,9 +617,7 @@ def draw_nfet( via1_dr = via_generator( x_range=(m1.xmin, m1.xmax), y_range=( - m2_arr.ymax - - i * (m2_spacing + m2_y) - - m2_y, + m2_arr.ymax - i * (m2_spacing + m2_y) - m2_y, m2_arr.ymax - i * (m2_spacing + m2_y), ), via_enclosure=via_enc, @@ -789,16 +737,12 @@ def draw_nfet( layer=pplus_layer, ) ) - psdm_in.move( - (rect_bulk_in.xmin + comp_pp_enc, rect_bulk_in.ymin + comp_pp_enc) - ) + psdm_in.move((rect_bulk_in.xmin + comp_pp_enc, rect_bulk_in.ymin + comp_pp_enc)) psdm_out = c_temp.add_ref( gf.components.rectangle( size=( - (rect_bulk_out.xmax - rect_bulk_out.xmin) - + 2 * comp_pp_enc, - (rect_bulk_out.ymax - rect_bulk_out.ymin) - + 2 * comp_pp_enc, + (rect_bulk_out.xmax - rect_bulk_out.xmin) + 2 * comp_pp_enc, + (rect_bulk_out.ymax - rect_bulk_out.ymin) + 2 * comp_pp_enc, ), layer=pplus_layer, ) @@ -1009,9 +953,7 @@ def draw_nfet( layer=comp_layer, ) ) - rect_pcmpgr_out.move( - (rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw) - ) + rect_pcmpgr_out.move((rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw)) B = c.add_ref( gf.geometry.boolean( A=rect_pcmpgr_out, @@ -1024,10 +966,8 @@ def draw_nfet( psdm_in = c_temp_gr.add_ref( gf.components.rectangle( size=( - (rect_pcmpgr_in.xmax - rect_pcmpgr_in.xmin) - - 2 * comp_pp_enc, - (rect_pcmpgr_in.ymax - rect_pcmpgr_in.ymin) - - 2 * comp_pp_enc, + (rect_pcmpgr_in.xmax - rect_pcmpgr_in.xmin) - 2 * comp_pp_enc, + (rect_pcmpgr_in.ymax - rect_pcmpgr_in.ymin) - 2 * comp_pp_enc, ), layer=pplus_layer, ) @@ -1041,10 +981,8 @@ def draw_nfet( psdm_out = c_temp_gr.add_ref( gf.components.rectangle( size=( - (rect_pcmpgr_out.xmax - rect_pcmpgr_out.xmin) - + 2 * comp_pp_enc, - (rect_pcmpgr_out.ymax - rect_pcmpgr_out.ymin) - + 2 * comp_pp_enc, + (rect_pcmpgr_out.xmax - rect_pcmpgr_out.xmin) + 2 * comp_pp_enc, + (rect_pcmpgr_out.ymax - rect_pcmpgr_out.ymin) + 2 * comp_pp_enc, ), layer=pplus_layer, ) @@ -1141,9 +1079,7 @@ def draw_nfet( layer=m1_layer, ) ) - comp_m1_out.move( - (rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw) - ) + comp_m1_out.move((rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw)) m1 = c.add_ref( gf.geometry.boolean( A=rect_pcmpgr_out, @@ -1184,16 +1120,16 @@ def draw_pfet( """ Retern pfet - Args: - layout : layout object - l : Float of gate length + Args: + layout : layout object + l : Float of gate length w : Float of gate width sd_l : Float of source and drain diffusion length - inter_sd_l : Float of source and drain diffusion length between fingers - nf : integer of number of fingers - M : integer of number of multipliers - grw : gaurd ring width when enabled - type : string of the device type + inter_sd_l : Float of source and drain diffusion length between fingers + nf : integer of number of fingers + M : integer of number of multipliers + grw : gaurd ring width when enabled + type : string of the device type bulk : String of bulk connection type (None, Bulk Tie, Guard Ring) con_bet_fin : boolean of having contacts for diffusion between fingers gate_con_pos : string of choosing the gate contact position (bottom, top, alternating ) @@ -1230,9 +1166,7 @@ def draw_pfet( dnwell_enc_pcmp = 1.1 sd_l_con = ( - ((sd_con_col) * con_size) - + ((sd_con_col - 1) * con_sp) - + 2 * con_comp_enc + ((sd_con_col) * con_size) + ((sd_con_col - 1) * con_sp) + 2 * con_comp_enc ) sd_l = sd_l_con @@ -1246,9 +1180,7 @@ def draw_pfet( if interdig == 1 and nf > 1 and nf != len(patt) and patt != "": nf = len(patt) - l_d = ( - nf * l + (nf - 1) * inter_sd_l + 2 * (con_comp_enc) - ) # diffution total length + l_d = nf * l + (nf - 1) * inter_sd_l + 2 * (con_comp_enc) # diffution total length rect_d_intr = gf.components.rectangle(size=(l_d, w), layer=comp_layer) sd_diff_intr = c_inst.add_ref(rect_d_intr) @@ -1270,9 +1202,7 @@ def draw_pfet( ) sd_diff.xmin = sd_diff_intr.xmin - cmpc_size[0] - sd_diff.ymin = ( - sd_diff_intr.ymin - (sd_diff.size[1] - sd_diff_intr.size[1]) / 2 - ) + sd_diff.ymin = sd_diff_intr.ymin - (sd_diff.size[1] - sd_diff_intr.size[1]) / 2 sd_con = via_stack( x_range=(sd_diff.xmin, sd_diff_intr.xmin), @@ -1319,9 +1249,7 @@ def draw_pfet( c_pc = gf.Component("poly con") - rect_pc = c_pc.add_ref( - gf.components.rectangle(size=pc_size, layer=poly2_layer) - ) + rect_pc = c_pc.add_ref(gf.components.rectangle(size=pc_size, layer=poly2_layer)) poly_con = via_stack( x_range=(rect_pc.xmin, rect_pc.xmax), @@ -1334,9 +1262,7 @@ def draw_pfet( if nf == 1: poly = c_inst.add_ref( - gf.components.rectangle( - size=(l, w + 2 * end_cap), layer=poly2_layer - ) + gf.components.rectangle(size=(l, w + 2 * end_cap), layer=poly2_layer) ) poly.xmin = sd_diff_intr.xmin + con_comp_enc poly.ymin = sd_diff_intr.ymin - end_cap @@ -1370,14 +1296,7 @@ def draw_pfet( w_p2 = w_p1 e_c = 0.2 else: - w_p2 = ( - w_p1 - + con_pl_enc - + con_size - + con_pl_enc - + poly2_spacing - + 0.1 - ) + w_p2 = w_p1 + con_pl_enc + con_size + con_pl_enc + poly2_spacing + 0.1 e_c = 0 if gate_con_pos == "bottom": @@ -1515,8 +1434,7 @@ def draw_pfet( ( ( pc2.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - pc2.ymin ), @@ -1535,9 +1453,7 @@ def draw_pfet( x_range=(m1.xmin, m1.xmax), y_range=( m2_arru.ymin + i * (m2_y + m2_spacing), - m2_arru.ymin - + i * (m2_y + m2_spacing) - + m2_y, + m2_arru.ymin + i * (m2_y + m2_spacing) + m2_y, ), via_enclosure=via_enc, via_layer=via1_layer, @@ -1565,8 +1481,7 @@ def draw_pfet( ( ( pc1.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - pc1.ymin ), @@ -1584,9 +1499,7 @@ def draw_pfet( via1_dr = via_generator( x_range=(m1.xmin, m1.xmax), y_range=( - m2_arrb.ymax - - i * (m2_spacing + m2_y) - - m2_y, + m2_arrb.ymax - i * (m2_spacing + m2_y) - m2_y, m2_arrb.ymax - i * (m2_spacing + m2_y), ), via_enclosure=via_enc, @@ -1614,18 +1527,14 @@ def draw_pfet( m2_join_b = c_inst.add_ref( gf.components.rectangle( size=( - m2_y - + (i + 1) * (m3_spacing + m3_x), + m2_y + (i + 1) * (m3_spacing + m3_x), m2_y, ), layer=m2_layer, ).move( ( m2_arrb.xmin - - ( - m2_y - + (i + 1) * (m3_spacing + m3_x) - ), + - (m2_y + (i + 1) * (m3_spacing + m3_x)), m2_arrb.ymax - i * (m2_spacing + m2_y) - m2_y, @@ -1635,20 +1544,15 @@ def draw_pfet( m2_join_u = c_inst.add_ref( gf.components.rectangle( size=( - m2_y - + (i + 1) * (m3_spacing + m3_x), + m2_y + (i + 1) * (m3_spacing + m3_x), m2_y, ), layer=m2_layer, ).move( ( m2_arru.xmin - - ( - m2_y - + (i + 1) * (m3_spacing + m3_x) - ), - m2_arru.ymin - + j * (m2_spacing + m2_y), + - (m2_y + (i + 1) * (m3_spacing + m3_x)), + m2_arru.ymin + j * (m2_spacing + m2_y), ) ) ) @@ -1700,8 +1604,7 @@ def draw_pfet( ( ( pc2.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - ((1 - j % 2) * pc1.ymin) - (j % 2) * pc2.ymin @@ -1714,14 +1617,7 @@ def draw_pfet( ( ( sd_l - - ( - ( - poly_con.xmax - - poly_con.xmin - - l - ) - / 2 - ) + - ((poly_con.xmax - poly_con.xmin - l) / 2) + j * (l + inter_sd_l) ), (1 - j % 2) * (pc1.ymin + 0.06) @@ -1732,9 +1628,7 @@ def draw_pfet( x_range=(m1.xmin, m1.xmax), y_range=( m2_arr.ymin + i * (m2_spacing + m2_y), - m2_arr.ymin - + i * (m2_spacing + m2_y) - + m2_y, + m2_arr.ymin + i * (m2_spacing + m2_y) + m2_y, ), via_enclosure=via_enc, via_layer=via1_layer, @@ -1772,8 +1666,7 @@ def draw_pfet( ( ( pc1.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - (j % 2) * pc1.ymin - (1 - j % 2) * pc2.ymin @@ -1786,14 +1679,7 @@ def draw_pfet( ( ( sd_l - - ( - ( - poly_con.xmax - - poly_con.xmin - - l - ) - / 2 - ) + - ((poly_con.xmax - poly_con.xmin - l) / 2) + j * (l + inter_sd_l) ), -(m1.ymax - m1.ymin) @@ -1804,9 +1690,7 @@ def draw_pfet( via1_dr = via_generator( x_range=(m1.xmin, m1.xmax), y_range=( - m2_arr.ymax - - i * (m2_spacing + m2_y) - - m2_y, + m2_arr.ymax - i * (m2_spacing + m2_y) - m2_y, m2_arr.ymax - i * (m2_spacing + m2_y), ), via_enclosure=via_enc, @@ -2040,16 +1924,12 @@ def draw_pfet( layer=nplus_layer, ) ) - nsdm_in.move( - (rect_bulk_in.xmin + comp_np_enc, rect_bulk_in.ymin + comp_np_enc) - ) + nsdm_in.move((rect_bulk_in.xmin + comp_np_enc, rect_bulk_in.ymin + comp_np_enc)) nsdm_out = c_temp.add_ref( gf.components.rectangle( size=( - (rect_bulk_out.xmax - rect_bulk_out.xmin) - + 2 * comp_np_enc, - (rect_bulk_out.ymax - rect_bulk_out.ymin) - + 2 * comp_np_enc, + (rect_bulk_out.xmax - rect_bulk_out.xmin) + 2 * comp_np_enc, + (rect_bulk_out.ymax - rect_bulk_out.ymin) + 2 * comp_np_enc, ), layer=nplus_layer, ) @@ -2230,9 +2110,7 @@ def draw_pfet( layer=comp_layer, ) ) - rect_pcmpgr_out.move( - (rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw) - ) + rect_pcmpgr_out.move((rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw)) B = c.add_ref( gf.geometry.boolean( A=rect_pcmpgr_out, @@ -2245,10 +2123,8 @@ def draw_pfet( psdm_in = c_temp_gr.add_ref( gf.components.rectangle( size=( - (rect_pcmpgr_in.xmax - rect_pcmpgr_in.xmin) - - 2 * comp_pp_enc, - (rect_pcmpgr_in.ymax - rect_pcmpgr_in.ymin) - - 2 * comp_pp_enc, + (rect_pcmpgr_in.xmax - rect_pcmpgr_in.xmin) - 2 * comp_pp_enc, + (rect_pcmpgr_in.ymax - rect_pcmpgr_in.ymin) - 2 * comp_pp_enc, ), layer=pplus_layer, ) @@ -2262,10 +2138,8 @@ def draw_pfet( psdm_out = c_temp_gr.add_ref( gf.components.rectangle( size=( - (rect_pcmpgr_out.xmax - rect_pcmpgr_out.xmin) - + 2 * comp_pp_enc, - (rect_pcmpgr_out.ymax - rect_pcmpgr_out.ymin) - + 2 * comp_pp_enc, + (rect_pcmpgr_out.xmax - rect_pcmpgr_out.xmin) + 2 * comp_pp_enc, + (rect_pcmpgr_out.ymax - rect_pcmpgr_out.ymin) + 2 * comp_pp_enc, ), layer=pplus_layer, ) @@ -2356,9 +2230,7 @@ def draw_pfet( layer=m1_layer, ) ) - comp_m1_out.move( - (rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw) - ) + comp_m1_out.move((rect_pcmpgr_in.xmin - grw, rect_pcmpgr_in.ymin - grw)) m1 = c.add_ref( gf.geometry.boolean( A=rect_pcmpgr_out, @@ -2431,9 +2303,7 @@ def draw_nfet_06v0_nvt( lvpwell_enc_ncmp = 0.43 sd_l_con = ( - ((sd_con_col) * con_size) - + ((sd_con_col - 1) * con_sp) - + 2 * con_comp_enc + ((sd_con_col) * con_size) + ((sd_con_col - 1) * con_sp) + 2 * con_comp_enc ) sd_l = sd_l_con @@ -2447,9 +2317,7 @@ def draw_nfet_06v0_nvt( if interdig == 1 and nf > 1 and nf != len(patt) and patt != "": nf = len(patt) - l_d = ( - nf * l + (nf - 1) * inter_sd_l + 2 * (con_comp_enc) - ) # diffution total length + l_d = nf * l + (nf - 1) * inter_sd_l + 2 * (con_comp_enc) # diffution total length rect_d_intr = gf.components.rectangle(size=(l_d, w), layer=comp_layer) sd_diff_intr = c_inst.add_ref(rect_d_intr) @@ -2471,9 +2339,7 @@ def draw_nfet_06v0_nvt( ) sd_diff.xmin = sd_diff_intr.xmin - cmpc_size[0] - sd_diff.ymin = ( - sd_diff_intr.ymin - (sd_diff.size[1] - sd_diff_intr.size[1]) / 2 - ) + sd_diff.ymin = sd_diff_intr.ymin - (sd_diff.size[1] - sd_diff_intr.size[1]) / 2 sd_con = via_stack( x_range=(sd_diff.xmin, sd_diff_intr.xmin), @@ -2520,9 +2386,7 @@ def draw_nfet_06v0_nvt( c_pc = gf.Component("poly con") - rect_pc = c_pc.add_ref( - gf.components.rectangle(size=pc_size, layer=poly2_layer) - ) + rect_pc = c_pc.add_ref(gf.components.rectangle(size=pc_size, layer=poly2_layer)) poly_con = via_stack( x_range=(rect_pc.xmin, rect_pc.xmax), @@ -2535,9 +2399,7 @@ def draw_nfet_06v0_nvt( if nf == 1: poly = c_inst.add_ref( - gf.components.rectangle( - size=(l, w + 2 * end_cap), layer=poly2_layer - ) + gf.components.rectangle(size=(l, w + 2 * end_cap), layer=poly2_layer) ) poly.xmin = sd_diff_intr.xmin + con_comp_enc poly.ymin = sd_diff_intr.ymin - end_cap @@ -2571,14 +2433,7 @@ def draw_nfet_06v0_nvt( w_p2 = w_p1 e_c = 0.2 else: - w_p2 = ( - w_p1 - + con_pl_enc - + con_size - + con_pl_enc - + poly2_spacing - + 0.1 - ) + w_p2 = w_p1 + con_pl_enc + con_size + con_pl_enc + poly2_spacing + 0.1 e_c = 0 if gate_con_pos == "bottom": @@ -2716,8 +2571,7 @@ def draw_nfet_06v0_nvt( ( ( pc2.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - pc2.ymin ), @@ -2736,9 +2590,7 @@ def draw_nfet_06v0_nvt( x_range=(m1.xmin, m1.xmax), y_range=( m2_arru.ymin + i * (m2_y + m2_spacing), - m2_arru.ymin - + i * (m2_y + m2_spacing) - + m2_y, + m2_arru.ymin + i * (m2_y + m2_spacing) + m2_y, ), via_enclosure=via_enc, via_layer=via1_layer, @@ -2766,8 +2618,7 @@ def draw_nfet_06v0_nvt( ( ( pc1.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - pc1.ymin ), @@ -2785,9 +2636,7 @@ def draw_nfet_06v0_nvt( via1_dr = via_generator( x_range=(m1.xmin, m1.xmax), y_range=( - m2_arrb.ymax - - i * (m2_spacing + m2_y) - - m2_y, + m2_arrb.ymax - i * (m2_spacing + m2_y) - m2_y, m2_arrb.ymax - i * (m2_spacing + m2_y), ), via_enclosure=via_enc, @@ -2815,18 +2664,14 @@ def draw_nfet_06v0_nvt( m2_join_b = c_inst.add_ref( gf.components.rectangle( size=( - m2_y - + (i + 1) * (m3_spacing + m3_x), + m2_y + (i + 1) * (m3_spacing + m3_x), m2_y, ), layer=m2_layer, ).move( ( m2_arrb.xmin - - ( - m2_y - + (i + 1) * (m3_spacing + m3_x) - ), + - (m2_y + (i + 1) * (m3_spacing + m3_x)), m2_arrb.ymax - i * (m2_spacing + m2_y) - m2_y, @@ -2836,20 +2681,15 @@ def draw_nfet_06v0_nvt( m2_join_u = c_inst.add_ref( gf.components.rectangle( size=( - m2_y - + (i + 1) * (m3_spacing + m3_x), + m2_y + (i + 1) * (m3_spacing + m3_x), m2_y, ), layer=m2_layer, ).move( ( m2_arru.xmin - - ( - m2_y - + (i + 1) * (m3_spacing + m3_x) - ), - m2_arru.ymin - + j * (m2_spacing + m2_y), + - (m2_y + (i + 1) * (m3_spacing + m3_x)), + m2_arru.ymin + j * (m2_spacing + m2_y), ) ) ) @@ -2901,8 +2741,7 @@ def draw_nfet_06v0_nvt( ( ( pc2.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - ((1 - j % 2) * pc1.ymin) - (j % 2) * pc2.ymin @@ -2915,14 +2754,7 @@ def draw_nfet_06v0_nvt( ( ( sd_l - - ( - ( - poly_con.xmax - - poly_con.xmin - - l - ) - / 2 - ) + - ((poly_con.xmax - poly_con.xmin - l) / 2) + j * (l + inter_sd_l) ), (1 - j % 2) * (pc1.ymin + 0.06) @@ -2933,9 +2765,7 @@ def draw_nfet_06v0_nvt( x_range=(m1.xmin, m1.xmax), y_range=( m2_arr.ymin + i * (m2_spacing + m2_y), - m2_arr.ymin - + i * (m2_spacing + m2_y) - + m2_y, + m2_arr.ymin + i * (m2_spacing + m2_y) + m2_y, ), via_enclosure=via_enc, via_layer=via1_layer, @@ -2973,8 +2803,7 @@ def draw_nfet_06v0_nvt( ( ( pc1.ymax - + (i + 1) - * (m2_spacing + m2_y) + + (i + 1) * (m2_spacing + m2_y) ) - (j % 2) * pc1.ymin - (1 - j % 2) * pc2.ymin @@ -2987,14 +2816,7 @@ def draw_nfet_06v0_nvt( ( ( sd_l - - ( - ( - poly_con.xmax - - poly_con.xmin - - l - ) - / 2 - ) + - ((poly_con.xmax - poly_con.xmin - l) / 2) + j * (l + inter_sd_l) ), -(m1.ymax - m1.ymin) @@ -3005,9 +2827,7 @@ def draw_nfet_06v0_nvt( via1_dr = via_generator( x_range=(m1.xmin, m1.xmax), y_range=( - m2_arr.ymax - - i * (m2_spacing + m2_y) - - m2_y, + m2_arr.ymax - i * (m2_spacing + m2_y) - m2_y, m2_arr.ymax - i * (m2_spacing + m2_y), ), via_enclosure=via_enc, @@ -3127,16 +2947,12 @@ def draw_nfet_06v0_nvt( layer=pplus_layer, ) ) - psdm_in.move( - (rect_bulk_in.xmin + comp_pp_enc, rect_bulk_in.ymin + comp_pp_enc) - ) + psdm_in.move((rect_bulk_in.xmin + comp_pp_enc, rect_bulk_in.ymin + comp_pp_enc)) psdm_out = c_temp.add_ref( gf.components.rectangle( size=( - (rect_bulk_out.xmax - rect_bulk_out.xmin) - + 2 * comp_pp_enc, - (rect_bulk_out.ymax - rect_bulk_out.ymin) - + 2 * comp_pp_enc, + (rect_bulk_out.xmax - rect_bulk_out.xmin) + 2 * comp_pp_enc, + (rect_bulk_out.ymax - rect_bulk_out.ymin) + 2 * comp_pp_enc, ), layer=pplus_layer, ) diff --git a/cells/klayout/pymacros/cells/draw_mos.py b/cells/klayout/pymacros/cells/draw_mos.py index 13693935..51ea8927 100644 --- a/cells/klayout/pymacros/cells/draw_mos.py +++ b/cells/klayout/pymacros/cells/draw_mos.py @@ -225,7 +225,7 @@ def draw_nfet(layout, l, w, ld, nf, grw, bulk, volt, deepnwell, pcmpgr): ) ) # Metals - + cell.shapes(metal1).insert( pya.Box( (ld + 2 * ld_violat + l + cont2ply - cmp2cont) * (i + 1) diff --git a/cells/klayout/pymacros/cells/draw_res.py b/cells/klayout/pymacros/cells/draw_res.py index 6db5b0a2..0c83123b 100644 --- a/cells/klayout/pymacros/cells/draw_res.py +++ b/cells/klayout/pymacros/cells/draw_res.py @@ -22,14 +22,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ---------- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ---------- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/cells/fet.py b/cells/klayout/pymacros/cells/fet.py index 1f05c8ba..a6dd2a9c 100644 --- a/cells/klayout/pymacros/cells/fet.py +++ b/cells/klayout/pymacros/cells/fet.py @@ -68,16 +68,22 @@ def __init__(self): "grw", self.TypeDouble, "Guard Ring Width", default=fet_grw, unit="um" ) - self.Type_handle = self.param("gate_con_pos", self.TypeList, "Gate Contact Position") + self.Type_handle = self.param( + "gate_con_pos", self.TypeList, "Gate Contact Position" + ) self.Type_handle.add_choice("top", "top") self.Type_handle.add_choice("bottom", "bottom") self.Type_handle.add_choice("alternating", "alternating") - - self.param("con_bet_fin", self.TypeBoolean, "Contact Between Fingers", default=1) + + self.param( + "con_bet_fin", self.TypeBoolean, "Contact Between Fingers", default=1 + ) self.param("sd_con_col", self.TypeInt, "Diffusion Contacts Columns", default=1) self.param("interdig", self.TypeBoolean, "Interdigitation", default=0) - self.param("patt", self.TypeString,"Pattern in case of Interdigitation", default= "") + self.param( + "patt", self.TypeString, "Pattern in case of Interdigitation", default="" + ) self.param("area", self.TypeDouble, "Area", readonly=True, unit="um^2") self.param("perim", self.TypeDouble, "Perimeter", readonly=True, unit="um") @@ -109,7 +115,7 @@ def coerce_parameters_impl(self): self.l = nfet_06v0_l if (self.w) < fet_5_6_w: self.w = fet_5_6_w - + if (self.ld) < fet_ld: self.ld = fet_ld @@ -135,20 +141,20 @@ def transformation_from_shape_impl(self): def produce_impl(self): instance = draw_nfet( self.layout, - l = self.l, - w= self.w, - sd_con_col= self.sd_con_col, - inter_sd_l= self.ld, - nf= self.nf, - grw= self.grw, - bulk= self.bulk, - volt= self.volt, - con_bet_fin= self.con_bet_fin, - gate_con_pos= self.gate_con_pos, - interdig= self.interdig, - patt= self.patt, - deepnwell= self.deepnwell, - pcmpgr= self.pcmpgr + l=self.l, + w=self.w, + sd_con_col=self.sd_con_col, + inter_sd_l=self.ld, + nf=self.nf, + grw=self.grw, + bulk=self.bulk, + volt=self.volt, + con_bet_fin=self.con_bet_fin, + gate_con_pos=self.gate_con_pos, + interdig=self.interdig, + patt=self.patt, + deepnwell=self.deepnwell, + pcmpgr=self.pcmpgr, ) write_cells = pya.CellInstArray( instance.cell_index(), @@ -191,16 +197,22 @@ def __init__(self): "grw", self.TypeDouble, "Guard Ring Width", default=fet_grw, unit="um" ) - self.Type_handle = self.param("gate_con_pos", self.TypeList, "Gate Contact Position") + self.Type_handle = self.param( + "gate_con_pos", self.TypeList, "Gate Contact Position" + ) self.Type_handle.add_choice("top", "top") self.Type_handle.add_choice("bottom", "bottom") self.Type_handle.add_choice("alternating", "alternating") - - self.param("con_bet_fin", self.TypeBoolean, "Contact Between Fingers", default=1) + + self.param( + "con_bet_fin", self.TypeBoolean, "Contact Between Fingers", default=1 + ) self.param("sd_con_col", self.TypeInt, "Diffusion Contacts Columns", default=1) self.param("interdig", self.TypeBoolean, "Interdigitation", default=0) - self.param("patt", self.TypeString,"Pattern in case of Interdigitation", default= "") + self.param( + "patt", self.TypeString, "Pattern in case of Interdigitation", default="" + ) self.param("area", self.TypeDouble, "Area", readonly=True, unit="um^2") self.param("perim", self.TypeDouble, "Perimeter", readonly=True, unit="um") @@ -258,20 +270,20 @@ def transformation_from_shape_impl(self): def produce_impl(self): instance = draw_pfet( self.layout, - l = self.l, - w= self.w, - sd_con_col= self.sd_con_col, - inter_sd_l= self.ld, - nf= self.nf, - grw= self.grw, - bulk= self.bulk, - volt= self.volt, - con_bet_fin= self.con_bet_fin, - gate_con_pos= self.gate_con_pos, - interdig= self.interdig, - patt= self.patt, - deepnwell= self.deepnwell, - pcmpgr= self.pcmpgr + l=self.l, + w=self.w, + sd_con_col=self.sd_con_col, + inter_sd_l=self.ld, + nf=self.nf, + grw=self.grw, + bulk=self.bulk, + volt=self.volt, + con_bet_fin=self.con_bet_fin, + gate_con_pos=self.gate_con_pos, + interdig=self.interdig, + patt=self.patt, + deepnwell=self.deepnwell, + pcmpgr=self.pcmpgr, ) write_cells = pya.CellInstArray( instance.cell_index(), @@ -308,16 +320,22 @@ def __init__(self): "grw", self.TypeDouble, "Guard Ring Width", default=fet_grw, unit="um" ) - self.Type_handle = self.param("gate_con_pos", self.TypeList, "Gate Contact Position") + self.Type_handle = self.param( + "gate_con_pos", self.TypeList, "Gate Contact Position" + ) self.Type_handle.add_choice("top", "top") self.Type_handle.add_choice("bottom", "bottom") self.Type_handle.add_choice("alternating", "alternating") - - self.param("con_bet_fin", self.TypeBoolean, "Contact Between Fingers", default=1) + + self.param( + "con_bet_fin", self.TypeBoolean, "Contact Between Fingers", default=1 + ) self.param("sd_con_col", self.TypeInt, "Diffusion Contacts Columns", default=1) self.param("interdig", self.TypeBoolean, "Interdigitation", default=0) - self.param("patt", self.TypeString,"Pattern in case of Interdigitation", default= "") + self.param( + "patt", self.TypeString, "Pattern in case of Interdigitation", default="" + ) self.param("area", self.TypeDouble, "Area", readonly=True, unit="um^2") self.param("perim", self.TypeDouble, "Perimeter", readonly=True, unit="um") @@ -365,19 +383,19 @@ def transformation_from_shape_impl(self): def produce_impl(self): instance = draw_nfet_06v0_nvt( self.layout, - l = self.l, - w= self.w, - sd_con_col= self.sd_con_col, - inter_sd_l= self.ld, - nf= self.nf, - grw= self.grw, - bulk= self.bulk, - con_bet_fin= self.con_bet_fin, - gate_con_pos= self.gate_con_pos, - interdig= self.interdig, - patt= self.patt, + l=self.l, + w=self.w, + sd_con_col=self.sd_con_col, + inter_sd_l=self.ld, + nf=self.nf, + grw=self.grw, + bulk=self.bulk, + con_bet_fin=self.con_bet_fin, + gate_con_pos=self.gate_con_pos, + interdig=self.interdig, + patt=self.patt, ) - + write_cells = pya.CellInstArray( instance.cell_index(), pya.Trans(pya.Point(0, 0)), @@ -388,4 +406,3 @@ def produce_impl(self): ) self.cell.insert(write_cells) self.cell.flatten(1) - diff --git a/cells/klayout/pymacros/cells/layers_def.py b/cells/klayout/pymacros/cells/layers_def.py index ee0f14a2..94feece8 100644 --- a/cells/klayout/pymacros/cells/layers_def.py +++ b/cells/klayout/pymacros/cells/layers_def.py @@ -18,19 +18,19 @@ from gdsfactory.types import LayerSpec -comp_layer : LayerSpec = (22 , 0 ) -poly2_layer: LayerSpec = (30 , 0 ) -nplus_layer: LayerSpec = (32 , 0 ) -pplus_layer: LayerSpec = (31 , 0 ) -contact_layer : LayerSpec = (33 , 0 ) -metal1_layer: LayerSpec = (34 , 0 ) -dnwell_layer : LayerSpec = (12 , 0 ) -lvpwell_layer : LayerSpec = (204, 0 ) -dualgate_layer: LayerSpec = (55 , 0 ) -v5_xtor_layer : LayerSpec = (112, 1 ) -m1_layer : LayerSpec = (34 , 0 ) -m2_layer : LayerSpec = (36 , 0 ) -m1_lbl : LayerSpec = (34 , 10) -via1_layer : LayerSpec =(35 , 0 ) -nwell_layer : LayerSpec = (21 , 0 ) -nat_layer : LayerSpec = (5, 0) +comp_layer: LayerSpec = (22, 0) +poly2_layer: LayerSpec = (30, 0) +nplus_layer: LayerSpec = (32, 0) +pplus_layer: LayerSpec = (31, 0) +contact_layer: LayerSpec = (33, 0) +metal1_layer: LayerSpec = (34, 0) +dnwell_layer: LayerSpec = (12, 0) +lvpwell_layer: LayerSpec = (204, 0) +dualgate_layer: LayerSpec = (55, 0) +v5_xtor_layer: LayerSpec = (112, 1) +m1_layer: LayerSpec = (34, 0) +m2_layer: LayerSpec = (36, 0) +m1_lbl: LayerSpec = (34, 10) +via1_layer: LayerSpec = (35, 0) +nwell_layer: LayerSpec = (21, 0) +nat_layer: LayerSpec = (5, 0) diff --git a/cells/klayout/pymacros/cells/via_generator.py b/cells/klayout/pymacros/cells/via_generator.py index ed38ff35..d93840b0 100644 --- a/cells/klayout/pymacros/cells/via_generator.py +++ b/cells/klayout/pymacros/cells/via_generator.py @@ -1,15 +1,15 @@ -# Copyright 2022 Skywater 130nm pdk development +# Copyright 2022 Skywater 130nm pdk development # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . @@ -20,71 +20,70 @@ from math import ceil, floor import gdsfactory as gf -from gdsfactory.types import Float2 , LayerSpec +from gdsfactory.types import Float2, LayerSpec from layers_def import * + @gf.cell def via_generator( - x_range : Float2 = (0,1) , - y_range : Float2 = (0,1) , - via_size : Float2 = (0.17,0.17), - via_layer : LayerSpec = (66,44), - via_enclosure : Float2 = (0.06,0.06), - via_spacing : Float2 = (0.17,0.17) - - + x_range: Float2 = (0, 1), + y_range: Float2 = (0, 1), + via_size: Float2 = (0.17, 0.17), + via_layer: LayerSpec = (66, 44), + via_enclosure: Float2 = (0.06, 0.06), + via_spacing: Float2 = (0.17, 0.17), ) -> gf.Component(): - + """ - return only vias withen the range xrange and yrange while enclosing by via_enclosure - and set number of rows and number of coloumns according to ranges and via size and spacing + return only vias withen the range xrange and yrange while enclosing by via_enclosure + and set number of rows and number of coloumns according to ranges and via size and spacing """ - + c = gf.Component() width = x_range[1] - x_range[0] length = y_range[1] - y_range[0] nr = floor(length / (via_size[1] + via_spacing[1])) - if (length - nr*via_size[1] - (nr-1)*via_spacing[1])/2 < via_enclosure[1]: + if (length - nr * via_size[1] - (nr - 1) * via_spacing[1]) / 2 < via_enclosure[1]: nr -= 1 - if nr <1 : + if nr < 1: nr = 1 - - nc = ceil(width / (via_size[0]+via_spacing[0])) - - if (round(width - nc*via_size[0] - (nc-1)*via_spacing[0],2))/2 < via_enclosure[0]: + nc = ceil(width / (via_size[0] + via_spacing[0])) + + if ( + round(width - nc * via_size[0] - (nc - 1) * via_spacing[0], 2) + ) / 2 < via_enclosure[0]: nc -= 1 - - if nc<1 : - nc =1 - - via_sp = (via_size[0]+via_spacing[0],via_size[1]+via_spacing[1]) + if nc < 1: + nc = 1 - rect_via = gf.components.rectangle(size = via_size , layer= via_layer) + via_sp = (via_size[0] + via_spacing[0], via_size[1] + via_spacing[1]) - via_arr = c.add_array(rect_via, rows= nr, columns= nc , spacing=via_sp) + rect_via = gf.components.rectangle(size=via_size, layer=via_layer) - via_arr.move((x_range[0],y_range[0])) + via_arr = c.add_array(rect_via, rows=nr, columns=nc, spacing=via_sp) - via_arr.movex((width - nc*via_size[0] - (nc-1)*via_spacing[0])/2) - via_arr.movey((length - nr*via_size[1] - (nr-1)*via_spacing[1])/2) + via_arr.move((x_range[0], y_range[0])) + + via_arr.movex((width - nc * via_size[0] - (nc - 1) * via_spacing[0]) / 2) + via_arr.movey((length - nr * via_size[1] - (nr - 1) * via_spacing[1]) / 2) return c -@gf.cell -def via_stack ( - x_range : Float2 = (0,1), - y_range : Float2 = (0,1), - base_layer : LayerSpec = comp_layer, - slotted_licon : int = 0, - metal_level : int = 1, - li_enc_dir = "V" -) -> gf.Component : +@gf.cell +def via_stack( + x_range: Float2 = (0, 1), + y_range: Float2 = (0, 1), + base_layer: LayerSpec = comp_layer, + slotted_licon: int = 0, + metal_level: int = 1, + li_enc_dir="V", +) -> gf.Component: """ return via stack till the metal level indicated where : @@ -93,92 +92,97 @@ def via_stack ( metal_level 3 : till m3 metal_level 4 : till m4 metal_level 5 : till m5 - withen the range xrange and yrange and expecting the base_layer to be drawen + withen the range xrange and yrange and expecting the base_layer to be drawen """ c = gf.Component() - # vias dimensions + # vias dimensions - con_size = (0.22,0.22) + con_size = (0.22, 0.22) con_enc = 0.07 m_enc = 0.06 - # if base_layer == diff_layer or base_layer == tap_layer : # con_enc = (0.06,0.06) - + # #elif base_layer == tap_layer: # # con_enc = (0.1,0.06) - # elif base_layer == poly_layer : # con_enc = (0.05,0.08) - # npc_enc = 0.01 + # npc_enc = 0.01 # npc = c.add_ref(gf.components.rectangle(size=(x_range[1]-x_range[0]+2*npc_enc, y_range[1]-y_range[0]+2*npc_enc),layer=npc_layer)) # npc.move((x_range[0]-npc_enc, y_range[0]-npc_enc)) - - # else : - # pass + # else : + # pass - con_spacing = (0.28,0.28) + con_spacing = (0.28, 0.28) - via_size = (0.22,0.22) - via_spacing = (0.28,0.28) - via_enc = (0.06,0.06) + via_size = (0.22, 0.22) + via_spacing = (0.28, 0.28) + via_enc = (0.06, 0.06) + if metal_level >= 1: + con_gen = via_generator( + x_range=x_range, + y_range=y_range, + via_size=con_size, + via_enclosure=(con_enc, con_enc), + via_layer=contact_layer, + via_spacing=con_spacing, + ) + con = c.add_ref(con_gen) - if metal_level >= 1 : - con_gen = via_generator(x_range=x_range,y_range=y_range,via_size=con_size,via_enclosure=(con_enc,con_enc),via_layer=contact_layer,via_spacing=con_spacing) - con = c.add_ref(con_gen) - - - m1_x = con.size[0] + 2*m_enc - - m1_y = con.size[1] + 2*m_enc + m1_x = con.size[0] + 2 * m_enc - m1 = c.add_ref(gf.components.rectangle(size=(m1_x,m1_y),layer=m1_layer)) + m1_y = con.size[1] + 2 * m_enc + + m1 = c.add_ref(gf.components.rectangle(size=(m1_x, m1_y), layer=m1_layer)) m1.xmin = con.xmin - m_enc m1.ymin = con.ymin - m_enc - if metal_level >=2 : - via1_gen = via_generator(x_range= (m1.xmin, m1.xmax), y_range=(m1.ymin,m1.ymax),via_size=via_size,via_enclosure=via_enc - ,via_layer=via1_layer,via_spacing=via_spacing) + if metal_level >= 2: + via1_gen = via_generator( + x_range=(m1.xmin, m1.xmax), + y_range=(m1.ymin, m1.ymax), + via_size=via_size, + via_enclosure=via_enc, + via_layer=via1_layer, + via_spacing=via_spacing, + ) via1 = c.add_ref(via1_gen) - - if (via1.xmax-via1.xmin + 2*m_enc[0]) < (via_size[0] + 2*via_enc[0]) and metal_level >=3: - m2_x = via_size[0] + 2*via_enc[0] - + if (via1.xmax - via1.xmin + 2 * m_enc[0]) < ( + via_size[0] + 2 * via_enc[0] + ) and metal_level >= 3: + m2_x = via_size[0] + 2 * via_enc[0] - else : - m2_x = via1.xmax-via1.xmin + 2*m_enc[0] - + else: + m2_x = via1.xmax - via1.xmin + 2 * m_enc[0] - if (via1.ymax-via1.ymin + 2*m_enc[1]) < (via_size[1] + 2*via_enc[1]) and metal_level >=3: - m2_y = via_size[1] + 2*via_enc[1] - + if (via1.ymax - via1.ymin + 2 * m_enc[1]) < ( + via_size[1] + 2 * via_enc[1] + ) and metal_level >= 3: + m2_y = via_size[1] + 2 * via_enc[1] - else : - m2_y = via1.ymax-via1.ymin + 2*m_enc[1] - - m2_mx = (m2_x - (via1.xmax - via1.xmin))/2 - m2_my = (m2_y - (via1.ymax - via1.ymin))/2 + else: + m2_y = via1.ymax - via1.ymin + 2 * m_enc[1] - m2 = c.add_ref(gf.components.rectangle(size=(m2_x,m2_y),layer=m2_layer)) - m2.move((via1.xmin - m2_mx, via1.ymin -m2_my)) - + m2_mx = (m2_x - (via1.xmax - via1.xmin)) / 2 + m2_my = (m2_y - (via1.ymax - via1.ymin)) / 2 - return c + m2 = c.add_ref(gf.components.rectangle(size=(m2_x, m2_y), layer=m2_layer)) + m2.move((via1.xmin - m2_mx, via1.ymin - m2_my)) + return c -# testing the generated methods +# testing the generated methods if __name__ == "__main__": c = via_stack() c.show() # c = vias_gen_draw(start_layer="li",end_layer="poly") # c.show() - \ No newline at end of file diff --git a/cells/klayout/pymacros/testing/cells/bjt.py b/cells/klayout/pymacros/testing/cells/bjt.py index c7c96bb0..d3e82ec1 100644 --- a/cells/klayout/pymacros/testing/cells/bjt.py +++ b/cells/klayout/pymacros/testing/cells/bjt.py @@ -29,7 +29,9 @@ def __init__(self): # Important: initialize the super class super(npn_bjt, self).__init__() - self.Type_handle = self.param("Type", self.TypeList, "Type", default= "npn_10p00x10p00") + self.Type_handle = self.param( + "Type", self.TypeList, "Type", default="npn_10p00x10p00" + ) self.Type_handle.add_choice("npn_10p00x10p00", "npn_10p00x10p00") self.Type_handle.add_choice("npn_05p00x05p00", "npn_05p00x05p00") self.Type_handle.add_choice("npn_00p54x16p00", "npn_00p54x16p00") @@ -98,7 +100,9 @@ def __init__(self): # Important: initialize the super class super(pnp_bjt, self).__init__() - self.Type_handle = self.param("Type", self.TypeList, "Type", default= "pnp_10p00x10p00") + self.Type_handle = self.param( + "Type", self.TypeList, "Type", default="pnp_10p00x10p00" + ) self.Type_handle.add_choice("pnp_10p00x10p00", "pnp_10p00x10p00") self.Type_handle.add_choice("pnp_05p00x05p00", "pnp_05p00x05p00") self.Type_handle.add_choice("pnp_10p00x00p42", "pnp_10p00x00p42") diff --git a/cells/klayout/pymacros/testing/cells/draw_bjt.py b/cells/klayout/pymacros/testing/cells/draw_bjt.py index 81fb5728..f16f284c 100644 --- a/cells/klayout/pymacros/testing/cells/draw_bjt.py +++ b/cells/klayout/pymacros/testing/cells/draw_bjt.py @@ -28,6 +28,6 @@ def draw_bjt(layout, device_name): if os.path.exists(gds_file) and os.path.isfile(gds_file): layout.read(gds_file) else: - print (f"{gds_file} is not exist, please recheck") + print(f"{gds_file} is not exist, please recheck") return layout.cell(device_name) diff --git a/cells/klayout/pymacros/testing/cells/draw_cap_mim.py b/cells/klayout/pymacros/testing/cells/draw_cap_mim.py index 70db8990..7f51395c 100644 --- a/cells/klayout/pymacros/testing/cells/draw_cap_mim.py +++ b/cells/klayout/pymacros/testing/cells/draw_cap_mim.py @@ -20,14 +20,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ---------- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ---------- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/testing/cells/draw_cap_mos.py b/cells/klayout/pymacros/testing/cells/draw_cap_mos.py index 111dd4e6..4d1055d0 100644 --- a/cells/klayout/pymacros/testing/cells/draw_cap_mos.py +++ b/cells/klayout/pymacros/testing/cells/draw_cap_mos.py @@ -20,14 +20,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ---------- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ---------- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/testing/cells/draw_diode.py b/cells/klayout/pymacros/testing/cells/draw_diode.py index 631d19a8..d549cdad 100644 --- a/cells/klayout/pymacros/testing/cells/draw_diode.py +++ b/cells/klayout/pymacros/testing/cells/draw_diode.py @@ -20,14 +20,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ----- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ----- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/testing/cells/draw_fet.py b/cells/klayout/pymacros/testing/cells/draw_fet.py index 76eba4dd..b6ccec5c 100644 --- a/cells/klayout/pymacros/testing/cells/draw_fet.py +++ b/cells/klayout/pymacros/testing/cells/draw_fet.py @@ -225,7 +225,7 @@ def draw_nfet(layout, l, w, ld, nf, grw, bulk, volt, deepnwell, pcmpgr): ) ) # Metals - + cell.shapes(metal1).insert( pya.Box( (ld + 2 * ld_violat + l + cont2ply - cmp2cont) * (i + 1) diff --git a/cells/klayout/pymacros/testing/cells/draw_mos.py b/cells/klayout/pymacros/testing/cells/draw_mos.py index 13693935..51ea8927 100644 --- a/cells/klayout/pymacros/testing/cells/draw_mos.py +++ b/cells/klayout/pymacros/testing/cells/draw_mos.py @@ -225,7 +225,7 @@ def draw_nfet(layout, l, w, ld, nf, grw, bulk, volt, deepnwell, pcmpgr): ) ) # Metals - + cell.shapes(metal1).insert( pya.Box( (ld + 2 * ld_violat + l + cont2ply - cmp2cont) * (i + 1) diff --git a/cells/klayout/pymacros/testing/cells/draw_res.py b/cells/klayout/pymacros/testing/cells/draw_res.py index 6db5b0a2..0c83123b 100644 --- a/cells/klayout/pymacros/testing/cells/draw_res.py +++ b/cells/klayout/pymacros/testing/cells/draw_res.py @@ -22,14 +22,14 @@ def number_spc_contacts(box_width, min_enc, cont_spacing, cont_width): - """ Calculate number of cantacts in a given dimensions and the free space for symmetry. - By getting the min enclosure,the width of the box,the width ans spacing of the contacts. - Parameters - ---------- - box_width (double) : length you place the via or cont. in - min_enc (double) : spacing between the edge of the box and the first contact. - cont_spacing (double) : spacing between different contacts - cont_width (double) : contacts in the same direction + """Calculate number of cantacts in a given dimensions and the free space for symmetry. + By getting the min enclosure,the width of the box,the width ans spacing of the contacts. + Parameters + ---------- + box_width (double) : length you place the via or cont. in + min_enc (double) : spacing between the edge of the box and the first contact. + cont_spacing (double) : spacing between different contacts + cont_width (double) : contacts in the same direction """ spc_cont = box_width - 2 * min_enc num_cont = int((spc_cont + cont_spacing) / (cont_width + cont_spacing)) diff --git a/cells/klayout/pymacros/testing/cells/fet.py b/cells/klayout/pymacros/testing/cells/fet.py index 6cb8e733..2a449ad0 100644 --- a/cells/klayout/pymacros/testing/cells/fet.py +++ b/cells/klayout/pymacros/testing/cells/fet.py @@ -97,7 +97,7 @@ def coerce_parameters_impl(self): self.l = nfet_06v0_l if (self.w) < fet_5_6_w: self.w = fet_5_6_w - + if (self.ld) < fet_ld: self.ld = fet_ld diff --git a/models/ngspice/testing/regression/bjt_beta/models_regression.py b/models/ngspice/testing/regression/bjt_beta/models_regression.py index 8ce18455..6affa111 100644 --- a/models/ngspice/testing/regression/bjt_beta/models_regression.py +++ b/models/ngspice/testing/regression/bjt_beta/models_regression.py @@ -54,7 +54,9 @@ def call_simulator(file_name: str): return os.system(f"ngspice -b -a {file_name} -o {file_name}.log > {file_name}.log") -def ext_npn_measured(dev_data_path: str, device: str, devices: list[str], dev_path: str) -> pd.DataFrame: +def ext_npn_measured( + dev_data_path: str, device: str, devices: list[str], dev_path: str +) -> pd.DataFrame: """Extract measured values from excel file. Args: dev_data_path (str): Path to excel file. @@ -164,7 +166,9 @@ def ext_npn_measured(dev_data_path: str, device: str, devices: list[str], dev_pa return df -def ext_pnp_measured(dev_data_path: str, device: str, devices: list[str], dev_path: str) -> pd.DataFrame: +def ext_pnp_measured( + dev_data_path: str, device: str, devices: list[str], dev_path: str +) -> pd.DataFrame: """Extract measured values from excel file. Args: dev_data_path (str): Path to excel file. @@ -334,7 +338,9 @@ def run_sim(char: str, dirpath: str, device: str, temp: float) -> dict: return info -def run_sims(char: str, df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + char: str, df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """Run simulations. Args: char (str): ib or ic to simulate. @@ -421,7 +427,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup pd.set_option("display.max_columns", None) @@ -527,8 +535,8 @@ def main(): result_data = simulated_data.merge(measured_data, how="left") ## We found that most of the curr are in the range of milli-Amps and most of the - ## error happens in the off mode of the BJT. And it causes large rmse for the values. - ## We will clip at 5nA for all currents to make sure that for small signal it works as expected. + ## error happens in the off mode of the BJT. And it causes large rmse for the values. + ## We will clip at 5nA for all currents to make sure that for small signal it works as expected. # Clipping all the values to lowest_curr lowest_curr = 5.0e-9 diff --git a/models/ngspice/testing/regression/bjt_cj/models_regression.py b/models/ngspice/testing/regression/bjt_cj/models_regression.py index 1e7b127a..551c1b85 100644 --- a/models/ngspice/testing/regression/bjt_cj/models_regression.py +++ b/models/ngspice/testing/regression/bjt_cj/models_regression.py @@ -415,7 +415,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup diff --git a/models/ngspice/testing/regression/bjt_iv/models_regression.py b/models/ngspice/testing/regression/bjt_iv/models_regression.py index e4650955..fbe415b0 100644 --- a/models/ngspice/testing/regression/bjt_iv/models_regression.py +++ b/models/ngspice/testing/regression/bjt_iv/models_regression.py @@ -525,7 +525,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup diff --git a/models/ngspice/testing/regression/diode/models_regression.py b/models/ngspice/testing/regression/diode/models_regression.py index ee27f744..562dcdd3 100644 --- a/models/ngspice/testing/regression/diode/models_regression.py +++ b/models/ngspice/testing/regression/diode/models_regression.py @@ -58,7 +58,9 @@ def call_simulator(file_name: str) -> int: return os.system(f"ngspice -b -a {file_name} -o {file_name}.log > {file_name}.log") -def ext_cv_measured(dev_data_path: str, device: str, corners: str, dev_path: str) -> pd.DataFrame: +def ext_cv_measured( + dev_data_path: str, device: str, corners: str, dev_path: str +) -> pd.DataFrame: """Extract measured data from csv file. Args: dev_data_path (str): Path to csv file. @@ -71,9 +73,9 @@ def ext_cv_measured(dev_data_path: str, device: str, corners: str, dev_path: str # Read Data df = pd.read_excel(dev_data_path) - dim_df = df[["Area" , "Pj"]].copy() + dim_df = df[["Area", "Pj"]].copy() dim_df.rename( - columns={"Area": "area" , "Pj": "perim"}, + columns={"Area": "area", "Pj": "perim"}, inplace=True, ) @@ -144,7 +146,7 @@ def ext_cv_measured(dev_data_path: str, device: str, corners: str, dev_path: str temp_list.append(temp) corner_list.append(corner) meas_list.append(f"{dev_path}/measured_cv/{meas_csv}") - + sdf = { "perim": perim_list, "area": area_list, @@ -160,11 +162,13 @@ def ext_cv_measured(dev_data_path: str, device: str, corners: str, dev_path: str df.drop_duplicates(inplace=True) df["device"] = device df = df[["device", "perim", "area", "temp", "corner", "diode_measured"]] - + return df -def ext_iv_measured(dev_data_path: str, device: str, corners: str, dev_path: str) -> pd.DataFrame: +def ext_iv_measured( + dev_data_path: str, device: str, corners: str, dev_path: str +) -> pd.DataFrame: """Extract measured data from csv file. Args: dev_data_path (str): Path to csv file. @@ -178,9 +182,9 @@ def ext_iv_measured(dev_data_path: str, device: str, corners: str, dev_path: str # Read Data df = pd.read_excel(dev_data_path) - dim_df = df[["Area" , "Pj"]].copy() + dim_df = df[["Area", "Pj"]].copy() dim_df.rename( - columns={"Area": "area" , "Pj": "perim"}, + columns={"Area": "area", "Pj": "perim"}, inplace=True, ) @@ -257,7 +261,15 @@ def ext_iv_measured(dev_data_path: str, device: str, corners: str, dev_path: str return df -def run_sim(char: str, dirpath: str, device: str, perim: float, area: float, corner: str, temp: float) -> dict: +def run_sim( + char: str, + dirpath: str, + device: str, + perim: float, + area: float, + corner: str, + temp: float, +) -> dict: """Run simulation. Args: char (str): Characteristic. @@ -319,7 +331,9 @@ def run_sim(char: str, dirpath: str, device: str, perim: float, area: float, cor return info -def run_sims(char: str, df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + char: str, df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """Run simulations. Args: char (str): Characteristic. @@ -352,9 +366,9 @@ def run_sims(char: str, df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count results.append(data) except Exception as exc: logging.info("Test case generated an exception: %s" % (exc)) - + # stored simulated data files - sf = glob.glob(f"{dirpath}/*_netlists_{char}/*.csv") + sf = glob.glob(f"{dirpath}/*_netlists_{char}/*.csv") for i in range(len(sf)): sdf = pd.read_csv( sf[i], @@ -376,8 +390,7 @@ def run_sims(char: str, df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count def main(): - """Main function. - """ + """Main function.""" # ======= Checking ngspice ======= ngspice_v_ = os.popen("ngspice -v").read() @@ -388,7 +401,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup @@ -414,7 +429,7 @@ def main(): "sc_diode", ] - char_measured = ["iv" , "cv"] + char_measured = ["iv", "cv"] for i, dev in enumerate(devices): dev_path = f"{main_regr_dir}/{dev}" @@ -456,17 +471,20 @@ def main(): meas_df = meas_func(diode_file, dev, corners, dev_path) else: meas_df = [] - - meas_len = len(pd.read_csv(glob.glob(f"{dev_path}/measured_{char}/*.csv")[1])) - + + meas_len = len( + pd.read_csv(glob.glob(f"{dev_path}/measured_{char}/*.csv")[1]) + ) + logging.info( f"# Device {dev} number of {char}_measured_datapoints : {len(meas_df) * meas_len}" ) sim_df = run_sims(char, meas_df, dev_path, workers_count) - - sim_len = len(pd.read_csv(glob.glob(f"{dev_path}/*_netlists_{char}/*.csv")[1])) + sim_len = len( + pd.read_csv(glob.glob(f"{dev_path}/*_netlists_{char}/*.csv")[1]) + ) logging.info( f"# Device {dev} number of {char}_simulated datapoints : {len(sim_df) * sim_len}" ) @@ -475,7 +493,7 @@ def main(): merged_df = meas_df.merge( sim_df, on=["device", "corner", "perim", "area", "temp"], how="left" ) - + merged_dfs = [] # create a new dataframe for rms error rms_df = pd.DataFrame( diff --git a/models/ngspice/testing/regression/mimcap_c/models_regression.py b/models/ngspice/testing/regression/mimcap_c/models_regression.py index 6fa8a1fb..d43c098f 100644 --- a/models/ngspice/testing/regression/mimcap_c/models_regression.py +++ b/models/ngspice/testing/regression/mimcap_c/models_regression.py @@ -57,11 +57,11 @@ def find_mimcap(filename): with open(filename) as log: log_data = log.readlines() - - cap_val = 0 + + cap_val = 0 for line in log_data: if "cv" in line: - cap_val = float (line.split("=")[1]) + cap_val = float(line.split("=")[1]) return cap_val @@ -90,60 +90,74 @@ def ext_measured(dev_data_path, device): }, inplace=True, ) - idf["length"] = df["Unnamed: 2"].apply(lambda x: str(x).split("(")[1].split("x")[0].split("u")[0]) - idf["width"] = df["Unnamed: 2"].apply(lambda x: str(x).split("(")[1].split("x")[1].split("u")[0]) - + idf["length"] = df["Unnamed: 2"].apply( + lambda x: str(x).split("(")[1].split("x")[0].split("u")[0] + ) + idf["width"] = df["Unnamed: 2"].apply( + lambda x: str(x).split("(")[1].split("x")[1].split("u")[0] + ) + # Get device names from measured data - idf["device"] = df["Unnamed: 2"].apply(lambda x: str(x).split("(")[0].replace("\n", "")) - + idf["device"] = df["Unnamed: 2"].apply( + lambda x: str(x).split("(")[0].replace("\n", "") + ) + # Renaming mim devices with its new names - idf["device"] = idf["device"].apply(lambda x: str(x).replace("mim_1p5fF", "cap_mim_1f5")) - idf["device"] = idf["device"].apply(lambda x: str(x).replace("mim_1p0fF", "cap_mim_1f0")) - idf["device"] = idf["device"].apply(lambda x: str(x).replace("mim_2p0fF", "cap_mim_2f0")) + idf["device"] = idf["device"].apply( + lambda x: str(x).replace("mim_1p5fF", "cap_mim_1f5") + ) + idf["device"] = idf["device"].apply( + lambda x: str(x).replace("mim_1p0fF", "cap_mim_1f0") + ) + idf["device"] = idf["device"].apply( + lambda x: str(x).replace("mim_2p0fF", "cap_mim_2f0") + ) # Adding mim varaints depending on stack option [mim-A , mim-B] # MIM-A is allowed only for M2-M3 # MIM-B is allowed for M3-M4 , M4-M5 , M5-M6 - idf["device"] = idf["device"].apply(lambda x: f"{str(x)}_{device}" ) - + idf["device"] = idf["device"].apply(lambda x: f"{str(x)}_{device}") + corners = [] temps = [] - for i in range(0,loops): + for i in range(0, loops): # Corner & temp selection based on measured data - if i in range (0,corner_count): + if i in range(0, corner_count): corner = "ss" - if i in range (0,temp_count): + if i in range(0, temp_count): temp = 25 - elif i in range (temp_count, 2*temp_count): + elif i in range(temp_count, 2 * temp_count): temp = -40 else: - temp = 175 - elif i in range (corner_count, 2*corner_count): + temp = 175 + elif i in range(corner_count, 2 * corner_count): corner = "typical" - if i in range (corner_count,corner_count+temp_count): + if i in range(corner_count, corner_count + temp_count): temp = 25 - elif i in range (corner_count+temp_count, corner_count+2*temp_count): + elif i in range(corner_count + temp_count, corner_count + 2 * temp_count): temp = -40 else: - temp = 175 - elif i in range (2*corner_count, 3*corner_count): + temp = 175 + elif i in range(2 * corner_count, 3 * corner_count): corner = "ff" - if i in range (2*corner_count,2*corner_count+temp_count): + if i in range(2 * corner_count, 2 * corner_count + temp_count): temp = 25 - elif i in range (2*corner_count+temp_count, 2*corner_count+2*temp_count): + elif i in range( + 2 * corner_count + temp_count, 2 * corner_count + 2 * temp_count + ): temp = -40 else: - temp = 175 + temp = 175 else: - corner = "typical" #Default - temp = 25 #Default - + corner = "typical" # Default + temp = 25 # Default + corners.append(corner) temps.append(temp) idf["corner"] = corners idf["temp"] = temps - + idf.dropna(axis=0, inplace=True) idf.drop_duplicates(inplace=True) idf = idf[["device", "corner", "length", "width", "temp", "mimcap_measured"]] @@ -161,7 +175,9 @@ def run_sim(dirpath, device, length, width, corner, temp): info["width"] = width info["length"] = length - netlist_path = f"{dirpath}/{device}_netlists/netlist_w{width}_l{length}_t{temp}_{corner}.spice" + netlist_path = ( + f"{dirpath}/{device}_netlists/netlist_w{width}_l{length}_t{temp}_{corner}.spice" + ) with open(netlist_tmp) as f: tmpl = Template(f.read()) @@ -187,7 +203,7 @@ def run_sim(dirpath, device, length, width, corner, temp): except Exception as exec: mim = 0.0 - print (exec) + print(exec) except Exception: mim = 0.0 @@ -239,7 +255,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup @@ -285,10 +303,14 @@ def main(): else: meas_df = [] - logging.info(f"# Device MIM {dev} number of measured_datapoints : {len(meas_df)}") + logging.info( + f"# Device MIM {dev} number of measured_datapoints : {len(meas_df)}" + ) sim_df = run_sims(meas_df, dev_path, workers_count) - logging.info(f"# Device MIM {dev} number of simulated datapoints :{len(sim_df)}") + logging.info( + f"# Device MIM {dev} number of simulated datapoints :{len(sim_df)}" + ) merged_df = meas_df.merge( sim_df, on=["device", "corner", "length", "width", "temp"], how="left" diff --git a/models/ngspice/testing/regression/mos_cv/models_regression.py b/models/ngspice/testing/regression/mos_cv/models_regression.py index 78c0e6de..1494bc1a 100644 --- a/models/ngspice/testing/regression/mos_cv/models_regression.py +++ b/models/ngspice/testing/regression/mos_cv/models_regression.py @@ -38,10 +38,10 @@ comp_cont_spc_gate_v3_3 = 0.15 # COMP overlap of contact V3.3 -comp_enc_cont_v3_3 = 0.07 +comp_enc_cont_v3_3 = 0.07 # Min/max contact size V3.3 -cont_min_size_v3_3 = 0.22 +cont_min_size_v3_3 = 0.22 # Space from COMP contact to Poly2 on COMP V5 comp_cont_spc_gate_v5_0 = 0.15 @@ -52,8 +52,10 @@ # Min/max contact size V5 cont_min_size_v5_0 = 0.2 -ld = {"v3_3": comp_cont_spc_gate_v3_3 + comp_enc_cont_v3_3 + cont_min_size_v3_3, - "v5_0": comp_cont_spc_gate_v5_0 + comp_enc_cont_v5_0 + cont_min_size_v5_0} +ld = { + "v3_3": comp_cont_spc_gate_v3_3 + comp_enc_cont_v3_3 + cont_min_size_v3_3, + "v5_0": comp_cont_spc_gate_v5_0 + comp_enc_cont_v5_0 + cont_min_size_v5_0, +} MOS = [0, -0.825, -1.65, -2.475, -3.3] PMOS3P3_VBS = ["-0", 0.825, 1.65, 2.475, 3.3] @@ -458,7 +460,9 @@ def run_sim(dirpath: str, device: str, width: float, length: float, nf: int) -> return info -def run_sims(df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """passing netlists to run_sim function and storing the results csv files into dataframes @@ -812,7 +816,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup diff --git a/models/ngspice/testing/regression/mos_iv_vbs/models_regression.py b/models/ngspice/testing/regression/mos_iv_vbs/models_regression.py index 0821f3c3..148f59c7 100644 --- a/models/ngspice/testing/regression/mos_iv_vbs/models_regression.py +++ b/models/ngspice/testing/regression/mos_iv_vbs/models_regression.py @@ -351,7 +351,9 @@ def run_sim(dirpath: str, device: str, width: float, length: float, temp=25) -> return info -def run_sims(df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """passing netlists to run_sim function and storing the results csv files into dataframes @@ -571,7 +573,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup diff --git a/models/ngspice/testing/regression/mos_iv_vgs/models_regression.py b/models/ngspice/testing/regression/mos_iv_vgs/models_regression.py index c3b731b2..052c3aaf 100644 --- a/models/ngspice/testing/regression/mos_iv_vgs/models_regression.py +++ b/models/ngspice/testing/regression/mos_iv_vgs/models_regression.py @@ -658,7 +658,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup diff --git a/models/ngspice/testing/regression/moscap_c/models_regression.py b/models/ngspice/testing/regression/moscap_c/models_regression.py index 5dc16a4d..a92bfd54 100644 --- a/models/ngspice/testing/regression/moscap_c/models_regression.py +++ b/models/ngspice/testing/regression/moscap_c/models_regression.py @@ -149,7 +149,9 @@ def ext_measured(dev_data_path: str, device: str, corners: str) -> pd.DataFrame: return df -def run_sim(dirpath: str, device: str, length: float, width: float, corner: str, temp=25) -> dict: +def run_sim( + dirpath: str, device: str, length: float, width: float, corner: str, temp=25 +) -> dict: """Run simulation for a given device, corner, length, width and temperature Args: dirpath (str): Path to directory @@ -211,7 +213,9 @@ def run_sim(dirpath: str, device: str, length: float, width: float, corner: str, return info -def run_sims(df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """Run simulations for a given dataframe Args: df (pd.DataFrame): Dataframe containing device, corner, length, width and temperature @@ -252,7 +256,7 @@ def run_sims(df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count()) -> pd.D def main(): - """Main function for moscap regression """ + """Main function for moscap regression""" # ======= Checking ngspice ======= ngspice_v_ = os.popen("ngspice -v").read() @@ -263,7 +267,9 @@ def main(): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer or newer." + ) exit(1) # pandas setup diff --git a/models/ngspice/testing/regression/resistor_r/models_regression.py b/models/ngspice/testing/regression/resistor_r/models_regression.py index bca863c6..37cf8af6 100644 --- a/models/ngspice/testing/regression/resistor_r/models_regression.py +++ b/models/ngspice/testing/regression/resistor_r/models_regression.py @@ -55,7 +55,9 @@ def call_simulator(file_name: str) -> int: return os.system(f"ngspice -b -a {file_name} -o {file_name}.log > {file_name}.log") -def ext_const_temp_corners(dev_data_path: str, device: str, corners: str) -> pd.DataFrame: +def ext_const_temp_corners( + dev_data_path: str, device: str, corners: str +) -> pd.DataFrame: """Extract constant temperature corners from excel file Args: dev_data_path (str): Path to excel file @@ -130,7 +132,15 @@ def ext_temp_corners(dev_data_path: str, device: str, corners: str) -> pd.DataFr return df -def run_sim(dirpath: str, device: str, length: float, width: float, corner: str, voltage: str, temp=25) -> dict: +def run_sim( + dirpath: str, + device: str, + length: float, + width: float, + corner: str, + voltage: str, + temp=25, +) -> dict: """Run simulation for a given device, corner, voltage and temperature Args: dirpath (str): Path to directory where netlists are stored @@ -198,7 +208,9 @@ def run_sim(dirpath: str, device: str, length: float, width: float, corner: str, return info -def run_sims(df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + df: pd.DataFrame, dirpath: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """Run simulations for all devices in dataframe Args: df (pd.DataFrame): Dataframe @@ -254,7 +266,9 @@ def main(num_cores): version = int((ngspice_v_.split("\n")[1]).split(" ")[1].split("-")[1]) print(version) if version <= 37: - logging.error("ngspice version is not supported. Please use ngspice version 38 or newer.") + logging.error( + "ngspice version is not supported. Please use ngspice version 38 or newer." + ) exit(1) # pandas setup pd.set_option("display.max_columns", None) diff --git a/models/ngspice/testing/sc_regression/gf180mcu_fd_sc_mcu7t5v0/models_regression.py b/models/ngspice/testing/sc_regression/gf180mcu_fd_sc_mcu7t5v0/models_regression.py index 5f17e2e8..c83240f6 100644 --- a/models/ngspice/testing/sc_regression/gf180mcu_fd_sc_mcu7t5v0/models_regression.py +++ b/models/ngspice/testing/sc_regression/gf180mcu_fd_sc_mcu7t5v0/models_regression.py @@ -17,6 +17,7 @@ import concurrent.futures import shutil + def call_simulator(file_name): """Call simulation commands to perform simulation. Args: diff --git a/models/xyce/testing/regression/bjt_cj/models_regression.py b/models/xyce/testing/regression/bjt_cj/models_regression.py index b7dc125a..bdf09884 100644 --- a/models/xyce/testing/regression/bjt_cj/models_regression.py +++ b/models/xyce/testing/regression/bjt_cj/models_regression.py @@ -536,9 +536,7 @@ def main(): no_rows = NO_ROWS_PNP if cj_file != "": - meas_df = ext_measured( - cj_file, dev, list_dev, dev_path, no_rows - ) + meas_df = ext_measured(cj_file, dev, list_dev, dev_path, no_rows) else: meas_df = list() diff --git a/models/xyce/testing/regression/mos_cv/models_regression.py b/models/xyce/testing/regression/mos_cv/models_regression.py index 15cd5f37..6d66fcb7 100644 --- a/models/xyce/testing/regression/mos_cv/models_regression.py +++ b/models/xyce/testing/regression/mos_cv/models_regression.py @@ -421,7 +421,9 @@ def run_sim(dirpath: str, device: str, width: float, length: float, nf: float) - return info -def run_sims(df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_count()) -> pd.DataFrame: +def run_sims( + df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_count() +) -> pd.DataFrame: """passing netlists to run_sim function and storing the results csv files into dataframes @@ -487,7 +489,7 @@ def run_sims(df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_cou # sweeping on all generated cvs files for i in range(len(sf)): df = pd.read_csv(sf[i]) - + if cap == "c": # use the first column as index v_s = "V(S_TN)" @@ -519,7 +521,7 @@ def run_sims(df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_cou # drop time column df.drop(df.columns[0], axis=1, inplace=True) # drop duplicate rows for columns V(S_TN) and V(G_TN) - df.drop_duplicates(subset=["V(D_TN)", "V(G_TN)"], inplace=True) + df.drop_duplicates(subset=["V(D_TN)", "V(G_TN)"], inplace=True) # use the first column as index v_s = "V(G_TN)" i_vds = "{-1.0E15*N(XMN1:M0:CGD)}" @@ -535,7 +537,7 @@ def run_sims(df: pd.DataFrame, dirpath: str, device: str, num_workers=mp.cpu_cou # drop time column df.drop(df.columns[0], axis=1, inplace=True) # drop duplicate rows for columns V(S_TN) and V(G_TN) - df.drop_duplicates(subset=["V(D_TN)", "V(G_TN)"], inplace=True) + df.drop_duplicates(subset=["V(D_TN)", "V(G_TN)"], inplace=True) # use the first column as index v_s = "V(G_TN)" i_vds = "{-1.0E15*N(XMN1:M0:CGS)}" diff --git a/models/xyce/testing/regression/mos_iv_vbs/models_regression.py b/models/xyce/testing/regression/mos_iv_vbs/models_regression.py index f0a56d82..68b74667 100644 --- a/models/xyce/testing/regression/mos_iv_vbs/models_regression.py +++ b/models/xyce/testing/regression/mos_iv_vbs/models_regression.py @@ -385,11 +385,21 @@ def error_cal( result_data["measured_vbs5"] = result_data["measured_vbs5"].clip( lower=lowest_curr ) - result_data["simulated_vbs1"] = result_data["simulated_vbs1"].clip(lower=lowest_curr) - result_data["simulated_vbs2"] = result_data["simulated_vbs2"].clip(lower=lowest_curr) - result_data["simulated_vbs3"] = result_data["simulated_vbs3"].clip(lower=lowest_curr) - result_data["simulated_vbs4"] = result_data["simulated_vbs4"].clip(lower=lowest_curr) - result_data["simulated_vbs5"] = result_data["simulated_vbs5"].clip(lower=lowest_curr) + result_data["simulated_vbs1"] = result_data["simulated_vbs1"].clip( + lower=lowest_curr + ) + result_data["simulated_vbs2"] = result_data["simulated_vbs2"].clip( + lower=lowest_curr + ) + result_data["simulated_vbs3"] = result_data["simulated_vbs3"].clip( + lower=lowest_curr + ) + result_data["simulated_vbs4"] = result_data["simulated_vbs4"].clip( + lower=lowest_curr + ) + result_data["simulated_vbs5"] = result_data["simulated_vbs5"].clip( + lower=lowest_curr + ) result_data["step1_error"] = ( np.abs(result_data["measured_vbs1"] - result_data["simulated_vbs1"]) diff --git a/models/xyce/testing/regression/mos_iv_vgs/models_regression.py b/models/xyce/testing/regression/mos_iv_vgs/models_regression.py index 5d7619c7..1382f615 100644 --- a/models/xyce/testing/regression/mos_iv_vgs/models_regression.py +++ b/models/xyce/testing/regression/mos_iv_vgs/models_regression.py @@ -432,12 +432,24 @@ def error_cal( result_data["measured_vgs6"] = result_data["measured_vgs6"].clip( lower=lowest_curr ) - result_data["simulated_vgs1"] = result_data["simulated_vgs1"].clip(lower=lowest_curr) - result_data["simulated_vgs2"] = result_data["simulated_vgs2"].clip(lower=lowest_curr) - result_data["simulated_vgs3"] = result_data["simulated_vgs3"].clip(lower=lowest_curr) - result_data["simulated_vgs4"] = result_data["simulated_vgs4"].clip(lower=lowest_curr) - result_data["simulated_vgs5"] = result_data["simulated_vgs5"].clip(lower=lowest_curr) - result_data["simulated_vgs6"] = result_data["simulated_vgs6"].clip(lower=lowest_curr) + result_data["simulated_vgs1"] = result_data["simulated_vgs1"].clip( + lower=lowest_curr + ) + result_data["simulated_vgs2"] = result_data["simulated_vgs2"].clip( + lower=lowest_curr + ) + result_data["simulated_vgs3"] = result_data["simulated_vgs3"].clip( + lower=lowest_curr + ) + result_data["simulated_vgs4"] = result_data["simulated_vgs4"].clip( + lower=lowest_curr + ) + result_data["simulated_vgs5"] = result_data["simulated_vgs5"].clip( + lower=lowest_curr + ) + result_data["simulated_vgs6"] = result_data["simulated_vgs6"].clip( + lower=lowest_curr + ) result_data["device"] = device result_data["length"] = length result_data["width"] = w diff --git a/rules/klayout/drc/run_drc.py b/rules/klayout/drc/run_drc.py index 189d628c..dac3f35e 100644 --- a/rules/klayout/drc/run_drc.py +++ b/rules/klayout/drc/run_drc.py @@ -64,7 +64,7 @@ def get_rules_with_violations(results_database): ---------- results_database : string or Path object Path string to the results file - + Returns ------- set @@ -154,7 +154,7 @@ def generate_drc_run_template(drc_dir: str, run_dir: str, run_tables_list: list Name of the rule deck to use for generating the template, by default "" run_tables_list : list, optional list of target parts of the rule deck, if empty assume all of the rule tables found, by default [] - + Returns ------- str @@ -247,7 +247,7 @@ def get_run_top_cell_name(arguments, layout_path): Dictionary that holds the user inputs for the script generated by docopt. layout_path : string Path to the target layout. - + Returns ------- string @@ -280,7 +280,7 @@ def generate_klayout_switches(arguments, layout_path): Dictionary that holds the arguments used by user in the run command. This is generated by docopt library. layout_path : string Path to the layout file that we will run DRC on. - + Returns ------- dict @@ -381,7 +381,7 @@ def check_klayout_version(): ) exit(1) elif len(klayout_v_list) == 3: - if klayout_v_list[1] < 28 : + if klayout_v_list[1] < 28: logging.warning(f"Prerequisites at a minimum: KLayout 0.28.0") logging.error( "Using this klayout version has not been assesed in this development. Limits are unknown" @@ -397,7 +397,7 @@ def check_layout_path(layout_path): ---------- layout_path : string string that represent the path of the layout. - + Returns ------- string @@ -409,7 +409,9 @@ def check_layout_path(layout_path): exit(1) if not ".gds" in layout_path and not ".oas" in layout_path: - logging.error("## Layout is not in GDSII or OASIS format. Please use gds format.") + logging.error( + "## Layout is not in GDSII or OASIS format. Please use gds format." + ) exit(1) return os.path.abspath(layout_path) @@ -445,7 +447,7 @@ def run_check(drc_file: str, drc_name: str, path: str, run_dir: str, sws: dict): String that holds the full path of the run location. sws : dict Dictionary that holds all switches that needs to be passed to the antenna checks. - + Returns ------- string @@ -469,9 +471,7 @@ def run_check(drc_file: str, drc_name: str, path: str, run_dir: str, sws: dict): new_sws["report"] = report_path sws_str = build_switches_string(new_sws) sws_str += f" -rd table_name={drc_name}" - log_file = os.path.join( - run_dir, "{}_{}.log".format(layout_base_name, drc_name) - ) + log_file = os.path.join(run_dir, "{}_{}.log".format(layout_base_name, drc_name)) run_str = f"klayout -b -r {drc_file} {sws_str}" diff --git a/rules/klayout/drc/testing/convert_lydb_to_gds.py b/rules/klayout/drc/testing/convert_lydb_to_gds.py index a127a2b1..fd0405b4 100644 --- a/rules/klayout/drc/testing/convert_lydb_to_gds.py +++ b/rules/klayout/drc/testing/convert_lydb_to_gds.py @@ -34,6 +34,7 @@ import re import json + def darw_polygons(polygon_data, cell, lay_num, dt, path_width): """ darw_polygons _summary_ @@ -43,11 +44,11 @@ def darw_polygons(polygon_data, cell, lay_num, dt, path_width): polygon_data : _type_ _description_ """ - + # polygon: (985.739,294.774;985.739,295.776;986.741,295.776;986.741,294.774) - - polygon_data = re.sub(r'\s+', '', polygon_data) - polygon_data = re.sub(r'[()]', '', polygon_data) + + polygon_data = re.sub(r"\s+", "", polygon_data) + polygon_data = re.sub(r"[()]", "", polygon_data) print("## POLYGON DATA : ", polygon_data) tag_split = polygon_data.split(":") @@ -60,20 +61,29 @@ def darw_polygons(polygon_data, cell, lay_num, dt, path_width): if tag == "polygon": for poly in polygons: - points = [(float(p.split(",")[0]), float(p.split(",")[1])) for p in poly.split(";")] - print(" All points : " , points) + points = [ + (float(p.split(",")[0]), float(p.split(",")[1])) + for p in poly.split(";") + ] + print(" All points : ", points) cell.add(gdstk.Polygon(points, lay_num, dt)) elif tag == "edge-pair": for poly in polygons: - points = [(float(p.split(",")[0]), float(p.split(",")[1])) for p in poly.split(";")] - print(" All points : " , points) + points = [ + (float(p.split(",")[0]), float(p.split(",")[1])) + for p in poly.split(";") + ] + print(" All points : ", points) cell.add(gdstk.FlexPath(points, path_width, layer=lay_num, datatype=dt)) - + elif tag == "edge": for poly in polygons: - points = [(float(p.split(",")[0]), float(p.split(",")[1])) for p in poly.split(";")] - print(" All points : " , points) + points = [ + (float(p.split(",")[0]), float(p.split(",")[1])) + for p in poly.split(";") + ] + print(" All points : ", points) cell.add(gdstk.FlexPath(points, path_width, layer=lay_num, datatype=dt)) else: print(f"## Error unknown type: {tag} ignored") @@ -86,9 +96,8 @@ def darw_polygons(polygon_data, cell, lay_num, dt, path_width): # points = [] # for point in polygon_points: # points.append(f"({point})") - - # print (polygon_data) + # print (polygon_data) def parse_results_db(results_database: str): @@ -99,7 +108,7 @@ def parse_results_db(results_database: str): ---------- results_database : string or Path object Path string to the results file - + Returns ------- set @@ -117,12 +126,12 @@ def parse_results_db(results_database: str): in_item = False rule_data_type_map = list() - for ev, elem in tqdm(ET.iterparse(results_database, events=('start','end'))): - + for ev, elem in tqdm(ET.iterparse(results_database, events=("start", "end"))): + if elem.tag != "item" and not in_item: elem.clear() continue - + if elem.tag != "item" and in_item: continue @@ -136,7 +145,7 @@ def parse_results_db(results_database: str): if len(values) > 0: polygons = values[0].findall("value") else: - polygons = [] + polygons = [] if cell_name == "": all_cells = elem.findall("cell") @@ -158,7 +167,7 @@ def parse_results_db(results_database: str): if rule_name is None: elem.clear() continue - + # print(rule_name) else: elem.clear() @@ -166,19 +175,25 @@ def parse_results_db(results_database: str): if not rule_name in rule_data_type_map: rule_data_type_map.append(rule_name) - + ## draw polygons here. if not cell is None: for p in polygons: - polygons = darw_polygons(p.text, cell, rule_lay_num, rule_data_type_map.index(rule_name) + 1, path_width) - print (type(p)) - #cell.add(gdstk.) + polygons = darw_polygons( + p.text, + cell, + rule_lay_num, + rule_data_type_map.index(rule_name) + 1, + path_width, + ) + print(type(p)) + # cell.add(gdstk.) break ## Clear memeory in_item = False elem.clear() - + lib.write_gds(f"{cell_name}.gds") print("Total read time: {}".format(time.time() - t0)) diff --git a/rules/klayout/drc/testing/run_regression.py b/rules/klayout/drc/testing/run_regression.py index 493ab14c..188aa2ad 100644 --- a/rules/klayout/drc/testing/run_regression.py +++ b/rules/klayout/drc/testing/run_regression.py @@ -79,7 +79,7 @@ def check_klayout_version(): ) exit(1) elif len(klayout_v_list) == 3: - if klayout_v_list[1] < 28 : + if klayout_v_list[1] < 28: logging.warning("Prerequisites at a minimum: KLayout 0.28.0") logging.error( "Using this klayout version has not been assesed in this development. Limits are unknown" @@ -100,7 +100,7 @@ def get_switches(yaml_file, rule_name): """ # load yaml config data - with open(yaml_file, 'r') as stream: + with open(yaml_file, "r") as stream: try: yaml_dic = yaml.safe_load(stream) except yaml.YAMLError as exc: @@ -188,7 +188,9 @@ def run_test_case( fail_patterns_count = 0 # Get switches used for each run - sw_file = os.path.join(Path(layout_path.parent.parent).absolute(), f"{test_rule}.{SUPPORTED_SW_EXT}") + sw_file = os.path.join( + Path(layout_path.parent.parent).absolute(), f"{test_rule}.{SUPPORTED_SW_EXT}" + ) if os.path.exists(sw_file): switches = " ".join(get_switches(sw_file, test_rule)) @@ -237,15 +239,35 @@ def run_test_case( check_call(call_str, shell=True) if os.path.exists(final_report): - pass_patterns_count, fail_patterns_count, falsePos_count, falseNeg_count = parse_results_db(test_rule, final_report) - - return pass_patterns_count, fail_patterns_count, falsePos_count, falseNeg_count + ( + pass_patterns_count, + fail_patterns_count, + falsePos_count, + falseNeg_count, + ) = parse_results_db(test_rule, final_report) + + return ( + pass_patterns_count, + fail_patterns_count, + falsePos_count, + falseNeg_count, + ) else: - return pass_patterns_count, fail_patterns_count, falsePos_count, falseNeg_count + return ( + pass_patterns_count, + fail_patterns_count, + falsePos_count, + falseNeg_count, + ) else: - return pass_patterns_count, fail_patterns_count, falsePos_count, falseNeg_count + return ( + pass_patterns_count, + fail_patterns_count, + falsePos_count, + falseNeg_count, + ) else: return pass_patterns_count, fail_patterns_count, falsePos_count, falseNeg_count @@ -291,7 +313,12 @@ def run_all_test_cases(tc_df, run_dir, thrCount): for future in concurrent.futures.as_completed(future_to_run_id): run_id = future_to_run_id[future] try: - pass_patterns, fail_patterns, false_positive, false_negative = future.result() + ( + pass_patterns, + fail_patterns, + false_positive, + false_negative, + ) = future.result() if pass_patterns + fail_patterns > 0: if false_positive + false_negative == 0: status_string = "Passed_rule" @@ -413,7 +440,9 @@ def generate_merged_testcase(orignal_testcase, marker_testcase): # Getting flattened top cells top_cell_org = lib_org.top_level()[0].flatten(apply_repetitions=True) top_cell_marker = lib_marker.top_level()[0].flatten(apply_repetitions=True) - marker_polygons = top_cell_marker.get_polygons(apply_repetitions=True, include_paths=True, depth=None) + marker_polygons = top_cell_marker.get_polygons( + apply_repetitions=True, include_paths=True, depth=None + ) # Merging all polygons of markers with original testcase for marker_polygon in marker_polygons: @@ -452,8 +481,8 @@ def darw_polygons(polygon_data, cell, lay_num, lay_dt, path_width): """ # Cleaning data points - polygon_data = re.sub(r'\s+', '', polygon_data) - polygon_data = re.sub(r'[()]', '', polygon_data) + polygon_data = re.sub(r"\s+", "", polygon_data) + polygon_data = re.sub(r"[()]", "", polygon_data) print("## POLYGON DATA : ", polygon_data) tag_split = polygon_data.split(":") @@ -467,20 +496,29 @@ def darw_polygons(polygon_data, cell, lay_num, lay_dt, path_width): # Select shape type to be drawn if tag == "polygon": for poly in polygons: - points = [(float(p.split(",")[0]), float(p.split(",")[1])) for p in poly.split(";")] - print(" All points : " , points) + points = [ + (float(p.split(",")[0]), float(p.split(",")[1])) + for p in poly.split(";") + ] + print(" All points : ", points) cell.add(gdstk.Polygon(points, lay_num, lay_dt)) elif tag == "edge-pair": for poly in polygons: - points = [(float(p.split(",")[0]), float(p.split(",")[1])) for p in poly.split(";")] - print(" All points : " , points) + points = [ + (float(p.split(",")[0]), float(p.split(",")[1])) + for p in poly.split(";") + ] + print(" All points : ", points) cell.add(gdstk.FlexPath(points, path_width, layer=lay_num, datatype=lay_dt)) elif tag == "edge": for poly in polygons: - points = [(float(p.split(",")[0]), float(p.split(",")[1])) for p in poly.split(";")] - print(" All points : " , points) + points = [ + (float(p.split(",")[0]), float(p.split(",")[1])) + for p in poly.split(";") + ] + print(" All points : ", points) cell.add(gdstk.FlexPath(points, path_width, layer=lay_num, datatype=lay_dt)) else: logging.error(f"## Unknown type: {tag} ignored") @@ -522,7 +560,7 @@ def convert_results_db_to_gds(results_database: str): rule_data_type_map = list() analysis_rules = [] - for ev, elem in tqdm(ET.iterparse(results_database, events=('start', 'end'))): + for ev, elem in tqdm(ET.iterparse(results_database, events=("start", "end"))): if elem.tag != "item" and not in_item: elem.clear() @@ -573,7 +611,9 @@ def convert_results_db_to_gds(results_database: str): rule_lay_dt = rule_data_type_map.index(rule_name) + 1 if cell is not None: for p in polygons: - polygons = darw_polygons(p.text, cell, rule_lay_num, rule_lay_dt, path_width) + polygons = darw_polygons( + p.text, cell, rule_lay_num, rule_lay_dt, path_width + ) break ## Clearing memeory @@ -587,27 +627,27 @@ def convert_results_db_to_gds(results_database: str): # Writing analysis rule deck output_runset_path = f'{results_database.replace(".lyrdb", "")}_analysis.drc' - runset_analysis_setup = f''' + runset_analysis_setup = f""" source($input) report("DRC analysis run report at", $report) pass_marker = {pass_marker} fail_marker = {fail_marker} fail_marker2 = {fail_marker2} text_marker = {text_marker} - ''' + """ - pass_patterns_rule = f''' + pass_patterns_rule = f""" pass_marker.interacting( text_marker.texts("{rule_name}") ).output("{rule_name}_pass_patterns", "{rule_name}_pass_patterns polygons") - ''' - fail_patterns_rule = f''' + """ + fail_patterns_rule = f""" fail_marker2.interacting(fail_marker.interacting(text_marker.texts("{rule_name}")) ).or( fail_marker.interacting(text_marker.texts("{rule_name}")).not_interacting(fail_marker2) ).output("{rule_name}_fail_patterns", "{rule_name}_fail_patterns polygons") - ''' - false_pos_rule = f''' + """ + false_pos_rule = f""" pass_marker.interacting(text_marker.texts("{rule_name}")).interacting(input({rule_lay_num}, {rule_lay_dt})).output("{rule_name}_false_positive", "{rule_name}_false_positive occurred") - ''' - false_neg_rule = f''' + """ + false_neg_rule = f""" ((fail_marker2.interacting(fail_marker.interacting(text_marker.texts("{rule_name}")))).or((fail_marker.interacting(input(11, 222).texts("{rule_name}")).not_interacting(fail_marker2)))).not_interacting(input({rule_lay_num}, {rule_lay_dt})).output("{rule_name}_false_negative", "{rule_name}_false_negative occurred") - ''' + """ # Adding list of analysis rules if not any(rule_name in rule_txt for rule_txt in analysis_rules): @@ -653,7 +693,9 @@ def get_unit_tests_dataframe(gds_files): for cell in top_cells: flatten_cell = cell.flatten() # Get all text labels for each cell - labels = flatten_cell.get_labels(apply_repetitions=True, depth=None, layer=lay_num, texttype=lay_dt) + labels = flatten_cell.get_labels( + apply_repetitions=True, depth=None, layer=lay_num, texttype=lay_dt + ) # Get label value for label in labels: rule = label.text @@ -662,9 +704,7 @@ def get_unit_tests_dataframe(gds_files): test_paths.append(gds_file) tc_df = pd.DataFrame({"test_path": test_paths, "rule_name": rules}) - tc_df["table_name"] = tc_df["test_path"].apply( - lambda x: x.name.replace(".gds", "") - ) + tc_df["table_name"] = tc_df["test_path"].apply(lambda x: x.name.replace(".gds", "")) return tc_df @@ -736,7 +776,9 @@ def run_regression(drc_dir, output_path, target_table, target_rule, cpu_count): ## Parse Existing Rules rules_df = parse_existing_rules(drc_dir, output_path) - logging.info("## Total number of rules found in rule decks: {}".format(len(rules_df))) + logging.info( + "## Total number of rules found in rule decks: {}".format(len(rules_df)) + ) print(rules_df) ## Get all test cases available in the repo. @@ -781,7 +823,9 @@ def run_regression(drc_dir, output_path, target_table, target_rule, cpu_count): return True -def main(drc_dir: str, rules_dir: str, output_path: str, target_table: str, target_rule: str): +def main( + drc_dir: str, rules_dir: str, output_path: str, target_table: str, target_rule: str +): """ Main Procedure. @@ -873,13 +917,11 @@ def main(drc_dir: str, rules_dir: str, output_path: str, target_table: str, targ level=logging.DEBUG, handlers=[ logging.FileHandler(os.path.join(output_path, "{}.log".format(run_name))), - logging.StreamHandler() + logging.StreamHandler(), ], format="%(asctime)s | %(levelname)-7s | %(message)s", datefmt="%d-%b-%Y %H:%M:%S", ) # Calling main function - run_status = main( - drc_dir, rules_dir, output_path, target_table, target_rule - ) + run_status = main(drc_dir, rules_dir, output_path, target_table, target_rule) diff --git a/rules/klayout/lvs/testing/run_regression.py b/rules/klayout/lvs/testing/run_regression.py index 6b08c95d..1b333823 100644 --- a/rules/klayout/lvs/testing/run_regression.py +++ b/rules/klayout/lvs/testing/run_regression.py @@ -66,6 +66,7 @@ def check_klayout_version(): ) exit(1) + def lvs_check(table, files): pass_count = 0 @@ -292,7 +293,7 @@ def main(): ["cap_mim_2f0_m4m5_noshield", "-rd mim_option=B -rd mim_cap=2"], ["cap_mim_1f0_m5m6_noshield", "-rd mim_option=B -rd mim_cap=1"], ["cap_mim_1f5_m5m6_noshield", "-rd mim_option=B -rd mim_cap=1.5"], - ["cap_mim_2f0_m5m6_noshield", "-rd mim_option=B -rd mim_cap=2"] + ["cap_mim_2f0_m5m6_noshield", "-rd mim_option=B -rd mim_cap=2"], ] # MOS Capacitor diff --git a/third_party/make-env/test/check.py b/third_party/make-env/test/check.py index 24883a1f..6a00c793 100644 --- a/third_party/make-env/test/check.py +++ b/third_party/make-env/test/check.py @@ -11,5 +11,6 @@ # Check that no system packages are found in the environment. import sys -assert all('/usr' not in p for p in sys.path), sys.path + +assert all("/usr" not in p for p in sys.path), sys.path print(sys.path)