| ######################################################################################################################## |
| # Copyright 2022 Mabrains Company LLC |
| # |
| # Licensed under the LGPL v2.1 License (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| ## |
| ######################################################################################################################## |
| ## |
| # This file is authored by: |
| # - <Mina Maksimous> <mina_maksimous@mabrains.com> |
| ## |
| ######################################################################################################################## |
| |
| ######################################################################################################################## |
| # Mabrains Company LLC |
| ## |
| # Mabrains poly resistor 1.8V Generator for Skywaters 130nm |
| ######################################################################################################################## |
| import pya |
| import math |
| from .layers_definiations import * |
| |
| |
| class PolyRes: |
| """ |
| Mabrains poly resistor Generator for Skywaters 130nm |
| """ |
| |
| def __init__(self, layout, |
| w=0.35, l=1, |
| rx=1, ry=1, |
| gr=0, series=0, |
| p_label="", n_label="" |
| ,connection_labels=1 |
| ): |
| |
| self.layout = layout |
| self.w = w |
| self.l = l + 0.12 |
| self.rx = rx |
| self.ry = ry |
| self.gr = gr |
| self.series = series |
| # constants |
| self.licon_enclosure = 0.08 |
| self.licon_length = 2 |
| self.res_spacing_x = 1.24 |
| self.res_spacing_y = 1.24 |
| |
| self.gr_half_width = 0.255 |
| self.psdm_spacing = 0.38 |
| self.psdm_enclosure = 0.11 |
| self. urpm_enclosure = 0.2 |
| self.connection_labels = connection_labels |
| |
| # layers_definations |
| self.l_poly = self.layout.layer(poly_lay_num, poly_lay_dt) # Poly |
| self.l_licon = self.layout.layer( |
| licon_lay_num, licon_lay_dt) # licon local interconnect |
| self.l_li = self.layout.layer(li_lay_num, li_lay_dt) |
| self.l_mcon = self.layout.layer(mcon_lay_num, mcon_lay_dt) |
| self.l_met1 = self.layout.layer(met1_lay_num, met1_lay_dt) |
| self.l_urpm = self.layout.layer(urpm_lay_num, urpm_lay_dt) |
| self.l_psdm = self.layout.layer( |
| psdm_lay_num, psdm_lay_dt) # psdm source drain impaln |
| self.l_tap = self.layout.layer(tap_lay_num, tap_lay_dt) |
| self.l_npc = self.layout.layer(npc_lay_num, npc_lay_dt) |
| self.l_poly_res = self.layout.layer(poly_res_lay_num, poly_res_lay_dt) |
| self.l_met1_label = self.layout.layer( |
| met1_label_lay_num, met1_label_lay_dt) |
| self.l_met1_pin = self.layout.layer( |
| met1_pin_lay_num, met1_pin_lay_dt) |
| cell_str = "rpoly_w" + str(w).replace(".", "p") + "u_l" + str(l).replace(".", "p") + "u_rx" + str( |
| rx) + "_ry" + str(ry) + "_gr" + str(gr) + "series" + str(series) |
| self.p_label = p_label |
| self.n_label = n_label |
| self.both_labels = 0 |
| self.row_both_labels = 0 |
| self.cell = self.layout.create_cell(cell_str) |
| self.lower_label_box = pya.Box() |
| self.upper_label_box = pya.Box() |
| |
| def draw_polyres(self): |
| # precision value for scaling |
| PERCISION = 1/self.layout.dbu |
| |
| # inputs |
| # self.draw_one_finger(self.w, self.l, 0, 0, PERCISION) |
| # self.draw_metal1_between(0+self.w*PERCISION, 0, PERCISION) |
| lfx = 0 |
| lfy = 0 |
| lfx_res = lfx + (self.gr_half_width + |
| self.psdm_spacing + self.psdm_enclosure) * PERCISION |
| lfy_res = lfy + (self.gr_half_width + |
| self.psdm_spacing + self.psdm_enclosure) * PERCISION |
| |
| gr_width = 2*self.gr_half_width + 2*self.psdm_spacing + 2*self.psdm_enclosure + \ |
| (self.rx - 1)*self.res_spacing_x + self.rx*self.w |
| gr_height = 2 * self.gr_half_width + 2 * self.psdm_spacing + 2 * self.psdm_enclosure + \ |
| (self.ry - 1) * self.res_spacing_y + self.ry * \ |
| (4*self.licon_enclosure + 2*self.licon_length + self.l) |
| self.draw_matrix(lfx_res, lfy_res, PERCISION) |
| |
| if self.rx == 1 and self.ry > 1: |
| if self.w < 1.27: |
| urpm_enclosure = ((1.27 * PERCISION - self.w * PERCISION) / 2) |
| else: |
| urpm_enclosure = 0.2 * PERCISION |
| urpm_lfx = lfx_res - urpm_enclosure |
| urpm_urx = urpm_lfx + self.w*PERCISION + 2*urpm_enclosure |
| urpm_lfy = lfy_res - self.urpm_enclosure * PERCISION |
| urpm_ury = urpm_lfy + (gr_height+2*self.urpm_enclosure - ( |
| 2 * self.gr_half_width + 2 * self.psdm_spacing + 2 * self.psdm_enclosure)) * PERCISION |
| self.cell.shapes(self.l_urpm).insert( |
| pya.Box(urpm_lfx, urpm_lfy, urpm_urx, urpm_ury)) |
| |
| else: |
| urpm_lfx = lfx_res - self.urpm_enclosure*PERCISION |
| urpm_urx = lfx_res + \ |
| ((self.rx - 1)*self.res_spacing_x + self.rx * |
| self.w + self.urpm_enclosure)*PERCISION |
| urpm_lfy = lfy_res - self.urpm_enclosure * PERCISION |
| urpm_ury = urpm_lfy + (gr_height + 2 * self.urpm_enclosure - ( |
| 2 * self.gr_half_width + 2 * self.psdm_spacing + 2 * self.psdm_enclosure)) * PERCISION |
| self.cell.shapes(self.l_urpm).insert( |
| pya.Box(urpm_lfx, urpm_lfy, urpm_urx, urpm_ury)) |
| |
| if self.gr: |
| self.draw_guard_ring(lfx, lfy, gr_width, gr_height, PERCISION) |
| |
| return self.cell |
| |
| def draw_one_finger(self, width, length, lfx, lfy, precision, label_location='', label=''): |
| """ Draw one finger of resistor given width and starting and ending points |
| = |
| Parameters |
| ---------- |
| width : double |
| Width of finger. |
| |
| lfx : double |
| lower left x position of point to start drawing |
| |
| lfy : double |
| lower left y position of point to start drawing |
| |
| length : double |
| length of resistor |
| |
| precision : int |
| precision of grid |
| |
| label_location : string |
| upper : upper label |
| lower : lower label |
| |
| """ |
| # **** important note all dimensions are referenced to poly box |
| # ury = length + licon margin *4 + length + 2*li length |
| height = (0.08 * 4 + length + 2 * self.licon_length) * precision |
| ury = lfy + height |
| urx = lfx + width * precision |
| # draw poly box |
| self.cell.shapes(self.l_poly).insert(pya.Box(lfx, lfy, urx, ury)) |
| |
| # draw psdm box |
| psdm_enclosure = 0.110 * precision |
| psdm_lfx = lfx - psdm_enclosure |
| psdm_lfy = lfy - psdm_enclosure |
| psdm_urx = urx + psdm_enclosure |
| psdm_ury = ury + psdm_enclosure |
| self.cell.shapes(self.l_psdm).insert( |
| pya.Box(psdm_lfx, psdm_lfy, psdm_urx, psdm_ury)) |
| |
| # draw npc box |
| npc_enclosure = 0.095 * precision |
| npc_lfx = lfx - npc_enclosure |
| npc_lfy = lfy - npc_enclosure |
| npc_urx = urx + npc_enclosure |
| npc_ury = ury + npc_enclosure |
| self.cell.shapes(self.l_npc).insert( |
| pya.Box(npc_lfx, npc_lfy, npc_urx, npc_ury)) |
| |
| if self.rx == 1 and self. ry == 1: |
| # draw urpm box |
| urpm_enclosure = 0.2 * precision |
| urpm_lfy = lfy - urpm_enclosure |
| urpm_ury = ury + urpm_enclosure |
| |
| # if width < 0.69 we put extra enclosure to pass min width of urpm rule which is 1.27 |
| if width > 0.7: |
| urpm_lfx = lfx - urpm_enclosure |
| urpm_urx = urx + urpm_enclosure |
| else: |
| urpm_enclosure = ((1.27 * precision - width * precision)/2) |
| urpm_lfx = lfx - urpm_enclosure |
| urpm_urx = urx + urpm_enclosure |
| self.cell.shapes(self.l_urpm).insert( |
| pya.Box(urpm_lfx, urpm_lfy, urpm_urx, urpm_ury)) |
| |
| # draw licon box |
| licon_enclosure = self.licon_enclosure * precision |
| # licon count => 0.35=> 1, 0.69=> 1, 1.41=> 2, 2.85=> 4, 5.73=> 8 |
| |
| licon_lfy1 = lfy + licon_enclosure |
| licon_ury1 = licon_lfy1 + self.licon_length * precision |
| |
| licon_lfy2 = lfy + (3 * licon_enclosure + |
| self.licon_length * precision + length * precision) |
| licon_ury2 = licon_lfy2 + self.licon_length * precision |
| if str(width)[0:4] == "0.35": |
| self.draw_one_licon(lfx, 0.08, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| elif str(width)[0:4] == "0.69": |
| self.draw_one_licon(lfx, 0.25, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| |
| elif str(width)[0:4] == "1.41": |
| self.draw_one_licon(lfx, 0.35, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 0.88, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| elif str(width)[0:4] == "2.85": |
| self.draw_one_licon(lfx, 0.418, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 1.026, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 1.634, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 2.242, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| |
| elif str(width)[0:4] == "5.73": |
| self.draw_one_licon(lfx, 0.46, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 1.11, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 1.76, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 2.41, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 3.06, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 3.71, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 4.36, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| self.draw_one_licon(lfx, 5.01, precision, |
| licon_lfy1, licon_ury1, licon_lfy2, licon_ury2) |
| |
| # draw polyres box |
| poly_res_lfy = lfy + 2 * licon_enclosure + self.licon_length * precision |
| poly_res_ury = poly_res_lfy + length * precision |
| self.cell.shapes(self.l_poly_res).insert( |
| pya.Box(lfx, poly_res_lfy, urx, poly_res_ury)) |
| |
| # draw li box |
| self.cell.shapes(self.l_li).insert( |
| pya.Box(lfx, lfy, urx, poly_res_lfy)) |
| self.cell.shapes(self.l_li).insert( |
| pya.Box(lfx, poly_res_ury, urx, ury)) |
| |
| # draw mcon |
| |
| self.draw_mcon_in_li(lfx, lfy, width * precision, |
| poly_res_lfy - lfy, precision) |
| self.draw_mcon_in_li(lfx, poly_res_ury, width * |
| precision, poly_res_lfy - lfy, precision) |
| |
| # draw M1 box |
| lower_m1_box = pya.Box(lfx, lfy, urx, poly_res_lfy) |
| self.cell.shapes(self.l_met1).insert( |
| pya.Box(lfx, lfy, urx, poly_res_lfy)) |
| upper_m1_box = pya.Box(lfx, poly_res_ury, urx, ury) |
| self.cell.shapes(self.l_met1).insert( |
| pya.Box(lfx, poly_res_ury, urx, ury)) |
| |
| # Add label for M1 |
| if label_location == 'upper' or self.both_labels == 1: |
| upper_text = pya.Text( |
| self.p_label, upper_m1_box.center().x, upper_m1_box.center().y) |
| self.upper_label_box = pya.Box(upper_m1_box.p1, upper_m1_box.p2) |
| if self.connection_labels: |
| self.cell.shapes(self.l_met1_label).insert(upper_text) |
| self.cell.shapes(self.l_met1_pin).insert(self.upper_label_box) |
| |
| if label_location == 'lower' or self.both_labels == 1: |
| lower_text = pya.Text( |
| self.n_label, lower_m1_box.center().x, lower_m1_box.center().y) |
| self.lower_label_box = pya.Box(lower_m1_box.p1, lower_m1_box.p2) |
| if self.connection_labels: |
| self.cell.shapes(self.l_met1_label).insert(lower_text) |
| self.cell.shapes(self.l_met1_pin).insert(self.lower_label_box) |
| |
| def draw_one_licon(self, lfx, start_x, precision, licon_lfy1, licon_ury1, licon_lfy2, licon_ury2): |
| """ Draw one pair of licon. |
| |
| Parameters |
| ---------- |
| lfx : double |
| lower left x position of poly. |
| |
| start_x : double |
| lower left spacing to start draw from. |
| |
| licon_lfy1 : double |
| lower left y position of point to start drawing for first licon. |
| |
| licon_ury1 : double |
| upper right y position of point to start drawing for first licon. |
| |
| licon_lfy2 : double |
| lower left y position of point to start drawing for second licon. |
| |
| licon_ury2 : double |
| upper right y position of point to start drawing for second licon. |
| |
| precision : int |
| precision of grid |
| """ |
| licon_lfx1 = lfx + start_x * precision |
| licon_urx1 = licon_lfx1 + 0.19 * precision |
| licon_lfx2 = licon_lfx1 |
| licon_urx2 = licon_urx1 |
| self.cell.shapes(self.l_licon).insert( |
| pya.Box(licon_lfx1, licon_lfy1, licon_urx1, licon_ury1)) |
| self.cell.shapes(self.l_licon).insert( |
| pya.Box(licon_lfx2, licon_lfy2, licon_urx2, licon_ury2)) |
| |
| def draw_mcon_in_li(self, lfx, lfy, width, height, precision): |
| """ Draw one pair of licon. |
| |
| Parameters |
| ---------- |
| lfx : double |
| lower left x position of point to start drawing from. |
| |
| lfy : double |
| lower left y position of point to start drawing from. |
| |
| width : double |
| total width of li layer |
| |
| height : double |
| total height of li layer |
| |
| precision : int |
| precision of grid |
| """ |
| mcon_width = 0.17 * precision |
| mcon_spacing = 0.19 * precision |
| |
| x_num_mcon, x_spacing = self.number_spc_contacts( |
| width, 0, mcon_spacing, mcon_width) |
| y_num_mcon, y_spacing = self.number_spc_contacts( |
| height, 0, mcon_spacing, mcon_width) |
| init_lfy = lfy + y_spacing/2 |
| current_lfx = lfx + x_spacing / 2 |
| # loop and draw each row of mcon |
| for i in range(x_num_mcon): |
| current_lfy = init_lfy |
| for j in range(y_num_mcon): |
| urx = current_lfx + 0.17 * precision |
| ury = current_lfy + 0.17 * precision |
| self.cell.shapes(self.l_mcon).insert( |
| pya.Box(current_lfx, current_lfy, urx, ury)) |
| current_lfy = current_lfy + mcon_width + mcon_spacing |
| |
| current_lfx = current_lfx + mcon_width + mcon_spacing |
| |
| def number_spc_contacts(self, box_width, min_enc, cont_spc, cont_width): |
| """ Calculate number of contacts in a given dimensions and the free space for symmetry. |
| |
| By getting the min enclosure,the width of the box,the width of the cont. or via |
| and the spacing between cont. or via |
| |
| Parameters |
| ---------- |
| box_width : double |
| The length you place the via or cont. in |
| |
| min_enc : double |
| the spacing between the edge of the box and the first via or cont. |
| |
| cont_spc : double |
| the spacing between different via's or cont |
| |
| cont_width: double |
| the cont. or via width in the same direction |
| |
| """ |
| |
| spc_cont = box_width - 2 * min_enc |
| num_cont = int((spc_cont + cont_spc) / (cont_width + cont_spc)) |
| free_spc = box_width - (num_cont * cont_width + |
| (num_cont - 1) * cont_spc) |
| return num_cont, free_spc |
| |
| def draw_metal1_between(self, lfx, lfy, precision): |
| """ draw one metal between resistors. |
| |
| Parameters |
| ---------- |
| lfx : double |
| lower left x position of point to start drawing from. |
| |
| lfy : double |
| lower left y position of point to start drawing from. |
| |
| precision : int |
| precision of grid |
| """ |
| urx = lfx + self.res_spacing_x * precision |
| ury = lfy + (self.licon_length + 2 * self.licon_enclosure) * precision |
| |
| self.cell.shapes(self.l_met1).insert(pya.Box(lfx, lfy, urx, ury)) |
| |
| def draw_one_raw(self, lfx, lfy, width, length, precision, num_of_res, first_down, Text=0, last_row=0): |
| """ draw one metal between resistors. |
| |
| width : double |
| Width of finger. |
| |
| lfx : double |
| lower left x position of point to start drawing |
| |
| lfy : double |
| lower left y position of point to start drawing |
| |
| length : double |
| length of resistor |
| |
| precision : int |
| precision of grid |
| |
| num_of_res : int |
| num of res to draw |
| |
| first_down : bool |
| is first metal1 is down or not |
| """ |
| current_lfx = lfx |
| returned_lfx = lfx |
| returned_lfy = lfy |
| label_location = '' |
| label = '' |
| |
| for i in range(1, num_of_res+1): |
| end_finger = num_of_res |
| if (i == 1 or (i == end_finger and self.ry == 1) or (last_row == 1 and i == end_finger)) and Text: |
| if ((i == 1 and first_down) or (i == end_finger and num_of_res % 2 == 0 and first_down) |
| or (i == end_finger and num_of_res % 2 != 0 and not first_down) |
| or (last_row == 1 and i == end_finger)) and (num_of_res != 1 and self.ry != 1): |
| if not(i == end_finger and self.ry % 2 == 0): |
| print("entered",str(self.ry),str(i),str(end_finger)) |
| label_location = 'upper' |
| label = self.p_label |
| elif last_row != 1 and (num_of_res != 1 and self.ry != 1): |
| label_location = 'lower' |
| label = self.n_label |
| elif num_of_res == 1 and self.ry == 1: |
| self.both_labels = 1 |
| elif num_of_res > 1 and self.ry == 1 : |
| if i == 1: |
| label_location = 'lower' |
| elif i == num_of_res : |
| label_location = 'upper' |
| elif num_of_res == 1 and self.ry > 1: |
| if last_row == 1 : |
| label_location = 'upper' |
| else : |
| label_location = 'lower' |
| print('-->',label_location) |
| self.draw_one_finger(width, length, current_lfx, lfy, |
| precision, label_location=label_location, label=label) |
| label_location='' |
| else: |
| self.draw_one_finger( |
| width, length, current_lfx, lfy, precision) |
| |
| if (not first_down) and (i == num_of_res): |
| returned_lfx = current_lfx |
| if i == num_of_res: # skip last loop |
| continue |
| lfx_metal1 = current_lfx + self.w * precision |
| if first_down: |
| if i % 2 == 1: |
| lfy_metal1 = lfy |
| else: |
| lfy_metal1 = lfy + \ |
| (self.licon_enclosure * 2 + |
| self.licon_length + length) * precision |
| else: |
| if i % 2 == 1: |
| lfy_metal1 = lfy + \ |
| (self.licon_enclosure * 2 + |
| self.licon_length + length) * precision |
| else: |
| lfy_metal1 = lfy |
| if self.series: |
| self.draw_metal1_between(lfx_metal1, lfy_metal1, precision) |
| |
| current_lfx += (width + self.res_spacing_x) * precision |
| |
| return returned_lfx, returned_lfy |
| |
| def draw_matrix(self, lfx, lfy, precision): |
| """ draw resistor matrix |
| |
| lfx : double |
| lower left x position of point to start drawing |
| |
| lfy : double |
| lower left y position of point to start drawing |
| |
| precision : int |
| precision of grid |
| """ |
| |
| current_lfy = lfy |
| |
| for i in range(1, self.ry+1): |
| text_write = 0 |
| last_row = 0 |
| if i == 1 or i == self.ry: |
| text_write = 1 |
| if i == self.ry : |
| last_row = 1 |
| |
| if i % 2 == 1: |
| returned_lfx, returned_lfy = self.draw_one_raw( |
| lfx, current_lfy, self.w, self.l, precision, self.rx, False, Text=text_write, last_row=last_row) |
| else: |
| returned_lfx, returned_lfy = self.draw_one_raw( |
| lfx, current_lfy, self.w, self.l, precision, self.rx, True, Text=text_write, last_row=last_row) |
| |
| if i != self.ry: |
| metal_lfy = returned_lfy + \ |
| (4 * self.licon_enclosure + 2 * |
| self. licon_length + self.l) * precision |
| metal_ury = metal_lfy + self.res_spacing_y * precision |
| metal_urx = returned_lfx + self.w * precision |
| if self.series and self.rx % 2 == 1: |
| self.cell.shapes(self.l_met1).insert( |
| pya.Box(returned_lfx, metal_lfy, metal_urx, metal_ury)) |
| |
| current_lfy += (4 * self.licon_enclosure + 2 * |
| self. licon_length + self.l + self.res_spacing_y) * precision |
| |
| def draw_guard_ring(self, x, y, guard_width, guard_height, precision, tap_width=0.26): |
| # psdm source drain impaln |
| l_psdm = self.layout.layer(psdm_lay_num, psdm_lay_dt) |
| # licon local interconnect |
| l_licon = self.layout.layer(licon_lay_num, licon_lay_dt) |
| l_li = self.layout.layer(li_lay_num, li_lay_dt) |
| l_mcon = self.layout.layer(mcon_lay_num, mcon_lay_dt) |
| l_met1 = self.layout.layer(met1_lay_num, met1_lay_dt) |
| l_tap = self.layout.layer(tap_lay_num, tap_lay_dt) |
| l_via = self.layout.layer(via_lay_num, via_lay_dt) |
| l_met2 = self.layout.layer(met2_lay_num, met2_lay_dt) |
| PERCISION = precision |
| guard_width *= PERCISION |
| guard_height *= PERCISION |
| npsdm_enc_diff = .125 * PERCISION |
| licon_size = 0.17 * PERCISION |
| mcon_m1_enc = 0.03 * PERCISION |
| via_met_enc = 0.085*PERCISION |
| mcon_size = 0.17 * PERCISION |
| mcon_spc = 0.19 * PERCISION |
| via_size = 0.15 * PERCISION |
| via_spc = 0.17 * PERCISION |
| tap_width = tap_width * PERCISION |
| guard_ring_lower_left = pya.Point(x, y) |
| guard_ring_upper_left = pya.Point(x, y+guard_height) |
| guard_ring_upper_right = pya.Point(x+guard_width, y+guard_height) |
| guard_ring_lower_right = pya.Point( |
| guard_ring_upper_right.x, guard_ring_lower_left.y) |
| guard_ring_path = pya.Path( |
| [guard_ring_lower_left, guard_ring_upper_left, guard_ring_upper_right, guard_ring_lower_right, |
| guard_ring_lower_left], tap_width, tap_width / 2, 0) |
| psdm_guard_ring_path = pya.Path( |
| [guard_ring_lower_left, guard_ring_upper_left, guard_ring_upper_right, guard_ring_lower_right, |
| guard_ring_lower_left], tap_width + 2 * npsdm_enc_diff, (tap_width + 2 * npsdm_enc_diff) / 2, 0) |
| gurad_ring_metal1_upper = pya.Path([guard_ring_upper_left, guard_ring_upper_right], tap_width, tap_width / 2, |
| tap_width / 2) |
| self.cell.shapes(l_met1).insert(gurad_ring_metal1_upper) |
| gurad_ring_metal1_lower = pya.Path([guard_ring_lower_left, guard_ring_lower_right], tap_width, tap_width / 2, |
| tap_width / 2) |
| self.cell.shapes(l_met1).insert(gurad_ring_metal1_lower) |
| gurad_ring_metal1_right = pya.Path([guard_ring_lower_right, guard_ring_upper_right], tap_width, tap_width / 2, |
| tap_width / 2) |
| self.cell.shapes(l_met1).insert(gurad_ring_metal1_right) |
| gurad_ring_metal1_left = pya.Path([guard_ring_lower_left, guard_ring_upper_left], tap_width, tap_width / 2, |
| tap_width / 2) |
| self.cell.shapes(l_met1).insert(gurad_ring_metal1_left) |
| self.cell.shapes(l_met2).insert(gurad_ring_metal1_upper) |
| self.cell.shapes(l_met2).insert(gurad_ring_metal1_lower) |
| self.cell.shapes(l_met2).insert(gurad_ring_metal1_right) |
| self.cell.shapes(l_met2).insert(gurad_ring_metal1_left) |
| self.cell.shapes(l_tap).insert(guard_ring_path) |
| self.cell.shapes(l_psdm).insert(psdm_guard_ring_path) |
| self.cell.shapes(l_li).insert(guard_ring_path) |
| # top_nmos_cell.shapes(l_met1).insert(guard_ring_path) |
| |
| distance_cont_guard_vert_licon = guard_ring_upper_left.y - \ |
| guard_ring_lower_left.y - licon_size - 2*licon_size |
| num_licon_guard_vert, free_spc_licon_guard_left = self.number_spc_contacts(distance_cont_guard_vert_licon, |
| mcon_m1_enc, |
| licon_size, licon_size) |
| licon_guard_p1_x_left = guard_ring_lower_left.x - licon_size / 2 |
| licon_guard_p1_x_right = guard_ring_lower_right.x - licon_size / 2 |
| licon_guard_p1_y = guard_ring_lower_left.y + \ |
| free_spc_licon_guard_left / 2 + licon_size/2 + licon_size |
| licon_guard_p2_x_left = licon_guard_p1_x_left + licon_size |
| licon_guard_p2_x_right = licon_guard_p1_x_right + licon_size |
| licon_guard_p2_y = licon_guard_p1_y + licon_size |
| # drawing vertical licon in guard_ring |
| for licon in range(num_licon_guard_vert): |
| licon_guard_box_left = pya.Box(licon_guard_p1_x_left, licon_guard_p1_y, licon_guard_p2_x_left, |
| licon_guard_p2_y) |
| licon_guard_box_right = pya.Box(licon_guard_p1_x_right, licon_guard_p1_y, licon_guard_p2_x_right, |
| licon_guard_p2_y) |
| self.cell.shapes(l_licon).insert(licon_guard_box_left) |
| self.cell.shapes(l_licon).insert(licon_guard_box_right) |
| licon_guard_p1_y += 2 * licon_size |
| licon_guard_p2_y += 2 * licon_size |
| distance_cont_guard_vert_mcon = guard_ring_upper_left.y - \ |
| guard_ring_lower_left.y - mcon_size - 2*mcon_spc |
| num_mcon_guard_vert, free_spc_mcon_guard_left = self.number_spc_contacts(distance_cont_guard_vert_mcon, mcon_m1_enc, |
| mcon_spc, mcon_size) |
| mcon_guard_p1_x_left = guard_ring_lower_left.x - mcon_size / 2 |
| mcon_guard_p1_x_right = guard_ring_lower_right.x - mcon_size / 2 |
| mcon_guard_p1_y = guard_ring_lower_left.y + \ |
| free_spc_mcon_guard_left / 2 + mcon_size/2 + mcon_spc |
| mcon_guard_p2_x_left = mcon_guard_p1_x_left + mcon_size |
| mcon_guard_p2_x_right = mcon_guard_p1_x_right + mcon_size |
| mcon_guard_p2_y = mcon_guard_p1_y + licon_size |
| for mcon in range(num_mcon_guard_vert): |
| mcon_guard_box_left = pya.Box( |
| mcon_guard_p1_x_left, mcon_guard_p1_y, mcon_guard_p2_x_left, mcon_guard_p2_y) |
| mcon_guard_box_right = pya.Box(mcon_guard_p1_x_right, mcon_guard_p1_y, mcon_guard_p2_x_right, |
| mcon_guard_p2_y) |
| self.cell.shapes(l_mcon).insert(mcon_guard_box_left) |
| self.cell.shapes(l_mcon).insert(mcon_guard_box_right) |
| mcon_guard_p1_y += mcon_size + mcon_spc |
| mcon_guard_p2_y += mcon_size + mcon_spc |
| distance_cont_guard_vert_via = guard_ring_upper_left.y - \ |
| guard_ring_lower_left.y - via_size - 2*via_spc |
| num_via_guard_vert, free_spc_via_guard_left = self.number_spc_contacts(distance_cont_guard_vert_via, |
| via_met_enc, |
| via_spc, via_size) |
| via_guard_p1_x_left = guard_ring_lower_left.x - via_size / 2 |
| via_guard_p1_x_right = guard_ring_lower_right.x - via_size / 2 |
| via_guard_p1_y = guard_ring_lower_left.y + \ |
| free_spc_via_guard_left / 2 + via_size/2 + via_spc |
| via_guard_p2_x_left = via_guard_p1_x_left + via_size |
| via_guard_p2_x_right = via_guard_p1_x_right + via_size |
| via_guard_p2_y = via_guard_p1_y + via_size |
| for via in range(num_via_guard_vert): |
| via_guard_box_left = pya.Box(via_guard_p1_x_left, via_guard_p1_y, via_guard_p2_x_left, |
| via_guard_p2_y) |
| via_guard_box_right = pya.Box(via_guard_p1_x_right, via_guard_p1_y, via_guard_p2_x_right, |
| via_guard_p2_y) |
| self.cell.shapes(l_via).insert(via_guard_box_left) |
| self.cell.shapes(l_via).insert(via_guard_box_right) |
| via_guard_p1_y += via_size + via_spc |
| via_guard_p2_y += via_size + via_spc |
| distance_cont_guard_hori = ( |
| guard_ring_upper_right.x - guard_ring_upper_left.x) - 2 * mcon_spc |
| num_licon_guard_hori, free_spc_licon_guard_hori = self.number_spc_contacts(distance_cont_guard_hori, |
| mcon_m1_enc, |
| licon_size, licon_size) |
| licon_guard_p1_x_hori = guard_ring_lower_left.x + \ |
| free_spc_licon_guard_hori / 2 + mcon_spc |
| licon_guard_p1_y_lower = guard_ring_lower_left.y - licon_size / 2 |
| licon_guard_p1_y_upper = guard_ring_upper_left.y - licon_size / 2 |
| licon_guard_p2_x_hori = licon_guard_p1_x_hori + licon_size |
| licon_guard_p2_y_upper = guard_ring_upper_left.y + licon_size / 2 |
| licon_guard_p2_y_lower = guard_ring_lower_left.y + licon_size / 2 |
| for licon in range(num_licon_guard_hori): |
| licon_guard_box_upper = pya.Box(licon_guard_p1_x_hori, licon_guard_p1_y_upper, licon_guard_p2_x_hori, |
| licon_guard_p2_y_upper) |
| licon_guard_box_lower = pya.Box(licon_guard_p1_x_hori, licon_guard_p1_y_lower, licon_guard_p2_x_hori, |
| licon_guard_p2_y_lower) |
| self.cell.shapes(l_licon).insert(licon_guard_box_upper) |
| self.cell.shapes(l_licon).insert(licon_guard_box_lower) |
| licon_guard_p1_x_hori += 2 * licon_size |
| licon_guard_p2_x_hori += 2 * licon_size |
| num_mcon_guard_hori, free_spc_mcon_guard_hori = self.number_spc_contacts(distance_cont_guard_hori, |
| mcon_m1_enc, |
| mcon_spc, mcon_size) |
| mcon_guard_p1_x_hori = guard_ring_lower_left.x + \ |
| free_spc_mcon_guard_hori / 2 + mcon_spc |
| mcon_guard_p1_y_lower = guard_ring_lower_left.y - mcon_size / 2 |
| mcon_guard_p1_y_upper = guard_ring_upper_left.y - mcon_size / 2 |
| mcon_guard_p2_x_hori = mcon_guard_p1_x_hori + mcon_size |
| mcon_guard_p2_y_upper = guard_ring_upper_left.y + mcon_size / 2 |
| mcon_guard_p2_y_lower = guard_ring_lower_left.y + mcon_size / 2 |
| for mcon in range(num_mcon_guard_hori): |
| mcon_guard_box_upper = pya.Box(mcon_guard_p1_x_hori, mcon_guard_p1_y_upper, |
| mcon_guard_p2_x_hori, |
| mcon_guard_p2_y_upper) |
| mcon_guard_box_lower = pya.Box(mcon_guard_p1_x_hori, mcon_guard_p1_y_lower, |
| mcon_guard_p2_x_hori, |
| mcon_guard_p2_y_lower) |
| self.cell.shapes(l_mcon).insert(mcon_guard_box_upper) |
| self.cell.shapes(l_mcon).insert(mcon_guard_box_lower) |
| mcon_guard_p1_x_hori += mcon_size + mcon_spc |
| mcon_guard_p2_x_hori += mcon_size + mcon_spc |
| num_via_guard_hori, free_spc_via_guard_hori = self.number_spc_contacts(distance_cont_guard_hori, |
| via_met_enc, |
| via_spc, via_size) |
| via_guard_p1_x_hori = guard_ring_lower_left.x + \ |
| free_spc_via_guard_hori / 2 + via_spc |
| via_guard_p1_y_lower = guard_ring_lower_left.y - via_size / 2 |
| via_guard_p1_y_upper = guard_ring_upper_left.y - via_size / 2 |
| via_guard_p2_x_hori = via_guard_p1_x_hori + via_size |
| via_guard_p2_y_upper = guard_ring_upper_left.y + via_size / 2 |
| via_guard_p2_y_lower = guard_ring_lower_left.y + via_size / 2 |
| for via in range(num_via_guard_hori): |
| via_guard_box_upper = pya.Box(via_guard_p1_x_hori, via_guard_p1_y_upper, |
| via_guard_p2_x_hori, |
| via_guard_p2_y_upper) |
| via_guard_box_lower = pya.Box(via_guard_p1_x_hori, via_guard_p1_y_lower, |
| via_guard_p2_x_hori, |
| via_guard_p2_y_lower) |
| self.cell.shapes(l_via).insert(via_guard_box_upper) |
| self.cell.shapes(l_via).insert(via_guard_box_lower) |
| via_guard_p1_x_hori += via_size + via_spc |
| via_guard_p2_x_hori += via_size + via_spc |
| |
| def return_label_boxes(self): |
| return self.lower_label_box,self.upper_label_box |