| ######################################################################################################################## |
| # 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 NMOS 1.8V Generator for Skywaters 130nm |
| ######################################################################################################################## |
| from .layers_definiations import * |
| import pya |
| import math |
| import os |
| import sys |
| |
| # path = os.path.abspath("layers_definiations") |
| # sys.path.insert(1, path) |
| |
| |
| # cell_extend_layer = layout.layer(1, 1) |
| # fill_shape = pya.Box(0,0,100*1000,100*1000) |
| # top_cell.shapes(cell_extend_layer).insert(fill_shape) |
| |
| |
| ######################################################################################################################### |
| # Exceptions |
| ######################################################################################################################### |
| class Error(Exception): |
| """Base class for other exceptions""" |
| pass |
| |
| |
| class small_channel_length(Error): |
| """Raised When the channel length is < 0.15u""" |
| pass |
| |
| |
| class small_channel_width(Error): |
| """Raised When the channel width is < 0.42u""" |
| pass |
| |
| |
| class small_drain_source_area(Error): |
| """Raised When the dsa < 1""" |
| pass |
| |
| |
| class gate_connection_error(Error): |
| """Raised when the connection value is not 0,1,2""" |
| pass |
| |
| |
| class alternate_connection_error(Error): |
| """Raised when the n factor don't play well with alternate factor""" |
| pass |
| |
| |
| class nf_error(Error): |
| """Raised when the nf < 1""" |
| pass |
| |
| |
| class layout_not_defined(Error): |
| """layout is not defined""" |
| pass |
| |
| |
| class max_drain_source_area(Error): |
| """Max Drain Source Area""" |
| |
| |
| class no_subcircuit_in_netlist(Error): |
| """no subcircuit inn netlist""" |
| ######################################################################################################################### |
| |
| |
| # Drawing functions |
| ######################################################################################################################### |
| class nmos18_device: |
| def __init__(self, w=0.42, l=0.15, nf=1, gr=1, |
| dsa=2, |
| connection=0, |
| n=1, |
| x_offest=0, |
| y_offest=0, |
| conn_num=0, |
| connection_labels = 1, |
| gate_connection="gate_connection_", |
| gate_connection_up="gate_connection_up_", |
| gate_connection_down="gate_connection_down_", |
| drain_connection="drain_connection_", |
| source_connection="source_connection_", |
| connected_gates = 1, |
| layout=None): |
| self.w = w |
| self.l = l |
| self.nf = nf |
| self.gr = gr |
| self.dsa = dsa |
| self.connection = connection |
| |
| self.n = n |
| self.x_offest = x_offest |
| self.y_offest = y_offest |
| self.conn_num = str(conn_num) |
| self.gate_connection = gate_connection |
| self.gate_connection_up = gate_connection_up |
| self.gate_connection_down = gate_connection_down |
| self.drain_connection = drain_connection |
| self.source_connection = source_connection |
| self.layout = layout |
| self.connected_gates = connected_gates |
| self.connection_labels = connection_labels |
| self.l_diff_implant = self.layout.layer(nsdm_lay_num, nsdm_lay_dt) |
| self.l_guard = self.layout.layer( |
| psdm_lay_num, psdm_lay_dt) # guard ring implant layer |
| self.cell_str = "nmos18_w" + str(self.w).replace(".", "p") + "u_l" + str(self.l).replace(".", "p") + "u_nf" + str( |
| self.nf) + "_drain_area" + str(self.dsa) + "_gate_connection" + str(self.connection) + "alt" + str(self.n) |
| |
| def number_spc_contacts(self, box_width, min_enc, cont_spc, 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 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_guard_ring(self, layout, x, y, guard_width, guard_height, precision, tap_width=0.26, cell=None,guard_label=''): |
| # psdm source drain impaln |
| l_psdm = layout.layer(psdm_lay_num, psdm_lay_dt) |
| l_nsdm = layout.layer(nsdm_lay_num, nsdm_lay_dt) |
| # licon local interconnect |
| l_licon = layout.layer(licon_lay_num, licon_lay_dt) |
| l_li = layout.layer(li_lay_num, li_lay_dt) |
| l_mcon = layout.layer(mcon_lay_num, mcon_lay_dt) |
| l_met1 = layout.layer(met1_lay_num, met1_lay_dt) |
| l_tap = layout.layer(tap_lay_num, tap_lay_dt) |
| l_via = layout.layer(via_lay_num, via_lay_dt) |
| l_met2 = 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) |
| 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) |
| 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) |
| 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) |
| cell.shapes(l_met1).insert(gurad_ring_metal1_left) |
| cell.shapes(l_met2).insert(gurad_ring_metal1_upper) |
| cell.shapes(l_met2).insert(gurad_ring_metal1_lower) |
| cell.shapes(l_met2).insert(gurad_ring_metal1_right) |
| cell.shapes(l_met2).insert(gurad_ring_metal1_left) |
| cell.shapes(l_tap).insert(guard_ring_path) |
| # if type == 'p': |
| # cell.shapes(l_psdm).insert(psdm_guard_ring_path) |
| # if type == 'n': |
| cell.shapes(self.l_guard).insert(psdm_guard_ring_path) |
| 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) |
| cell.shapes(l_licon).insert(licon_guard_box_left) |
| 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) |
| cell.shapes(l_mcon).insert(mcon_guard_box_left) |
| 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) |
| cell.shapes(l_via).insert(via_guard_box_left) |
| 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) |
| cell.shapes(l_licon).insert(licon_guard_box_upper) |
| 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) |
| cell.shapes(l_mcon).insert(mcon_guard_box_upper) |
| 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) |
| cell.shapes(l_via).insert(via_guard_box_upper) |
| 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 |
| |
| gurad_ring_metal1_right_bbox = gurad_ring_metal1_right.bbox() |
| if guard_label != '': |
| guard_connection_text = pya.Text(guard_label, |
| gurad_ring_metal1_right_bbox.center().x, |
| gurad_ring_metal1_right_bbox.center().y,) |
| if self.connection_labels: |
| cell.shapes(self.l_met2_label).insert(guard_connection_text) |
| |
| |
| def draw_nmos(self): |
| """ |
| Draw nmos 1.8v |
| |
| Parameters |
| ---------- |
| w : double |
| Channel width of the transistor |
| l : double |
| Channel length of the transistor |
| nf : integer |
| number of fingers |
| gr : bool |
| guard ring option |
| dsa : integer max 8 |
| Area of drain and source |
| connection : 0 , 1 , 2 |
| 0 : gate connection up |
| 1 : gate connection down |
| 2 : gate connection alternate by factor n |
| n : integer |
| Alternate factor flip the gates every n in case of alternate option |
| x_offest : offset of the origin in the x_direction |
| y_offest : offset of the origin in the y_direction |
| conn_num : number of the connection |
| """ |
| # Netnames |
| print(self.connection) |
| if self.gate_connection_up == "gate_connection_up_": |
| gate_connection_text_up = self.gate_connection_up + \ |
| str(self.conn_num) |
| else: |
| gate_connection_text_up = self.gate_connection_up |
| |
| if self.gate_connection_down == "gate_connection_down_": |
| gate_connection_text_down = self.gate_connection_down + \ |
| str(self.conn_num) |
| else: |
| gate_connection_text_down = self.gate_connection_down |
| |
| if self.gate_connection == "gate_connection_": |
| gate_connection_text_down = self.gate_connection + \ |
| str(self.conn_num) |
| gate_connection_text_up = self.gate_connection + str(self.conn_num) |
| else: |
| gate_connection_text_down = self.gate_connection |
| gate_connection_text_up = self.gate_connection |
| |
| if self.drain_connection == "drain_connection_": |
| drain_connection_text_input = self.drain_connection + self.conn_num |
| else: |
| drain_connection_text_input = self.drain_connection |
| |
| if self.source_connection == "source_connection_": |
| source_connection_text_input = self.source_connection + self.conn_num |
| else: |
| source_connection_text_input = self.source_connection |
| # Exceptions |
| if self.w < 0.42: |
| raise small_channel_width |
| |
| if self.l < 0.15: |
| raise small_channel_length |
| |
| if self.nf < 1: |
| raise nf_error |
| |
| if self.dsa < 1: |
| raise small_drain_source_area |
| |
| if self.dsa > 8: |
| raise max_drain_source_area |
| |
| if self.connection != 1 and self.connection != 0 and self.connection != 2 and self.connection != 3 and self.connection != 4: |
| raise gate_connection_error |
| |
| if self.connection == 2 and self.nf % self.n != 0: |
| raise alternate_connection_error |
| |
| if self.layout is None: |
| raise layout_not_defined |
| |
| conn_num = str(self.conn_num) |
| # layout = pya.Layout() |
| |
| # precision value for scaling |
| |
| PERCISION = 1 / self.layout.dbu |
| liconpoly_spc = 0.055 * PERCISION |
| |
| # 1 for source_shared 0 for no nf turned into no of multipliers |
| source_shared = 1 |
| multipliers = 1 |
| diff_spc = 0.27 * PERCISION |
| |
| # the extension of n+ or p+ layer beyond diff to define it's type |
| npsdm_enc_diff = .125 * PERCISION |
| |
| # the spacing of different regions of doping |
| npsdm_spc_opposite = 0.135 * PERCISION |
| |
| # the spacing of the same type regions of doping |
| npsdm_spc = 0.38 * PERCISION |
| |
| # mcon _contact_size |
| mcon_size = 0.17 * PERCISION |
| |
| # mcon_spacing |
| mcon_spc = 0.19 * PERCISION |
| |
| # and the channel length is low todo find the length in code |
| |
| diffusion_width = self.dsa * mcon_size + \ |
| (self.dsa - 1) * mcon_spc + 2 * liconpoly_spc + 0.01*PERCISION |
| |
| channel_length = int(self.l * PERCISION) |
| |
| if source_shared == 0: |
| # if no source sharing nf = 1 and repetition become multiplier |
| self.nf = 1 |
| |
| if self.nf == 1: |
| # if self.nf = 1 alternative doesn't make sense so the default is up |
| if self.connection == 2: |
| self.connection = 0 |
| # todo :correct the diffusion_total_width of singel finger |
| |
| diffusion_total_width = self.nf * channel_length + \ |
| (self.nf - 1) * diffusion_width + 2 * diffusion_width |
| channel_width = self.w * PERCISION |
| |
| diff_min_width = 0.28 |
| poly_min_width = 0.15 |
| poly_diff_min_enc = 0.13 * PERCISION |
| polylicon_spc_diff = 0.22 * PERCISION |
| |
| licon_size = 0.17 * PERCISION |
| licon_spc = 0.17 * PERCISION |
| |
| diff_licon_enc_vertical = 0.08 * PERCISION |
| diff_licon_enc_horzintal = 0.04 * PERCISION |
| liconpoly_enc_vertical = 0.05 * PERCISION |
| liconpoly_enc_horizontal = 0.08 * PERCISION |
| li_licon_enc = 0.08 * PERCISION |
| npc_enc_gate = 0.1 * PERCISION |
| m1_width = 0.17 * PERCISION |
| mcon_m1_enc = 0.03 * PERCISION |
| mcon_m1_enc_adjacent = 0.06 * PERCISION |
| via_size = 0.15 * PERCISION |
| via_spc = 0.17 * PERCISION |
| via_met_enc = 0.085 * PERCISION |
| li_width = 0.17 * PERCISION |
| nwell_extension = 0.18 * PERCISION |
| |
| # number of vertical licon's diff todo use the function |
| num_ver_licon, free_space_diff_licon = self.number_spc_contacts(channel_width, diff_licon_enc_vertical, licon_spc, |
| licon_size) |
| # number of vertical mcon diff |
| num_ver_mcon, free_spc_mcon_diff = self.number_spc_contacts( |
| channel_width, mcon_m1_enc, mcon_spc, mcon_size) |
| |
| # layers_definations |
| l_diff = self.layout.layer(diff_lay_num, diff_lay_dt) # Diffusion |
| l_poly = self.layout.layer(poly_lay_num, poly_lay_dt) # Poly |
| # nsdm source drain impalnt |
| l_nsdm = self.layout.layer(nsdm_lay_num, nsdm_lay_dt) |
| # 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_npc = self.layout.layer(npc_lay_num, npc_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_nwell = self.layout.layer(nwell_lay_num, nwell_lay_dt) |
| l_via = self.layout.layer(via_lay_num, via_lay_dt) |
| l_met2 = self.layout.layer(met2_lay_num, met2_lay_dt) |
| l_prbndry = self.layout.layer(prbndry_lay_num, prbndry_lay_dt) |
| l_poly_label = self.layout.layer(poly_label_lay_num, poly_label_lay_dt) |
| l_met1_label = self.layout.layer(met1_label_lay_num, met1_label_lay_dt) |
| self.l_met2_label = self.layout.layer(met2_label_lay_num,met2_label_lay_dt) |
| |
| ##cells## |
| # top_nmos_cell = layout.create_cell("top_nmos_"+str(w)+"_"+str(l)) |
| |
| self.nmos_cell = self.layout.create_cell(self.cell_str) |
| licon_between_fingers_cell = self.layout.create_cell( |
| "licon_between_fingers") |
| |
| li_between_fingers_cell = self.layout.create_cell("li_between_fingers") |
| mcon_between_fingers_cell = self.layout.create_cell( |
| "mcon_between_fingers") |
| ## |
| self.diff_box = pya.Box(0, 0, diffusion_total_width, channel_width) |
| diff_box = pya.Box(0, 0, diffusion_total_width, channel_width) |
| |
| # main diff box |
| nsdm_box = pya.Box(-npsdm_enc_diff, -npsdm_enc_diff, diffusion_total_width + npsdm_enc_diff, |
| channel_width + npsdm_enc_diff) |
| # source drain implant diff |
| x = 0 |
| |
| # draw the gate fingers |
| for finger in range(self.nf): |
| gate_box = pya.Box(diffusion_width + x, -poly_diff_min_enc, channel_length + diffusion_width + x, |
| channel_width + poly_diff_min_enc) |
| |
| self.nmos_cell.shapes(l_poly).insert(gate_box) |
| |
| x += channel_length + diffusion_width |
| |
| gate_box = pya.Box(diffusion_width, -poly_diff_min_enc, channel_length + diffusion_width, |
| channel_width + poly_diff_min_enc) |
| ######################################################################################################################### |
| # connection of gate box dimensions |
| ######################################################################################################################### |
| |
| contact_gate_width = 2 * liconpoly_enc_horizontal + licon_size |
| contact_gate_height = 2 * liconpoly_enc_vertical + 3 * licon_size |
| num_horizontal_licon_gate = 1 |
| |
| free_spc_licon_gate = contact_gate_width - \ |
| (2 * num_horizontal_licon_gate - 1) * licon_size |
| if channel_length > contact_gate_width: |
| # calculate number of horizontal licon in gate connection todo use function to do |
| contact_gate_width = channel_length |
| spc_for_licon_gate = channel_length - 2 * liconpoly_enc_horizontal |
| num_horizontal_licon_gate = int( |
| ((spc_for_licon_gate / licon_size) + 1) / 2) |
| free_spc_licon_gate = channel_length - \ |
| (2 * num_horizontal_licon_gate - 1) * licon_size |
| elif channel_length < contact_gate_width and self.nf != 1 and self.dsa == 1: |
| self.connection = 2 |
| |
| if self.connection == 0 or self.connection == 2: |
| up_gate_connection = self.layout.create_cell("up_gate_connection") |
| if self.connection == 1 or self.connection == 2: |
| down_gate_connection = self.layout.create_cell( |
| "down_gate_connection") |
| |
| # contacte_gate_box |
| contact_gate_box_down = pya.Box(gate_box.center().x - contact_gate_width / 2, |
| -polylicon_spc_diff - contact_gate_height, |
| gate_box.center().x + contact_gate_width / 2, -polylicon_spc_diff) |
| neck_box_down = pya.Box(diffusion_width, -polylicon_spc_diff, channel_length + diffusion_width, |
| -poly_diff_min_enc) |
| # licon_box_down = pya.Box(contact_gate_box_down.center().x - licon_size/2, contact_gate_box_down.center().y-(licon_size/2),contact_gate_box_down.center().x + licon_size/2,contact_gate_box_down.center().y + licon_size/2) |
| npc_box_down = pya.Box(contact_gate_box_down.p1.x - 1.6*npc_enc_gate, contact_gate_box_down.p1.y - npc_enc_gate, |
| contact_gate_box_down.p2.x + 1.6*npc_enc_gate, contact_gate_box_down.p2.y + npc_enc_gate) |
| li_box_down = pya.Box(diff_box.p1.x, contact_gate_box_down.p1.y, |
| diff_box.p1.x + multipliers * diffusion_total_width + ( |
| 2 * multipliers - 2) * npsdm_enc_diff + (multipliers - 1) * npsdm_spc, |
| contact_gate_box_down.p2.y) |
| |
| gate_connection_text_down = pya.Text(gate_connection_text_up, li_box_down.center().x, |
| li_box_down.center().y) |
| |
| num_hori_licon_diff, free_space_licon_diff_hor = self.number_spc_contacts(diffusion_width, liconpoly_spc, licon_size, |
| licon_size) |
| |
| sh1 = 0 |
| for hor_licon_diff in range(num_hori_licon_diff): |
| licon_between_fingers = pya.Box(free_space_licon_diff_hor / 2 + sh1, |
| free_space_diff_licon / 2, free_space_licon_diff_hor / 2 + licon_size + sh1, |
| free_space_diff_licon / 2 + licon_size) |
| licon_between_fingers_cell.shapes( |
| l_licon).insert(licon_between_fingers) |
| sh1 += 2 * licon_size |
| |
| # print(num_hori_licon_diff,free_space_licon_diff_hor,diffusion_width) |
| |
| num_hori_mcon_diff, free_space_mcon_diff_hor = self.number_spc_contacts( |
| diffusion_width, 0, mcon_spc, mcon_size) |
| sh2 = 0 |
| for hor_mcon_diff in range(num_hori_mcon_diff): |
| mcon_between_fingers = pya.Box(free_space_mcon_diff_hor / 2 + sh2, |
| free_spc_mcon_diff / 2, |
| free_space_mcon_diff_hor / 2 + sh2 + mcon_size, |
| free_spc_mcon_diff / 2 + mcon_size) |
| mcon_between_fingers_cell.shapes( |
| l_mcon).insert(mcon_between_fingers) |
| sh2 += mcon_size + mcon_spc |
| |
| if channel_length < 0.17 * PERCISION: |
| li_width_reduction = 0.17 * PERCISION - channel_length |
| else: |
| li_width_reduction = 0 |
| |
| li_between_fingers_path = pya.Path([pya.Point(diffusion_width / 2, diff_box.p1.y), |
| pya.Point(diffusion_width / 2, diff_box.p2.y)], |
| diffusion_width - li_width_reduction) |
| met1_between_fingers_path = pya.Path([pya.Point(diffusion_width / 2, diff_box.p1.y - mcon_m1_enc), |
| pya.Point(diffusion_width / 2, diff_box.p2.y + mcon_m1_enc)], |
| diffusion_width) |
| |
| contact_gate_box_up = pya.Box(gate_box.center().x - contact_gate_width / 2, channel_width + polylicon_spc_diff, |
| gate_box.center().x + contact_gate_width / 2, |
| channel_width + polylicon_spc_diff + contact_gate_height) |
| neck_box_up = pya.Box(diffusion_width, channel_width + poly_diff_min_enc, |
| channel_length + diffusion_width, |
| channel_width + polylicon_spc_diff) |
| licon_box_up = pya.Box(contact_gate_box_up.center().x - licon_size / 2, |
| contact_gate_box_up.center().y - (licon_size / 2), |
| contact_gate_box_up.center().x + licon_size / 2, |
| contact_gate_box_up.center().y + licon_size / 2) |
| npc_box_up = pya.Box(contact_gate_box_up.p1.x - 1.6 * npc_enc_gate, contact_gate_box_up.p1.y - npc_enc_gate, |
| contact_gate_box_up.p2.x + 1.6 * npc_enc_gate, contact_gate_box_up.p2.y + npc_enc_gate) |
| |
| |
| li_path_up = pya.Path( |
| [pya.Point(diff_box.p1.x, licon_box_up.center().y), |
| pya.Point(diff_box.p2.x, licon_box_up.center().y)], |
| li_width) |
| |
| licon_diff_contact_left = pya.Box(diff_box.p1.x + diff_licon_enc_horzintal, free_space_diff_licon / 2, |
| diff_licon_enc_horzintal + licon_size, free_space_diff_licon / 2 + licon_size) |
| li_diff_left = pya.Path([pya.Point(licon_diff_contact_left.center().x, diff_box.p1.y), |
| pya.Point(licon_diff_contact_left.center().x, diff_box.p2.y)], li_width) |
| met1_diff_left = pya.Path([pya.Point(licon_diff_contact_left.center().x, diff_box.p1.y - mcon_m1_enc), |
| pya.Point(licon_diff_contact_left.center().x, diff_box.p2.y + mcon_m1_enc)], |
| m1_width + 2 * mcon_m1_enc) |
| # drain_connection |
| x_offset_drain = 0 |
| met1_diff_left_bbox = met1_diff_left.bbox() |
| for drain in range(math.ceil((self.nf + 1) / 2)): |
| drain_connection_text = pya.Text(drain_connection_text_input, |
| met1_diff_left_bbox.center().x + self.x_offest + x_offset_drain, |
| met1_diff_left_bbox.center().y + self.y_offest) |
| if self.connection_labels : |
| self.nmos_cell.shapes(l_met1_label).insert(drain_connection_text) |
| x_offset_drain = x_offset_drain + 2 * \ |
| (channel_length + diffusion_width) |
| |
| # source connection |
| x_offset_source = channel_length + diffusion_width |
| for source in range(((self.nf + 1) - math.ceil((self.nf + 1) / 2))): |
| source_connection_text = pya.Text(source_connection_text_input, |
| met1_diff_left_bbox.center().x + self.x_offest + x_offset_source, |
| met1_diff_left_bbox.center().y + self.y_offest) |
| if self.connection_labels: |
| self.nmos_cell.shapes(l_met1_label).insert(source_connection_text) |
| x_offset_source = x_offset_source + 2 * \ |
| (channel_length + diffusion_width) |
| |
| mcon_diff_left = pya.Box(licon_diff_contact_left.p1.x, |
| 0, licon_diff_contact_left.p1.x + mcon_size, mcon_size) |
| |
| licon_diff_contact_right = pya.Box(diff_box.p2.x - diff_licon_enc_horzintal - licon_size, |
| free_space_diff_licon / 2, |
| diff_box.p2.x - diff_licon_enc_horzintal, |
| free_space_diff_licon / 2 + licon_size) |
| li_diff_right = pya.Path([pya.Point(licon_diff_contact_right.center().x, diff_box.p1.y), |
| pya.Point(licon_diff_contact_right.center().x, diff_box.p2.y)], li_width) |
| mcon_diff_right = pya.Box(licon_diff_contact_right.p1.x, 0, licon_diff_contact_right.p1.x + mcon_size, |
| mcon_size) |
| met1_diff_right = pya.Path([pya.Point(licon_diff_contact_right.center().x, diff_box.p1.y - mcon_m1_enc), |
| pya.Point(licon_diff_contact_right.center().x, diff_box.p2.y + mcon_m1_enc)], |
| m1_width + 2 * mcon_m1_enc) |
| |
| self.nmos_cell.shapes(l_diff).insert(diff_box) |
| # if mos_type == 'n': |
| self.nmos_cell.shapes(self.l_diff_implant).insert(nsdm_box) |
| # if mos_type == 'p': |
| # self.nmos_cell.shapes(l_psdm).insert(nsdm_box) |
| if self.connected_gates == 0: |
| li_box_down = contact_gate_box_down |
| li_box_up = contact_gate_box_up |
| num_ver_mcon_gates, free_spc_mcon_gates_v = self.number_spc_contacts(li_box_down.height(), mcon_m1_enc, mcon_spc, |
| mcon_size) |
| num_hor_mcon_gates, free_spc_mcon_gates_h = self.number_spc_contacts(li_box_down.width(), mcon_m1_enc_adjacent, mcon_spc, |
| mcon_size) |
| # shift distance for alternate mode |
| shift_distance = self.n * (diffusion_width + channel_length) |
| if self.connection != 3: |
| if self.connection == 1 or self.connection == 2: |
| down_gate_connection.shapes(l_poly).insert(contact_gate_box_down) |
| down_gate_connection.shapes(l_poly).insert(neck_box_down) |
| |
| y_sh = 0 |
| if self.connection_labels: |
| self.nmos_cell.shapes(l_met1_label).insert( |
| gate_connection_text_down) |
| p1_x = contact_gate_box_down.p1.x + free_spc_licon_gate / 2 |
| p1_y = contact_gate_box_down.p1.y + liconpoly_enc_vertical |
| p2_x = contact_gate_box_down.p1.x + free_spc_licon_gate / 2 + licon_size |
| p2_y = contact_gate_box_down.p1.y + liconpoly_enc_vertical + licon_size |
| for licon_ct in range(num_horizontal_licon_gate): |
| licon_box_down = pya.Box(p1_x, p1_y, p2_x, p2_y) |
| |
| down_gate_connection.shapes(l_licon).insert(licon_box_down) |
| p1_y += 2 * licon_size |
| p2_y += 2 * licon_size |
| licon_box_down = pya.Box(p1_x, p1_y, p2_x, p2_y) |
| down_gate_connection.shapes(l_licon).insert(licon_box_down) |
| p1_y -= 2 * licon_size |
| p2_y -= 2 * licon_size |
| |
| p1_x += 2 * licon_size |
| p2_x += 2 * licon_size |
| if self.connected_gates == 0: # the gate has contacts but no connection |
| down_gate_connection.shapes(l_li).insert(contact_gate_box_down) |
| down_gate_connection.shapes(l_met1).insert(contact_gate_box_down) |
| else: |
| self.nmos_cell.shapes(l_li).insert(li_box_down) |
| self.nmos_cell.shapes(l_met1).insert(li_box_down) |
| down_gate_connection.shapes(l_npc).insert(npc_box_down) |
| |
| x_mcon_gates = li_box_down.p1.x + free_spc_mcon_gates_h / 2 |
| y_mcon_gates = li_box_down.p1.y + free_spc_mcon_gates_v / 2 |
| y1_mcon_gates = y_mcon_gates + mcon_size |
| |
| for mcon in range(num_hor_mcon_gates): |
| x1_mcon_gates = x_mcon_gates + mcon_size |
| mcon_box_gate = pya.Box( |
| x_mcon_gates, y_mcon_gates, x1_mcon_gates, y1_mcon_gates) |
| if self.connected_gates == 0: # the gate has contacts but no connection |
| down_gate_connection.shapes(l_mcon).insert(mcon_box_gate) |
| else: |
| self.nmos_cell.shapes(l_mcon).insert(mcon_box_gate) |
| for mcon1 in range(num_ver_mcon_gates - 1): |
| y_mcon_gates += mcon_size + mcon_spc |
| y1_mcon_gates += mcon_size + mcon_spc |
| mcon_box_gate = pya.Box( |
| x_mcon_gates, y_mcon_gates, x1_mcon_gates, y1_mcon_gates) |
| if self.connected_gates == 0: # the gate has contacts but no connection |
| down_gate_connection.shapes(l_mcon).insert(mcon_box_gate) |
| else: |
| self.nmos_cell.shapes(l_mcon).insert(mcon_box_gate) |
| y_mcon_gates -= (num_ver_mcon_gates - 1) * \ |
| mcon_size + (num_ver_mcon_gates - 1) * mcon_spc |
| y1_mcon_gates -= (num_ver_mcon_gates - 1) * \ |
| mcon_size + (num_ver_mcon_gates - 1) * mcon_spc |
| x_mcon_gates += mcon_size + mcon_spc |
| x1_mcon_gates += mcon_size + mcon_spc |
| |
| if self.connection == 0 or self.connection == 2: |
| if self.connection == 0: |
| shift_distance = 0 |
| up_gate_connection.shapes(l_poly).insert(contact_gate_box_up) |
| up_gate_connection.shapes(l_poly).insert(neck_box_up) |
| p1_x = contact_gate_box_up.p1.x + free_spc_licon_gate / 2 |
| p1_y = contact_gate_box_up.p1.y + liconpoly_enc_vertical |
| p2_x = contact_gate_box_up.p1.x + free_spc_licon_gate / 2 + licon_size |
| p2_y = contact_gate_box_up.p1.y + liconpoly_enc_vertical + licon_size |
| li_box_up = pya.Box(diff_box.p1.x, contact_gate_box_up.p1.y, |
| diff_box.p1.x + multipliers * diffusion_total_width + ( |
| 2 * multipliers - 2) * npsdm_enc_diff + ( |
| multipliers - 1) * npsdm_spc, contact_gate_box_up.p2.y) |
| |
| gate_connection_text_up = pya.Text(gate_connection_text_up, li_box_up.center().x, |
| li_box_up.center().y) |
| if self.connection_labels: |
| self.nmos_cell.shapes(l_met1_label).insert(gate_connection_text_up) |
| if self.connected_gates == 0: # the gate has contacts but no connection |
| li_box_up = contact_gate_box_up |
| up_gate_connection.shapes(l_li).insert(contact_gate_box_up) |
| up_gate_connection.shapes(l_met1).insert(contact_gate_box_up) |
| else: |
| self.nmos_cell.shapes(l_li).insert(li_box_up) |
| self.nmos_cell.shapes(l_met1).insert(li_box_up) |
| for licon_ct in range(num_horizontal_licon_gate): |
| licon_box_up = pya.Box(p1_x, p1_y, p2_x, p2_y) |
| |
| up_gate_connection.shapes(l_licon).insert(licon_box_up) |
| p1_y += 2 * licon_size |
| p2_y += 2 * licon_size |
| licon_box_up = pya.Box(p1_x, p1_y, p2_x, p2_y) |
| up_gate_connection.shapes(l_licon).insert(licon_box_up) |
| p1_y -= 2 * licon_size |
| p2_y -= 2 * licon_size |
| |
| p1_x += 2 * licon_size |
| p2_x += 2 * licon_size |
| |
| x_mcon_gates = li_box_up.p1.x + free_spc_mcon_gates_h / 2 |
| y_mcon_gates = li_box_up.p1.y + free_spc_mcon_gates_v / 2 |
| y1_mcon_gates = y_mcon_gates + mcon_size |
| |
| for mcon in range(num_hor_mcon_gates): |
| x1_mcon_gates = x_mcon_gates + mcon_size |
| mcon_box_gate = pya.Box( |
| x_mcon_gates, y_mcon_gates, x1_mcon_gates, y1_mcon_gates) |
| if self.connected_gates == 0 : |
| up_gate_connection.shapes(l_mcon).insert(mcon_box_gate) |
| else: |
| self.nmos_cell.shapes(l_mcon).insert(mcon_box_gate) |
| for mcon1 in range(num_ver_mcon_gates - 1): |
| y_mcon_gates += mcon_size + mcon_spc |
| y1_mcon_gates += mcon_size + mcon_spc |
| mcon_box_gate = pya.Box( |
| x_mcon_gates, y_mcon_gates, x1_mcon_gates, y1_mcon_gates) |
| if self.connected_gates == 0 : |
| up_gate_connection.shapes(l_mcon).insert(mcon_box_gate) |
| else: |
| self.nmos_cell.shapes(l_mcon).insert(mcon_box_gate) |
| y_mcon_gates -= (num_ver_mcon_gates - 1) * \ |
| mcon_size + (num_ver_mcon_gates - 1) * mcon_spc |
| y1_mcon_gates -= (num_ver_mcon_gates - 1) * \ |
| mcon_size + (num_ver_mcon_gates - 1) * mcon_spc |
| x_mcon_gates += mcon_size + mcon_spc |
| x1_mcon_gates += mcon_size + mcon_spc |
| up_gate_connection.shapes(l_npc).insert(npc_box_up) |
| |
| mcon_between_fingers_cell.shapes(l_mcon).insert(mcon_between_fingers) |
| |
| li_between_fingers_cell.shapes(l_li).insert(li_between_fingers_path) |
| li_between_fingers_cell.shapes( |
| l_met1).insert(met1_between_fingers_path) |
| |
| if self.connection != 3: |
| down_iteration = self.n |
| up_iteration = self.n |
| # distance to iterate down gate connection |
| down_iteration_distance = diffusion_width + channel_length |
| up_iteration_distance = down_iteration_distance |
| iteration_distance_group = 2 * self.n * \ |
| (diffusion_width + channel_length) |
| if self.connection == 1: # for gate_connection_down_only |
| down_iteration = self.nf |
| up_iteration = 0 |
| down_iteration_distance = diffusion_width + channel_length |
| iteration_distance_group = 0 |
| bottom_connection = pya.CellInstArray(down_gate_connection.cell_index(), pya.Trans(pya.Point(0, 0)), |
| pya.Vector( |
| down_iteration_distance, 0), |
| pya.Vector( |
| iteration_distance_group, 0), down_iteration, |
| math.ceil(self.nf / (2 * self.n))) |
| self.nmos_cell.insert(bottom_connection) |
| |
| elif self.connection == 0: # for gate_connection_up_only |
| up_iteration = self.nf |
| down_iteration = 0 |
| up_iteration_distance = diffusion_width + channel_length |
| shift_distance = 0 |
| iteration_distance_group = 0 |
| |
| repition_b = self.nf / self.n - math.ceil(self.nf / (2 * self.n)) |
| |
| if self.nf == 1: |
| repition_b = 1 |
| |
| upper_connection = pya.CellInstArray(up_gate_connection.cell_index(), pya.Trans(pya.Point(shift_distance, 0)), |
| pya.Vector( |
| up_iteration_distance, 0), |
| pya.Vector(iteration_distance_group, 0), up_iteration, repition_b) |
| |
| self.nmos_cell.insert(upper_connection) |
| |
| else: |
| bottom_connection = pya.CellInstArray(down_gate_connection.cell_index(), pya.Trans(pya.Point(0, 0)), |
| pya.Vector( |
| down_iteration_distance, 0), |
| pya.Vector( |
| iteration_distance_group, 0), down_iteration, |
| math.ceil(self.nf / (2 * self.n))) |
| self.nmos_cell.insert(bottom_connection) |
| |
| upper_connection = pya.CellInstArray(up_gate_connection.cell_index(), pya.Trans(pya.Point(shift_distance, 0)), |
| pya.Vector( |
| up_iteration_distance, 0), |
| pya.Vector( |
| iteration_distance_group, 0), up_iteration, |
| self.nf / self.n - math.ceil(self.nf / (2 * self.n))) |
| |
| self.nmos_cell.insert(upper_connection) |
| |
| self.nmos_cell.flatten(True) |
| |
| |
| if self.nf: |
| licon_between_fingers_arr = pya.CellInstArray(licon_between_fingers_cell.cell_index(), |
| pya.Trans( |
| pya.Point(0, 0)), |
| pya.Vector( |
| 0, 2 * licon_size), |
| pya.Vector( |
| diffusion_width + channel_length, 0), |
| num_ver_licon, |
| self.nf + 1) |
| self.nmos_cell.insert(licon_between_fingers_arr) |
| |
| self.nmos_cell.flatten(True) |
| |
| if self.nf: |
| li_between_fingers_arr = pya.CellInstArray(li_between_fingers_cell.cell_index(), |
| pya.Trans( |
| pya.Point(0, 0)), |
| pya.Vector( |
| diffusion_width + channel_length, 0), |
| pya.Vector(0, 0), |
| self.nf + 1, 1) |
| |
| self.nmos_cell.insert(li_between_fingers_arr) |
| |
| self.nmos_cell.flatten(True) |
| |
| if self.nf: |
| mcon_diff_bet_fing = pya.CellInstArray(mcon_between_fingers_cell.cell_index(), pya.Trans(pya.Point(0, 0)), |
| pya.Vector( |
| diffusion_width + channel_length, 0), |
| pya.Vector(0, mcon_spc + mcon_size), self.nf + 1, num_ver_mcon) |
| self.nmos_cell.insert(mcon_diff_bet_fing) |
| |
| self.nmos_cell.flatten(True) |
| |
| # multiple_transistors = pya.CellInstArray(nmos_cell.cell_index(), pya.Trans(pya.Point(0, 0)), |
| # pya.Vector(diffusion_total_width + 2 * npsdm_enc_diff + npsdm_spc, 0), |
| # pya.Vector(0, 0), multipliers, 1) |
| |
| # top_nmos_cell.insert(multiple_transistors) |
| tap_width = 0.26 * PERCISION |
| if self.connection == 0: # gate_up |
| guard_up = contact_gate_box_up.p2.y |
| guard_down = diff_box.p1.y |
| elif self.connection == 2: # alternate_mode |
| guard_up = contact_gate_box_up.p2.y |
| guard_down = contact_gate_box_down.p1.y |
| |
| elif self.connection == 1: # gate_down |
| guard_down = contact_gate_box_down.p1.y |
| guard_up = diff_box.p2.y |
| |
| else: #No gate connection |
| guard_down = diff_box.p1.y |
| guard_up = diff_box.p2.y |
| |
| guard_ring_lower_left = pya.Point(diff_box.p1.x - 2 * npsdm_enc_diff - npsdm_spc_opposite - tap_width / 2, |
| guard_down - 2 * npsdm_enc_diff - npsdm_spc_opposite - tap_width / 2) |
| guard_ring_upper_left = pya.Point(guard_ring_lower_left.x, |
| guard_up + 2 * npsdm_enc_diff + npsdm_spc_opposite + tap_width / 2) |
| guard_ring_upper_right = pya.Point( |
| multipliers * diffusion_total_width + 2 * multipliers * npsdm_enc_diff + ( |
| multipliers - 1) * npsdm_spc + npsdm_spc_opposite + tap_width / 2, guard_ring_upper_left.y) |
| guard_ring_lower_right = pya.Point( |
| guard_ring_upper_right.x, guard_ring_lower_left.y) |
| # primitive_boundry |
| prbndry_box = pya.Box(guard_ring_lower_left, guard_ring_upper_right) |
| guard_ring_width = (guard_ring_lower_right.x - |
| guard_ring_lower_left.x)/PERCISION |
| guard_ring_height = (guard_ring_upper_right.y - |
| guard_ring_lower_right.y)/PERCISION |
| self.nmos_cell.shapes(l_prbndry).insert(prbndry_box) |
| |
| if self.gr: |
| pass |
| self.draw_guard_ring(layout=self.layout, x=guard_ring_lower_left.x, y=guard_ring_lower_left.y, |
| guard_width=guard_ring_width, guard_height=guard_ring_height, precision=PERCISION, cell=self.nmos_cell) |
| |
| return self.nmos_cell |