def get_mos_tap_info(self, row_info: MOSRowInfo, conn_layer: int, seg: int, options: Param) -> MOSLayInfo: row_type = row_info.row_type guard_ring: bool = options.get('guard_ring', row_info.guard_ring) if guard_ring: sub_type: MOSType = options.get('sub_type', row_type.sub_type) else: sub_type: MOSType = row_type.sub_type lch = self.lch sd_pitch = self.sd_pitch mp_h: int = self.mos_config['mp_h'] mp_po_extx: int = self.mos_config['mp_po_extx'] md_w: int = self.mos_config['md_w'] mos_lay_table = self.tech_info.config['mos_lay_table'] mp_lp = mos_lay_table['MP'] g_info = self.get_conn_info(1, True) d_info = self.get_conn_info(1, False) threshold = row_info.threshold ds_yt = row_info.ds_conn_y[1] mp_yb, mp_yt = row_info['mp_y'] md_yb, md_yt = row_info['md_y'] md_yc = (md_yt + md_yb) // 2 ds_yb = md_yc - (ds_yt - md_yc) fg = seg num_wire = seg + 1 num_po = num_wire + 1 builder = LayoutInfoBuilder() bbox = self._get_mos_active_rect_list(builder, row_info, fg, row_info.sub_width, sub_type) # Connect gate to MP mp_yc = (mp_yb + mp_yt) // 2 mp_delta = (sd_pitch + lch) // 2 + mp_po_extx if num_po & 1: num_vg = num_po // 2 if num_vg & 1: # we have 3 PO left over in the middle num_vg2 = (num_vg - 1) // 2 num_vgm = 2 else: # we have 5 PO left over in the middle num_vg2 = (num_vg - 2) // 2 num_vgm = 4 # draw middle vg vgm_x = bbox.xm - ((num_vgm - 1) * sd_pitch) // 2 mp_xl = vgm_x - mp_delta mp_xr = vgm_x + (num_vgm - 1) * sd_pitch + mp_delta builder.add_rect_arr(mp_lp, BBox(mp_xl, mp_yb, mp_xr, mp_yt)) builder.add_via(g_info.get_via_info('M1_LiPo', vgm_x, mp_yc, mp_h, nx=num_vgm, spx=sd_pitch)) # draw left/right vg if num_vg2 > 0: vg_pitch = 2 * sd_pitch def _add_vg_half(vg_x: int) -> None: xl = vg_x - mp_delta xr = vg_x + mp_delta builder.add_rect_arr(mp_lp, BBox(xl, mp_yb, xr, mp_yt), nx=num_vg2, spx=vg_pitch) builder.add_via(g_info.get_via_info('M1_LiPo', vg_x, mp_yc, mp_h, nx=num_vg2, spx=vg_pitch)) _add_vg_half(0) _add_vg_half((num_wire - 1) * sd_pitch - (num_vg2 - 1) * vg_pitch) else: # even number of PO, can connect pair-wise num_vg = num_po // 2 vg_pitch = 2 * sd_pitch builder.add_rect_arr(mp_lp, BBox(-mp_delta, mp_yb, mp_delta, mp_yt), nx=num_vg, spx=vg_pitch) builder.add_via(g_info.get_via_info('M1_LiPo', 0, mp_yc, mp_h, nx=num_vg, spx=vg_pitch)) # connect drain/source to M1 m1_yc = (md_yb + md_yt) // 2 via_pitch = d_info.via_h + d_info.via_sp vnum_bot = (md_yt - md_yb - d_info.via_bot_enc * 2 + d_info.via_sp) // via_pitch vnum_top = (ds_yt - ds_yb - d_info.via_top_enc * 2 + d_info.via_sp) // via_pitch vnum = min(vnum_top, vnum_bot) builder.add_via(d_info.get_via_info('M1_LiAct', 0, m1_yc, md_w, ortho=False, num=vnum, nx=num_wire, spx=sd_pitch)) edge_info = MOSEdgeInfo(mos_type=sub_type, has_od=True, is_sub=True) be = BlkExtInfo(row_type, threshold, guard_ring, ImmutableList([(fg, sub_type)]), ImmutableSortedDict()) wire_info = (0, num_wire, sd_pitch) return MOSLayInfo(builder.get_info(bbox), edge_info, edge_info, be, be, g_info=wire_info, d_info=wire_info, s_info=wire_info, shorted_ports=ImmutableList())
def get_mos_conn_info(self, row_info: MOSRowInfo, conn_layer: int, seg: int, w: int, stack: int, g_on_s: bool, options: Param) -> MOSLayInfo: assert conn_layer == 1, 'currently only work for conn_layer = 1' lch = self.lch sd_pitch = self.sd_pitch mp_h: int = self.mos_config['mp_h'] mp_po_extx: int = self.mos_config['mp_po_extx'] md_w: int = self.mos_config['md_w'] mos_lay_table = self.tech_info.config['mos_lay_table'] mp_lp = mos_lay_table['MP'] g_info = self.get_conn_info(1, True) d_info = self.get_conn_info(1, False) export_mid = options.get('export_mid', False) export_mid = export_mid and stack == 2 row_type = row_info.row_type ds_yb, ds_yt = row_info.ds_conn_y threshold = row_info.threshold mp_yb, mp_yt = row_info['mp_y'] md_yb, md_yt = row_info['md_y'] fg = seg * stack wire_pitch = stack * sd_pitch conn_pitch = 2 * wire_pitch num_s = seg // 2 + 1 num_d = (seg + 1) // 2 s_xc = 0 d_xc = wire_pitch if g_on_s: num_g = fg // 2 + 1 g_xc = 0 else: num_g = (fg + 1) // 2 g_xc = sd_pitch g_pitch = 2 * sd_pitch builder = LayoutInfoBuilder() bbox = self._get_mos_active_rect_list(builder, row_info, fg, w, row_info.row_type) # Connect gate to MP mp_po_dx = (sd_pitch + lch) // 2 + mp_po_extx builder.add_rect_arr(mp_lp, BBox(g_xc - mp_po_dx, mp_yb, g_xc + mp_po_dx, mp_yt), nx=num_g, spx=g_pitch) # connect gate to M1. mp_yc = (mp_yb + mp_yt) // 2 builder.add_via(g_info.get_via_info('M1_LiPo', g_xc, mp_yc, mp_h, nx=num_g, spx=g_pitch)) # connect drain/source to M1 m1_yc = (md_yb + md_yt) // 2 via_pitch = d_info.via_h + d_info.via_sp vnum1 = (md_yt - md_yb - d_info.via_bot_enc * 2 + d_info.via_sp) // via_pitch vnum2 = (ds_yt - ds_yb - d_info.via_top_enc * 2 + d_info.via_sp) // via_pitch vnum = min(vnum1, vnum2) builder.add_via(d_info.get_via_info('M1_LiAct', d_xc, m1_yc, md_w, ortho=False, num=vnum, nx=num_d, spx=conn_pitch)) builder.add_via(d_info.get_via_info('M1_LiAct', s_xc, m1_yc, md_w, ortho=False, num=vnum, nx=num_s, spx=conn_pitch)) if export_mid: m_xc = sd_pitch num_m = fg + 1 - num_s - num_d m_info = (m_xc, num_m, wire_pitch) builder.add_via(d_info.get_via_info('M1_LiAct', m_xc, m1_yc, md_w, ortho=False, num=vnum, nx=num_m, spx=wire_pitch)) else: m_info = None edge_info = MOSEdgeInfo(mos_type=row_type, has_od=True, is_sub=False) be = BlkExtInfo(row_type, threshold, False, ImmutableList([(fg, row_type)]), ImmutableSortedDict()) return MOSLayInfo(builder.get_info(bbox), edge_info, edge_info, be, be, g_info=(g_xc, num_g, g_pitch), d_info=(d_xc, num_d, conn_pitch), s_info=(s_xc, num_s, conn_pitch), m_info=m_info, shorted_ports=ImmutableList([MOSPortType.G]))