def _draw_dummies(self, template, xintv_list, yintv_list, dx=0, dy=0): mos_layer_table = self.config['mos_layer_table'] od_dummy_lay = mos_layer_table['OD_dummy'] res = template.grid.resolution for xl, xr in xintv_list: for yb, yt in yintv_list: box = BBox(xl, yb, xr, yt, res, unit_mode=True) template.add_rect(od_dummy_lay, box.move_by(dx=dx, dy=dy, unit_mode=True))
def draw_bridges(self, x0, y0, x1, y1, w_gnd, w_bridge, sep_bridge, gap, layer_id, bridge_layer_id): res = self.grid.resolution dir_vec = np.array((x1 - x0, y1 - y0), dtype=int) seg_length = np.max(np.abs(dir_vec)) # type: int dir_unit = dir_vec // seg_length ortho_unit = np.array((-dir_unit[1], dir_unit[0]), dtype=int) if x1 == x0: # vertical wire wire_dir = 'y' box = BBox(-w_gnd // 2, -w_bridge // 2, w_gnd // 2, w_bridge // 2, res, unit_mode=True) else: wire_dir = 'x' box = BBox(-w_bridge // 2, -w_gnd // 2, w_bridge // 2, w_gnd // 2, res, unit_mode=True) num_seg = seg_length // sep_bridge if num_seg > 0: values = np.linspace(0.0, seg_length, num_seg + 2, endpoint=True) bridge_layer = self.grid.tech_info.get_layer_name(bridge_layer_id) orig = np.array((x0, y0), dtype=int) for sel in values[1:-1]: sel = int(round(sel)) mp0 = orig + dir_unit * sel - ortho_unit * gap box0 = box.move_by(dx=mp0[0], dy=mp0[1], unit_mode=True) delta = ortho_unit * 2 * gap box1 = box0.move_by(dx=delta[0], dy=delta[1], unit_mode=True) wbox = box0.merge(box1) self.add_rect(bridge_layer, wbox) for idx in range(bridge_layer_id, layer_id): bot_layer = self.grid.tech_info.get_layer_name(idx) top_layer = self.grid.tech_info.get_layer_name(idx + 1) bot_via_dir = self.grid.get_direction(idx) self.add_via(box0, bot_layer, top_layer, bot_via_dir) self.add_via(box1, bot_layer, top_layer, bot_via_dir)
def _draw_layout_helper(self, num_layer, bot_layer, port_widths, io_width, io_space, width, height, space, show_pins): res = self.grid.resolution width = int(round(width / res)) height = int(round(height / res)) space = int(round(space / res)) io_pitch = io_width + io_space io_layer = AnalogBase.get_mos_conn_layer(self.grid.tech_info) + 1 vm_layer = io_layer + 1 outp_tr = (io_width - 1) / 2 inp_tr = outp_tr + io_pitch inn_tr = inp_tr + io_pitch outn_tr = inn_tr + io_pitch tr_list = [outp_tr, inp_tr, inn_tr, outn_tr] cap_yb = self.grid.get_wire_bounds(io_layer, outn_tr, width=io_width, unit_mode=True)[1] cap_yb += space # draw caps cap_bboxl = BBox(space, cap_yb, width + space, cap_yb + height, res, unit_mode=True) cap_bboxr = cap_bboxl.move_by(dx=width + space, unit_mode=True) capl_ports = self.add_mom_cap(cap_bboxl, bot_layer, num_layer, port_widths=port_widths) capr_ports = self.add_mom_cap(cap_bboxr, bot_layer, num_layer, port_widths=port_widths) # connect caps to dlev/summer inputs/outputs warr_list = [ capl_ports[vm_layer][0], capl_ports[vm_layer][1], capr_ports[vm_layer][0], capr_ports[vm_layer][1] ] hwarr_list = self.connect_matching_tracks(warr_list, io_layer, tr_list, width=io_width) for name, warr in zip(('outp', 'inp', 'inn', 'outn'), hwarr_list): self.add_pin(name, warr, show=show_pins) # calculate size top_layer = bot_layer + num_layer - 1 if self.grid.get_direction(top_layer) == 'x': yt = capr_ports[top_layer][1][0].get_bbox_array(self.grid).top_unit xr = capr_ports[top_layer - 1][1][0].get_bbox_array( self.grid).right_unit else: yt = capr_ports[top_layer - 1][1][0].get_bbox_array( self.grid).top_unit xr = capr_ports[top_layer][1][0].get_bbox_array( self.grid).right_unit self.size = self.grid.get_size_tuple(top_layer, xr + space, yt, round_up=True, unit_mode=True) self.array_box = self.bound_box
def draw_dum_connection(self, template, mos_info, edge_mode, gate_tracks, options): # type: (TemplateBase, Dict[str, Any], int, List[int], Dict[str, Any]) -> None res = self.config['resolution'] mos_lay_table = self.config['mos_layer_table'] lay_name_table = self.config['layer_name'] layout_info = mos_info['layout_info'] sd_yc = mos_info['sd_yc'] lch_unit = layout_info['lch_unit'] sd_pitch = layout_info['sd_pitch'] fg = layout_info['fg'] b_po_y_list = layout_info['b_po_y_list'] g_y_list = layout_info['g_y_list'] d_y_list = layout_info['d_y_list'] b_y_list = layout_info['b_y_list'] mos_constants = self.get_mos_tech_constants(lch_unit) sp_gb_po = mos_constants['sp_gb_po'] po_od_spx = mos_constants['po_od_spx'] w_delta = mos_constants['w_delta'] sd_pitch2 = sd_pitch // 2 width = fg * sd_pitch lch2 = lch_unit // 2 po_name = mos_lay_table['PO_dummy'] od_name = mos_lay_table['OD_dummy'] po_yb = g_y_list[0][0] - sd_yc po_yt = b_po_y_list[0][0] - sp_gb_po - sd_yc od_yb = d_y_list[0][0] - sd_yc od_yt = d_y_list[0][1] + w_delta - sd_yc od_w = sd_pitch - lch_unit - 2 * po_od_spx if (edge_mode & 1) == 0: po_box = BBox(sd_pitch2 - lch2, po_yb, sd_pitch2 + lch2, po_yt, res, unit_mode=True) template.add_rect(po_name, po_box, unit_mode=True) po_xcl = sd_pitch2 * 3 else: po_xcl = sd_pitch2 od_xl = sd_pitch2 + lch2 + po_od_spx od_xr = od_xl + od_w if (edge_mode & 2) == 0: po_box = BBox(width - sd_pitch2 - lch2, po_yb, width - sd_pitch2 + lch2, po_yt, res, unit_mode=True) template.add_rect(po_name, po_box, unit_mode=True) po_xcr = width - sd_pitch2 * 3 else: po_xcr = width - sd_pitch2 # get dummy PO X coordinates nx = (po_xcr - po_xcl) // sd_pitch + 1 po_yt = b_po_y_list[0][1] - sd_yc if nx > 0: # draw dummy PO po_box = BBox(po_xcl - lch2, po_yb, po_xcl + lch2, po_yt, res, unit_mode=True) template.add_rect(po_name, po_box, nx=nx, spx=sd_pitch, unit_mode=True) if fg > 1: od_box = BBox(od_xl, od_yb, od_xr, od_yt, res, unit_mode=True) template.add_rect(od_name, od_box, nx=fg - 1, spx=sd_pitch, unit_mode=True) # draw body M1 m1_name = lay_name_table[1] m1_yb, m1_yt = b_y_list[1] m1_box = BBox(0, m1_yb, width, m1_yt, res, unit_mode=True) m1_box = m1_box.move_by(dy=-sd_yc, unit_mode=True) template.add_rect(m1_name, m1_box) # add body ports dum_layer = self.get_dum_conn_layer() for tidx in gate_tracks: warr = WireArray(TrackID(dum_layer, tidx), m1_box.bottom_unit, m1_box.top_unit, res=res, unit_mode=True) template.add_pin('dummy', warr, show=False)
def draw_mos_connection( self, # type: MOSTechSOIGenericBC template, # type: TemplateBase mos_info, # type: Dict[str, Any] sdir, # type: int ddir, # type: int gate_pref_loc, # type: str gate_ext_mode, # type: int min_ds_cap, # type: bool is_diff, # type: bool diode_conn, # type: bool options, # type: Dict[str, Any] ): # type: (...) -> None stack = options.get('stack', 1) # note: ignore gate_ext_mode, min_ds_cap, is_diff if diode_conn: raise ValueError('Diode connection not supported yet.') res = self.config['resolution'] via_id_table = self.config['via_id'] mos_lay_table = self.config['mos_layer_table'] lay_name_table = self.config['layer_name'] layout_info = mos_info['layout_info'] sd_yc = mos_info['sd_yc'] lch_unit = layout_info['lch_unit'] sd_pitch = layout_info['sd_pitch'] fg = layout_info['fg'] b_po_y_list = layout_info['b_po_y_list'] g_y_list = layout_info['g_y_list'] d_y_list = layout_info['d_y_list'] b_y_list = layout_info['b_y_list'] mos_constants = self.get_mos_tech_constants(lch_unit) gate_layers = mos_constants['gate_layers'] g_via_info = mos_constants['g_via'] b_via_info = mos_constants['b_via'] w_delta = mos_constants['w_delta'] w_body = mos_constants['w_body'] body_po_extx = mos_constants['body_po_extx'] num_via_body = mos_constants['num_via_body'] md_w = mos_constants['md_w'] mp_h = mos_constants['mp_h'] g_drc_info = self.get_conn_drc_info(lch_unit, 'g') if fg % stack != 0: raise ValueError( 'AnalogMosConn: stack = %d must evenly divides fg = %d' % (stack, fg)) wire_pitch = stack * sd_pitch num_seg = fg // stack width = fg * sd_pitch # draw OD # draw main OD od_name = mos_lay_table['OD'] d_od_yb, d_od_yt = d_y_list[0] d_od_yt += w_delta od_box = BBox(-md_w // 2, d_od_yb, width + md_w // 2, d_od_yt, res, unit_mode=True) od_box = od_box.move_by(dy=-sd_yc, unit_mode=True) self.draw_od(template, od_name, od_box, od_type='main') # draw body OD b_od_yb = d_od_yt b_od_yt = b_y_list[0][1] b_od_xc = sd_pitch // 2 od_box = BBox(-w_body // 2, b_od_yb, w_body // 2, b_od_yt, res, unit_mode=True) od_box = od_box.move_by(dx=b_od_xc, dy=-sd_yc, unit_mode=True) self.draw_od(template, od_name, od_box, nx=fg, spx=sd_pitch, od_type='body') # draw PO # draw gate PO bar po_name = mos_lay_table['PO'] po_xc = sd_pitch // 2 po_yb, po_yt = g_y_list[0] g_po_yc = (po_yb + po_yt) // 2 po_box = BBox(po_xc - lch_unit // 2, po_yb, po_xc + (fg - 1) * sd_pitch + lch_unit // 2, po_yt, res, unit_mode=True) po_box = po_box.move_by(dy=-sd_yc, unit_mode=True) template.add_rect(po_name, po_box) # draw gate PO po_yb, po_yt = po_yt, d_y_list[0][1] po_box = BBox(-lch_unit // 2, po_yb, lch_unit // 2, po_yt, res, unit_mode=True) po_box = po_box.move_by(dx=po_xc, dy=-sd_yc, unit_mode=True) template.add_rect(po_name, po_box, nx=fg, spx=sd_pitch * res) # draw gate layers po_yb = d_y_list[0][0] gate_box = BBox(po_box.left_unit, po_yb, po_box.right_unit, po_yt, res, unit_mode=True) gate_box = gate_box.move_by(dy=-sd_yc, unit_mode=True) for gate_lay in gate_layers: template.add_rect(gate_lay, gate_box, nx=fg, spx=sd_pitch * res) # draw body PO bar po_xl = -body_po_extx po_xr = width + body_po_extx po_yb, po_yt = b_po_y_list[0] po_box = BBox(po_xl, po_yb, po_xr, po_yt, res, unit_mode=True) po_box = po_box.move_by(dy=-sd_yc, unit_mode=True) template.add_rect(po_name, po_box) # draw gate connections # draw via to M1 m1_name = lay_name_table[1] via_xc = width // 2 via_yc = g_po_yc via_w, via_h = g_via_info['dim'][0] via_type = via_id_table[(po_name, m1_name)] via_enc_le = g_via_info['bot_enc_le'][0] m1_w_g = g_drc_info[1]['w'] via_enc1 = (mp_h - via_h) // 2 via_enc2 = (m1_w_g - via_h) // 2 enc1 = [via_enc_le, via_enc_le, via_enc1, via_enc1] enc2 = [via_enc_le, via_enc_le, via_enc2, via_enc2] template.add_via_primitive(via_type, loc=[via_xc, via_yc - sd_yc], num_cols=fg - 1, sp_cols=sd_pitch - via_w, enc1=enc1, enc2=enc2, cut_width=via_w, cut_height=via_h, unit_mode=True) # draw gate M1 bar m1_bbox = BBox(0, -m1_w_g // 2, width, m1_w_g // 2, res, unit_mode=True) m1_bbox = m1_bbox.move_by(dy=via_yc - sd_yc, unit_mode=True) template.add_rect(m1_name, m1_bbox) # figure out gate location and number of gate wires if sdir == 0: g_x0 = wire_pitch elif ddir == 0: g_x0 = 0 else: g_x0 = 0 if gate_pref_loc == 's' else wire_pitch num_s = num_seg // 2 + 1 num_d = (num_seg + 1) // 2 num_g = num_s if g_x0 == 0 else num_d # draw gate M1 to M2 vias m2_name = lay_name_table[2] m2_w = g_drc_info[2]['w'] via_w, via_h = g_via_info['dim'][1] via_enc_le1 = g_via_info['bot_enc_le'][1] via_enc_top2 = g_via_info['top_enc_le'][1] via_enc_bot2 = via_yc - via_h // 2 - g_y_list[2][0] via_enc1 = (m1_w_g - via_h) // 2 via_enc2 = (m2_w - via_w) // 2 enc1 = [via_enc_le1, via_enc_le1, via_enc1, via_enc1] enc2 = [via_enc2, via_enc2, via_enc_top2, via_enc_bot2] via_type = via_id_table[(m1_name, m2_name)] template.add_via_primitive(via_type, loc=[g_x0, via_yc - sd_yc], enc1=enc1, enc2=enc2, cut_width=via_w, cut_height=via_h, nx=num_g, spx=2 * wire_pitch, unit_mode=True) # draw gate vias to connection layer self._draw_vertical_vias(template, lch_unit, g_x0, num_g, 2 * wire_pitch, g_y_list[2][0] - sd_yc, g_y_list[2][1] - sd_yc, 2) # draw drain vias to connection layer d_yb, d_yt = d_y_list[-1] self._draw_vertical_vias( template=template, lch_unit=lch_unit, x0=0, num=fg + 1, pitch=sd_pitch, mx_yb=d_yb - sd_yc, mx_yt=d_yt - sd_yc, start_layer=0, end_layer=1, ) self._draw_vertical_vias(template, lch_unit, 0, num_seg + 1, wire_pitch, d_yb - sd_yc, d_yt - sd_yc, 1) # draw body vias to M1 via_type = via_id_table[(od_name, m1_name)] via_w, via_h = b_via_info['dim'] via_sp = b_via_info['sp'] enc1 = b_via_info['enc1'] enc2 = b_via_info['enc2'] b_m1_yb, b_m1_yt = b_y_list[1] via_yc = (b_m1_yb + b_m1_yt) // 2 template.add_via_primitive(via_type, loc=[sd_pitch // 2, via_yc - sd_yc], num_rows=num_via_body, sp_rows=via_sp, enc1=enc1, enc2=enc2, cut_width=via_w, cut_height=via_h, nx=fg, spx=sd_pitch, unit_mode=True) # draw body M1 bar m1_box = BBox(0, b_m1_yb, width, b_m1_yt, res, unit_mode=True) m1_box = m1_box.move_by(dy=-sd_yc, unit_mode=True) template.add_rect(m1_name, m1_box) # add ports mos_conn_layer = self.get_mos_conn_layer() gtr0 = template.grid.coord_to_track(mos_conn_layer, g_x0, unit_mode=True) g_yb, g_yt = g_y_list[-1] g_warrs = self._get_wire_array(mos_conn_layer, gtr0, num_g, g_yb - sd_yc, g_yt - sd_yc, pitch=2 * stack) s_warrs = self._get_wire_array(mos_conn_layer, -0.5, num_s, d_yb - sd_yc, d_yt - sd_yc, pitch=2 * stack) d_warrs = self._get_wire_array(mos_conn_layer, stack - 0.5, num_d, d_yb - sd_yc, d_yt - sd_yc, pitch=2 * stack) template.add_pin('g', g_warrs, show=False) template.add_pin('d', d_warrs, show=False) template.add_pin('s', s_warrs, show=False)