Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)