Ejemplo n.º 1
0
    def _do_dummy_fill(self, top_layer, tapx, tap1, offset, offlev, samp):
        res = self.grid.resolution

        tapx_box = tapx.fill_box
        off_box = offset.fill_box
        tap1_box = tap1.fill_box
        lev_box = offlev.fill_box
        samp_box = samp.fill_box
        yb = tapx_box.bottom_unit
        yt = tapx_box.top_unit
        box1 = BBox(tapx_box.right_unit, yb, off_box.left_unit, yt, res, unit_mode=True)
        box2 = BBox(tap1_box.right_unit, yb, lev_box.left_unit, yt, res, unit_mode=True)

        params = dict(
            mos_type='nch',
            threshold='standard',
            width=box1.width_unit,
            height=box1.height_unit,
        )
        dum1 = self.new_template(params=params, temp_cls=DummyFillActive)
        params['width'] = box2.width_unit
        params['height'] = box2.height_unit
        dum2 = self.new_template(params=params, temp_cls=DummyFillActive)
        self.add_instance(dum1, 'XDUM1', loc=(box1.left_unit, box1.bottom_unit), unit_mode=True)
        self.add_instance(dum2, 'XDUM2', loc=(box2.left_unit, box2.bottom_unit), unit_mode=True)

        hm_layer = top_layer - 1
        for layer in range(1, hm_layer):
            self.do_max_space_fill(layer, bound_box=box1)
            self.do_max_space_fill(layer, bound_box=box2)

        self.fill_box = tapx_box.merge(samp_box)
        self.do_max_space_fill(hm_layer, self.fill_box, fill_pitch=2)
Ejemplo n.º 2
0
    def _draw_g_via(self, template, lch_unit, m1_yb, m1_yt, x_list, r_list,
                    l_list):
        mos_lay_table = self.config['mos_layer_table']
        via_table = self.config['via_id']
        layer_table = self.config['layer_name']

        mos_constants = self.get_mos_tech_constants(lch_unit)
        sd_pitch = mos_constants['sd_pitch']
        g_via_info = mos_constants['laygo_g_via']

        g_v0_w, g_v0_h = g_via_info['dim'][0]

        g_m1_h = g_v0_h + 2 * g_via_info['top_enc_le'][0]
        g_m1_yb = m1_yt - g_m1_h
        g_m1_yc = (g_m1_yb + m1_yt) // 2

        bot_encx = g_via_info['bot_enc_side'][0]
        bot_ency = g_via_info['bot_enc_le'][0]
        top_encx = g_via_info['top_enc_side'][0]
        top_ency = g_via_info['top_enc_le'][0]

        enc1 = [bot_encx, bot_encx, bot_ency, bot_ency]
        enc2 = [top_encx, top_encx, top_ency, top_ency]

        conn_layer = self.get_dig_conn_layer()
        via_id = via_table[(mos_lay_table['PO'], layer_table[conn_layer])]

        for xc, rflag, lflag in zip(x_list, r_list, l_list):
            if rflag:
                template.add_via_primitive(via_id,
                                           [xc + sd_pitch // 2, g_m1_yc],
                                           enc1=enc1,
                                           enc2=enc2,
                                           unit_mode=True)
                template.add_rect(
                    ('M1', 'drawing'),
                    BBox(xc,
                         g_m1_yb,
                         xc + sd_pitch // 2 + g_v0_w // 2 + top_encx,
                         m1_yt,
                         self.res,
                         unit_mode=True))

            if lflag:
                template.add_via_primitive(via_id,
                                           [xc - sd_pitch // 2, g_m1_yc],
                                           enc1=enc1,
                                           enc2=enc2,
                                           unit_mode=True)
                template.add_rect(
                    ('M1', 'drawing'),
                    BBox(xc - sd_pitch // 2 - g_v0_w // 2 - top_encx,
                         g_m1_yb,
                         xc,
                         m1_yt,
                         self.res,
                         unit_mode=True))
Ejemplo n.º 3
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.º 4
0
    def _draw_dummies(self, template, xc, fg, od_po_loc):
        mos_lay_table = self.config['mos_layer_table']

        po_lch = self.res_config['po_lch']
        po_pitch = self.res_config['po_pitch']
        po_od_exty = self.res_config['po_od_exty']
        mp_spy_dum = self.res_config['mp_spy_dum']
        mp_h_dum = self.res_config['mp_h_dum']
        od_mp_ency_dum = self.res_config['od_mp_ency_dum']
        po_h_min = self.res_config['po_h_min']

        mp_pitch = mp_spy_dum + mp_h_dum

        res = template.grid.resolution

        od_w = po_lch + (fg - 1) * po_pitch
        od_xl = xc - od_w // 2
        od_xr = od_xl + od_w
        po_xr = od_xl + po_lch
        od_loc, po_loc = od_po_loc
        od_dum_lay = mos_lay_table['OD_dummy']
        po_dum_lay = mos_lay_table['PO_dummy']
        mp_dum_lay = mos_lay_table['MP_dummy']
        if od_loc:
            # draw dummy transistors
            for od_yb, od_yt in od_loc:
                po_yb = od_yb - po_od_exty
                po_yt = od_yt + po_od_exty
                # draw OD
                template.add_rect(od_dum_lay, BBox(od_xl, od_yb, od_xr, od_yt, res, unit_mode=True))
                # draw PO
                template.add_rect(po_dum_lay, BBox(od_xl, po_yb, po_xr, po_yt, res, unit_mode=True),
                                  nx=fg, spx=po_pitch * res)
                # draw M0PO
                # compute number of M0PO
                od_h = od_yt - od_yb
                avail_sp = od_h - 2 * od_mp_ency_dum
                num_mp = (avail_sp - mp_h_dum) // mp_pitch + 1
                if num_mp > 0:
                    mp_harr = mp_h_dum + (num_mp - 1) * mp_pitch
                    mp_xl = od_xl + po_lch // 2
                    mp_xr = od_xr - po_lch // 2
                    mp_yb = od_yb + (od_h - mp_harr) // 2
                    mp_yt = mp_yb + mp_h_dum
                    template.add_rect(mp_dum_lay, BBox(mp_xl, mp_yb, mp_xr, mp_yt, res,
                                                       unit_mode=True),
                                      ny=num_mp, spy=mp_pitch * res)
        elif po_loc is not None:
            # draw dummy PO only
            po_yb, po_yt = po_loc
            if po_yt - po_yb >= po_h_min:
                template.add_rect(po_dum_lay, BBox(od_xl, po_yb, po_xr, po_yt, res, unit_mode=True),
                                  nx=fg, spx=po_pitch * res)
Ejemplo n.º 5
0
 def intersection_iter(self, box, dx=0, dy=0):
     # type: (BBox, int, int) -> Generator[BBox, None, None]
     """Finds all bounding box that intersects the given box."""
     res = self._res
     test_box = box.expand(dx=dx, dy=dy, unit_mode=True)
     box_iter = self._index.intersection(
         test_box.get_bounds(unit_mode=True), objects='raw')
     for xl, yb, xr, yt, sdx, sdy in box_iter:
         box_real = BBox(xl, yb, xr, yt, res, unit_mode=True)
         box_sp = box_real.expand(dx=sdx, dy=sdy, unit_mode=True)
         if box_sp.overlaps(box) or test_box.overlaps(box_real):
             yield box_real.expand(dx=max(dx, sdx),
                                   dy=max(dy, sdy),
                                   unit_mode=True)
Ejemplo n.º 6
0
    def draw_mos(self, template, layout_info):
        # type: (TemplateBase, Dict[str, Any]) -> None
        """Draw transistor geometries.

        Note: because body-connected transistors in SOI technology cannot be
        drawn on the same row, this method only draws implant and threshold
        layers.  The actual transistor is drawn in draw_mos_connection() method.

        For substrate row, this method just draws a large M1 rectangle to short
        all body connections together.
        """

        res = self.config['resolution']

        sd_pitch = layout_info['sd_pitch']
        fg = layout_info['fg']
        arr_yb, arr_yt = layout_info['arr_y']
        imp_info = layout_info['imp_info']
        blk_type = layout_info['blk_type']

        # compute array/bounding box size
        width = fg * sd_pitch
        template.array_box = BBox(0,
                                  arr_yb,
                                  width,
                                  arr_yt,
                                  res,
                                  unit_mode=True)
        template.prim_bound_box = template.array_box
        template.prim_top_layer = self.get_mos_conn_layer()

        # draw implant layers
        if width > 0:
            for imp_name, (imp_yb, imp_yt) in imp_info.items():
                imp_box = BBox(0, imp_yb, width, imp_yt, res, unit_mode=True)
                template.add_rect(imp_name, imp_box)

        if blk_type == 'sub':
            # draw M1 rectangle for substrate contact
            m1_extx = layout_info['m1_extx']
            mx_yb, mx_yt = layout_info['mx_y']
            sub_box = BBox(-m1_extx,
                           mx_yb,
                           width + m1_extx,
                           mx_yt,
                           res,
                           unit_mode=True)
            m1_name = self.config['layer_name'][1]
            template.add_rect(m1_name, sub_box)
Ejemplo n.º 7
0
    def draw_layout(self):
        # type: () -> None

        res = self.grid.resolution
        edge_margin = int(round(self.params['cap_edge_margin'] / res))
        cap_height = int(round(self.params['cap_height'] / res))
        num_cap_layer = self.params['num_cap_layer']
        show_pins = self.params['show_pins']

        # place instances
        io_layer, io_width, cap_yt, resout = self.place()

        # draw AC coupling caps bounding boxes
        # figure out cap left/right X coordinate
        blk_w = self.grid.get_size_dimension(self.size, unit_mode=True)[0]
        xl = edge_margin
        xr = blk_w - edge_margin

        # draw mom caps and get cap ports
        cap_yt = min(cap_yt, edge_margin + cap_height)
        cap_box = BBox(xl, edge_margin, xr, cap_yt, res, unit_mode=True)
        # make sure both left and right ports on vertical layers are in
        port_parity = {lay: (0, 1) for lay in range(io_layer, io_layer + num_cap_layer, 2)}
        for lay in range(io_layer + 1, io_layer + num_cap_layer, 2):
            port_parity[lay] = (1, 1)
        cap_ports = self.add_mom_cap(cap_box, io_layer, num_cap_layer,
                                     port_widths=io_width, port_parity=port_parity)

        out_layer = io_layer + num_cap_layer - 1
        self.connect_to_tracks(resout, cap_ports[io_layer][0][0].track_id)
        self.add_pin('out', cap_ports[out_layer][0], show=show_pins)
        self.add_pin('in', cap_ports[out_layer][1], show=show_pins)
Ejemplo n.º 8
0
    def _fill_dummy(self, top_layer, fill_top_layer, tot_box, inst_res,
                    inst_cap, dum_params):
        res = self.grid.resolution

        box_res = inst_res.bound_box
        box_cap = inst_cap.bound_box

        # fill empty space
        yt = tot_box.top_unit
        for box in (box_res, box_cap):
            if box.top_unit < yt:
                cur_box = BBox(box.left_unit,
                               box.top_unit,
                               box.right_unit,
                               yt,
                               res,
                               unit_mode=True)
                self._fill_space(cur_box, dum_params, fill_top_layer)

        # fill resistor
        for lay in range(inst_res.master.top_layer, fill_top_layer + 1):
            self.do_max_space_fill(lay, box_res, fill_pitch=2)

        # fill capacitor
        for lay in range(inst_cap.master.top_layer, top_layer):
            self.do_max_space_fill(lay, box_cap, fill_pitch=2)
Ejemplo n.º 9
0
    def draw_layout(self):
        # type: () -> None
        fill_config = self.params['fill_config']
        bot_layer = self.params['bot_layer']
        top_layer = self.params['top_layer']
        show_pins = self.params['show_pins']

        if top_layer is None:
            top_layer = bot_layer + 1
        blk_w, blk_h = self.grid.get_fill_size(top_layer, fill_config, unit_mode=True)
        bnd_box = BBox(0, 0, blk_w, blk_h, self.grid.resolution, unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.array_box = bnd_box

        vdd_list, vss_list = None, None
        for lay in range(bot_layer, top_layer + 1):
            fill_width, fill_space, space, space_le = fill_config[lay]
            vdd_list, vss_list = self.do_power_fill(lay, space, space_le, vdd_warrs=vdd_list,
                                                    vss_warrs=vss_list, fill_width=fill_width,
                                                    fill_space=fill_space, unit_mode=True)
            if lay == bot_layer:
                self.add_pin('VDD_b', vdd_list, show=False)
                self.add_pin('VSS_b', vss_list, show=False)

        self.add_pin('VDD', vdd_list, show=show_pins)
        self.add_pin('VSS', vss_list, show=show_pins)
Ejemplo n.º 10
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.º 11
0
 def intersection_rect_iter(self, box):
     # type: (BBox) -> Generator[BBox, None, None]
     """Finds all bounding box that intersects the given box."""
     res = self._res
     box_iter = self._index.intersection(box.get_bounds(unit_mode=True),
                                         objects='raw')
     for xl, yb, xr, yt, sdx, sdy in box_iter:
         yield BBox(xl, yb, xr, yt, res, unit_mode=True)
Ejemplo n.º 12
0
 def bound_box(self):
     # type: () -> BBox
     xl, yb, xr, yt = self._index.bounds
     return BBox(int(xl),
                 int(yb),
                 int(xr),
                 int(yt),
                 self._res,
                 unit_mode=True)
Ejemplo n.º 13
0
    def draw_layout(self):
        res = self.grid.resolution
        core_params = self.params.copy()
        tot_width = core_params.pop('tot_width')
        show_pins = core_params['show_pins']

        core_params['show_pins'] = False
        core_master = self.new_template(params=core_params,
                                        temp_cls=NPassGateWClkCore)

        sd_pitch = core_master.layout_info.sd_pitch_unit
        tot_width *= sd_pitch
        cur_width = core_master.layout_info.get_total_width(core_master.fg_tot)

        if cur_width > tot_width:
            raise ValueError(
                'Need at least width=%d, but constrained to have width=%d' %
                (cur_width, tot_width))

        xshift = (tot_width - cur_width) // 2
        inst = self.add_instance(core_master, loc=(xshift, 0), unit_mode=True)

        vdd_warrs = inst.get_all_port_pins('VDD')
        vss_warrs = inst.get_all_port_pins('VSS')

        # set size
        vdd_lay_id = vdd_warrs[0].layer_id
        top_layer = vdd_lay_id + 2
        height = inst.bound_box.height_unit
        self.set_size_from_bound_box(
            top_layer, BBox(0, 0, tot_width, height, res, unit_mode=True))

        # fill and export supplies
        sup_width = 2
        fill_margin = 0.5
        edge_margin = 0.2
        lay_id = vdd_lay_id + 1
        vdd_warrs, vss_warrs = self.do_power_fill(lay_id,
                                                  vdd_warrs,
                                                  vss_warrs,
                                                  sup_width=sup_width,
                                                  fill_margin=fill_margin,
                                                  edge_margin=edge_margin)
        lay_id += 1
        edge_margin = 0
        vdd_warrs, vss_warrs = self.do_power_fill(lay_id,
                                                  vdd_warrs,
                                                  vss_warrs,
                                                  sup_width=sup_width,
                                                  fill_margin=fill_margin,
                                                  edge_margin=edge_margin)

        self.add_pin('VSS', vss_warrs, show=show_pins)
        self.add_pin('VDD', vdd_warrs, show=show_pins)
        for port_name in inst.port_names_iter():
            if port_name != 'VSS' and port_name != 'VDD':
                self.reexport(inst.get_port(port_name), show=show_pins)
Ejemplo n.º 14
0
    def draw_layout(self):
        """ Specifies the creation of the lumerical shapes """

        self.add_rect(layer='SI',
                      bbox=BBox(left=0,
                                bottom=0,
                                right=self.params['width'],
                                top=self.params['length'],
                                resolution=self.grid.resolution,
                                unit_mode=False),
                      unit_mode=False)
Ejemplo n.º 15
0
    def draw_layout(self):
        # type: () -> None
        fill_config = self.params['fill_config']
        decap_params = self.params['decap_params']
        nx = self.params['nx']
        ny = self.params['ny']
        top_layer = self.params['top_layer']
        show_pins = self.params['show_pins']

        params = decap_params.copy()
        params['nx'] = nx
        params['ny'] = ny
        params['fill_config'] = fill_config
        params['top_layer'] = top_layer

        master_cap = self.new_template(params=params, temp_cls=DecapFillCore)

        w_blk, h_blk = self.grid.get_fill_size(top_layer, fill_config, unit_mode=True)
        w_tot = w_blk * nx
        h_tot = h_blk * ny
        dx = (w_tot - master_cap.bound_box.width_unit) // 2
        cap_inst = self.add_instance(master_cap, 'XCAP', (dx, 0), unit_mode=True)
        hm_layer = master_cap.mos_conn_layer + 1

        if top_layer <= hm_layer:
            raise ValueError('top layer must be at least %d' % (hm_layer + 1))

        # set size
        res = self.grid.resolution
        self.array_box = bnd_box = BBox(0, 0, w_tot, h_tot, res, unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.add_cell_boundary(bnd_box)

        # do power fill
        ym_layer = hm_layer + 1
        vdd_list = cap_inst.get_all_port_pins('VDD')
        vss_list = cap_inst.get_all_port_pins('VSS')
        fill_width, fill_space, space, space_le = fill_config[ym_layer]
        vdd_list, vss_list = self.do_power_fill(ym_layer, space, space_le, vdd_warrs=vdd_list,
                                                vss_warrs=vss_list, fill_width=fill_width,
                                                fill_space=fill_space, unit_mode=True)
        if top_layer > ym_layer:
            params = dict(fill_config=fill_config, show_pins=False)
            inst = None
            for bot_layer in range(ym_layer, top_layer):
                params['bot_layer'] = bot_layer
                master = self.new_template(params=params, temp_cls=PowerFill)
                inst = self.add_instance(master, 'X%d' % bot_layer, nx=nx, ny=ny,
                                         spx=w_blk, spy=h_blk, unit_mode=True)
            vdd_list = self.connect_wires(inst.get_all_port_pins('VDD'))
            vss_list = self.connect_wires(inst.get_all_port_pins('VSS'))

        self.add_pin('VDD', vdd_list, show=show_pins)
        self.add_pin('VSS', vss_list, show=show_pins)
Ejemplo n.º 16
0
    def get_substrate_box(self):
        # type: () -> Tuple[Optional[BBox], Optional[BBox]]
        """Returns the substrate tap bounding box."""
        (imp_yb, imp_yt), (thres_yb, thres_yt) = self._sub_bndy

        xl, xr = self._sub_bndx
        if xl is None or xr is None:
            return None, None

        res = self.grid.resolution
        if imp_yb is None or imp_yt is None:
            imp_box = None
        else:
            imp_box = BBox(xl, imp_yb, xr, imp_yt, res, unit_mode=True)
        if thres_yb is None or thres_yt is None:
            thres_box = None
        else:
            thres_box = BBox(xl, thres_yb, xr, thres_yt, res, unit_mode=True)

        return imp_box, thres_box
Ejemplo n.º 17
0
    def draw_layout(self):
        mos_type = self.params['mos_type']
        threshold = self.params['threshold']
        w = self.params['width']
        h = self.params['height']

        # draw fill
        tech_cls = self.grid.tech_info.tech_params['layout']['mos_tech_class']
        tech_cls.draw_active_fill(self, mos_type, threshold, w, h)

        # set size
        box = BBox(0, 0, w, h, self.grid.resolution, unit_mode=True)
        self.prim_top_layer = 1
        self.array_box = self.prim_bound_box = box

        self.grid.tech_info.draw_device_blockage(self)
Ejemplo n.º 18
0
    def _draw_layout_helper(self, cap_bot_layer, cap_top_layer, cap_width,
                            cap_height, sub_lch, sub_w, sub_type, threshold,
                            show_pins):
        res = self.grid.resolution
        cap_width = int(round(cap_width / res))
        cap_height = int(round(cap_height / res))

        blk_w, _ = self.grid.get_block_size(cap_top_layer, unit_mode=True)
        w_pitch, _ = self.grid.get_size_pitch(cap_top_layer, unit_mode=True)
        tot_width = -(-cap_width // blk_w) * blk_w

        sub_params = dict(
            lch=sub_lch,
            w=sub_w,
            sub_type=sub_type,
            threshold=threshold,
            top_layer=cap_top_layer,
            blk_width=tot_width // w_pitch,
            show_pins=False,
        )
        sub_master = self.new_template(params=sub_params,
                                       temp_cls=SubstrateContact)
        inst = self.add_instance(sub_master, inst_name='XSUB')
        port_name = 'VDD' if sub_type == 'ntap' else 'VSS'
        self.reexport(inst.get_port(port_name), show=show_pins)

        subw, subh = self.grid.get_size_dimension(sub_master.size,
                                                  unit_mode=True)
        self.size = self.grid.get_size_tuple(cap_top_layer,
                                             tot_width,
                                             subh + cap_height,
                                             round_up=True,
                                             unit_mode=True)
        self.array_box = self.bound_box

        cap_xl = self.array_box.xc_unit - cap_width // 2
        cap_box = BBox(cap_xl,
                       subh,
                       cap_xl + cap_width,
                       subh + cap_height,
                       res,
                       unit_mode=True)
        cap_ports = self.add_mom_cap(cap_box, cap_bot_layer,
                                     cap_top_layer - cap_bot_layer + 1, 2)
        cp, cn = cap_ports[cap_top_layer]
        self.add_pin('plus', cp, show=show_pins)
        self.add_pin('minus', cn, show=show_pins)
Ejemplo n.º 19
0
    def draw_layout(self):
        """ Specifies the creation of the lumerical shapes """

        self.add_rect(layer='SI',
                      bbox=BBox(left=0,
                                bottom=0,
                                right=self.params['width'],
                                top=self.params['length'],
                                resolution=self.grid.resolution,
                                unit_mode=False),
                      unit_mode=False)
        sub_master = self.new_template(params={
            'length': self.params['width'],
            'width': self.params['length']
        },
                                       temp_cls=AddSubRect)
        self.add_instance(master=sub_master)
Ejemplo n.º 20
0
    def _draw_mom_cap(self, cap_x_list, bot_layer, top_layer, cap_spy,
                      cap_h_list, port_tr_w, show_pins):
        grid = self.grid
        res = grid.resolution

        # get port location
        bnd_box = self.bound_box
        cap_yt = bnd_box.top_unit - cap_spy

        # draw MOM cap
        num_layer = top_layer - bot_layer + 1

        out_list = []
        out_res_info = in_res_info = None
        for cap_idx, ((cap_xl, cap_xr),
                      cap_h) in enumerate(zip(cap_x_list, cap_h_list)):
            cap_yb = max(bnd_box.bottom_unit + cap_spy, cap_yt - cap_h)
            cap_box = BBox(cap_xl, cap_yb, cap_xr, cap_yt, res, unit_mode=True)
            parity = cap_idx % 2
            port_par = (parity, 1 - parity)
            ports = self.add_mom_cap(cap_box,
                                     bot_layer,
                                     num_layer,
                                     port_widths=port_tr_w,
                                     port_parity={
                                         bot_layer: port_par,
                                         top_layer: port_par
                                     })
            if parity == 0:
                warr_in = ports[top_layer][1 - parity][0]
                out = ports[bot_layer][parity][0]
            else:
                warr_in = ports[top_layer][parity][0]
                out = ports[bot_layer][1 - parity][0]

            out_list.append(out)
            # draw output metal resistor and port
            out_port, out_res_info = self._add_metal_res(out, go_up=True)
            self.add_pin('out<%d>' % cap_idx, out_port, show=show_pins)
            # draw clock metal resistor and port
            in_port, in_res_info = self._add_metal_res(warr_in, go_up=False)
            self.add_pin('in<%d>' % cap_idx, in_port, show=show_pins)

        # return ports
        return out_list, out_res_info, in_res_info
Ejemplo n.º 21
0
    def draw_res_boundary(self, template, boundary_type, layout_info, end_mode):
        # type: (TemplateBase, str, Dict[str, Any]) -> None
        wcore, hcore = self.res_config['core_size']
        wedge, hedge = self.res_config['edge_size']
        template_lib = self.res_config['template_lib']
        core_cell = self.res_config['%s_cell' % boundary_type]

        template.add_instance_primitive(template_lib, core_cell, (0, 0))

        if boundary_type == 'corner':
            wbox, hbox = wedge, hedge
        elif boundary_type == 'lr':
            wbox, hbox = wedge, hcore
        else:
            wbox, hbox = wcore, hedge

        res = template.grid.resolution
        template.prim_bound_box = BBox(0, 0, wbox, hbox, res, unit_mode=True)
        template.array_box = template.prim_bound_box
        template.prim_top_layer = self.get_bot_layer()
Ejemplo n.º 22
0
    def draw_res_core(self, template, layout_info):
        # type: (TemplateBase, Dict[str, Any]) -> None
        template_lib = self.res_config['template_lib']
        core_cell = self.res_config['core_cell']
        btr, ttr = self.res_config['port_tracks']
        xl, xr = self.res_config['port_coord']
        wcore, hcore = self.res_config['core_size']

        template.add_instance_primitive(template_lib, core_cell, (0, 0))
        port_layer = self.get_bot_layer()

        warr = template.add_wires(port_layer, btr, xl, xr, unit_mode=True)
        template.add_pin('bot', warr, show=False)
        warr = template.add_wires(port_layer, ttr, xl, xr, unit_mode=True)
        template.add_pin('top', warr, show=False)

        res = template.grid.resolution
        template.prim_bound_box = BBox(0, 0, wcore, hcore, res, unit_mode=True)
        template.array_box = template.prim_bound_box
        template.prim_top_layer = port_layer
Ejemplo n.º 23
0
    def draw_layout(self):
        """ Specifies the creation of the lumerical shapes """

        self.add_rect(
            layer='SI',
            coord1=self.params['point1'],
            coord2=self.params['point2'],
            unit_mode=False,
        )

        self.add_rect(
            layer='SI',
            bbox=BBox(
                left=1,
                bottom=-10,
                right=10,
                top=-7,
                resolution=self.grid.resolution,
                unit_mode=False
            ),
            unit_mode=False
        )
Ejemplo n.º 24
0
 def bbox_rotate(self, bbox: BBox, angle: float) -> BBox:
     """
     Given a bbox, finds coordinates for new rotated bbox
     Parameters
     ----------
     bbox : BBox
         input bbox
     angle : float
         angle in radians to rotate the bbox
     Returns
     -------
     bbox : BBox
         output bbox
     """
     ll = [bbox.left, bbox.bottom]
     new_x = math.cos(angle) * ll[0] - math.sin(angle) * ll[1]
     new_y = math.sin(angle) * ll[0] + math.cos(angle) * ll[1]
     return BBox(left=new_x,
                 bottom=new_y,
                 right=new_x + self._res,
                 top=new_y + self._res,
                 unit_mode=False,
                 resolution=self._res)
Ejemplo n.º 25
0
    def set_digital_size(self, num_cols=None):
        if self._dig_size is None:
            if num_cols is None:
                num_cols = 0
                for intv in self._used_list:
                    num_cols = max(num_cols, intv.get_end())

            self._laygo_info.set_num_col(num_cols)
            self._dig_size = num_cols, self._num_rows

            top_layer = self._laygo_info.top_layer

            width = self._laygo_info.tot_width
            height = self._ytop[1]
            bound_box = BBox(0,
                             0,
                             width,
                             height,
                             self.grid.resolution,
                             unit_mode=True)
            self.set_size_from_bound_box(top_layer, bound_box)
            if not self._laygo_info.draw_boundaries:
                self.array_box = bound_box
Ejemplo n.º 26
0
    def get_via0_info(self, xc, yc, wres, resolution):
        """Compute resistor CO parameters and metal 1 bounding box."""
        mos_layer_table = self.config['mos_layer_table']
        layer_table = self.config['layer_name']
        via_id_table = self.config['via_id']
        co_w = self.res_config['co_w']
        co_sp = self.res_config['co_sp']
        po_co_encx, po_co_ency = self.res_config['po_co_enc']
        m1_co_encx, m1_co_ency = self.res_config['m1_co_enc']
        num_co = (wres - po_co_encx * 2 + co_sp) // (co_w + co_sp)
        m1_h = co_w + 2 * m1_co_ency

        # get via parameters
        po_name = mos_layer_table['PO']
        m1_name = layer_table[1]
        via_id = via_id_table[(po_name, m1_name)]
        via_params = dict(
            via_type=via_id,
            loc=[xc, yc],
            num_cols=num_co,
            sp_cols=co_sp,
            enc1=[po_co_encx, po_co_encx, po_co_ency, po_co_ency],
            enc2=[m1_co_encx, m1_co_encx, m1_co_ency, m1_co_ency],
            unit_mode=True)

        varr_w = num_co * (co_w + co_sp) - co_sp
        m1_type = self.tech_info.get_layer_type(layer_table[1])
        m1_min_len = self.tech_info.get_min_length_unit(m1_type, m1_h)
        m1_w = max(2 * m1_co_encx + varr_w, m1_min_len)
        m1_xl = xc - m1_w // 2
        m1_xr = m1_xl + m1_w
        m1_yb = yc - m1_h // 2
        m1_yt = m1_yb + m1_h

        m1_box = BBox(m1_xl, m1_yb, m1_xr, m1_yt, resolution, unit_mode=True)
        return via_params, m1_box
Ejemplo n.º 27
0
    def _place(self):
        rxclk_params = self.params['rxclk_params'].copy()
        core_params = self.params['core_params'].copy()
        ctle_params = self.params['ctle_params'].copy()
        dlev_cap_params = self.params['dlev_cap_params'].copy()
        bus_margin = self.params['bus_margin']
        show_pins = self.params['show_pins']

        # create template masters
        rxclk_params['parity'] = 0
        rxclk_params['show_pins'] = False
        clk_master0 = self.new_template(params=rxclk_params, temp_cls=RXClkArray)
        rxclk_params['parity'] = 1
        clk_master1 = self.new_template(params=rxclk_params, temp_cls=RXClkArray)

        core_params['show_pins'] = False
        core_master = self.new_template(params=core_params, temp_cls=RXCore)

        in_xm_offset = core_master.in_offset
        ctle_params['cap_port_offset'] = in_xm_offset
        ctle_params['show_pins'] = False
        ctle_master = self.new_template(params=ctle_params, temp_cls=CTLE)

        dlev_cap_params['show_pins'] = False
        dlev_cap_params['io_width'] = core_params['hm_cur_width']
        dlev_cap_params['io_space'] = core_params['diff_space']
        dcap_master = self.new_template(params=dlev_cap_params, temp_cls=DLevCap)

        clkw, clkh = self.grid.get_size_dimension(clk_master0.size, unit_mode=True)
        corew, coreh = self.grid.get_size_dimension(core_master.size, unit_mode=True)
        ctlew, ctleh = self.grid.get_size_dimension(ctle_master.size, unit_mode=True)

        # compute X coordinate
        # TODO: less hard coding
        vbus_layer = AnalogBase.get_mos_conn_layer(self.grid.tech_info) + 2
        ibias_width = 2
        bus_ibias_names = ['{}_ibias_nmos_intsum', '{}_ibias_dfe<1>', '{}_ibias_dfe<2>',
                           '{}_ibias_dfe<3>', '{}_ibias_offset']
        bus_vss_names = ['bias_nmos_analog', 'bias_nmos_digital', 'bias_nmos_summer', 'bias_nmos_tap1', ]
        bus_vdd_names = ['bias_pmos_analog', 'bias_pmos_digital', 'bias_pmos_summer',
                         '{}_bias_ffe', '{}_bias_dlevp', '{}_bias_dlevn', ]
        bus_en_names = ['{}_en_dfe1', '{}_offp', '{}_offn']

        num_track_tot = len(bus_ibias_names) + len(bus_vss_names) + \
                        len(bus_vdd_names) + len(bus_en_names) + (2 + bus_margin * 2) * 4
        # TODO: handle cases where vbus_layer's pitch is not multiple of all lower vertical layer's pitch
        bias_width = self.grid.get_track_pitch(vbus_layer, unit_mode=True) * num_track_tot

        maxw = max(clkw, corew)
        if maxw == corew:
            # add some room
            blk_w = self.grid.get_block_size(core_master.size[0], unit_mode=True)[0]
            maxw += -(-400 // blk_w) * blk_w
        x_clk = bias_width + ctlew + maxw - clkw
        x_core = bias_width + ctlew + maxw - corew

        clk_inst0 = self.add_instance(clk_master0, 'XCLK0', loc=(x_clk, clkh), orient='MX', unit_mode=True)
        core_inst = self.add_instance(core_master, 'XCORE', loc=(x_core, clkh), unit_mode=True)
        clk_inst1 = self.add_instance(clk_master1, 'XCLK1', loc=(x_clk, clkh + coreh), unit_mode=True)
        ctle_inst = self.add_instance(ctle_master, 'XCTLE', loc=(bias_width, 0), unit_mode=True)

        bus_order = [(bus_en_names, 'VDD', 1), (bus_vdd_names, 'VDD', 1),
                     (bus_vss_names, 'VSS', 1), (bus_ibias_names, 'VSS', ibias_width)]
        vdd_list = []
        vss_list = []
        self._connect_bias_wires(clk_inst0, core_inst, [core_inst, clk_inst1], clkh, 'odd', bus_order,
                                 vdd_list, vss_list, x_core)
        bus_order = bus_order[::-1]
        self._connect_bias_wires(clk_inst1, core_inst, [clk_inst1], clk_inst1.location_unit[1], 'even', bus_order,
                                 vdd_list, vss_list, x_core)

        # move ctle to center of rxcore
        mid = core_inst.location_unit[1] + coreh // 2
        ctle_inst.move_by(dy=mid - ctleh // 2, unit_mode=True)

        dcap_inst1 = self.add_instance(dcap_master, 'XDCAP1', loc=(x_core + corew, 0), orient='MX', unit_mode=True)
        dcap_inst0 = self.add_instance(dcap_master, 'XDCAP0', loc=(x_core + corew, 0), unit_mode=True)
        # move dcap inst to right Y location, then connect and export
        for idx, dinst in enumerate((dcap_inst0, dcap_inst1)):
            core_outp = core_inst.get_all_port_pins('outp_dlev<%d>' % idx)[0]
            dcap_outp = dinst.get_all_port_pins('outp')[0]
            hm_layer = core_outp.layer_id
            hm_pitch = self.grid.get_track_pitch(hm_layer)
            delta = core_outp.track_id.base_index - dcap_outp.track_id.base_index
            dinst.move_by(dy=hm_pitch * delta)

            for dname, cname in zip(['outp', 'outn', 'inp', 'inn'],
                                    ['outp_dlev', 'outn_dlev', 'outp_summer', 'outn_summer']):
                cname += '<%d>' % idx
                wlist = core_inst.get_all_port_pins(cname) + dinst.get_all_port_pins(dname)
                w = self.connect_wires(wlist)
                if dname.startswith('out'):
                    self.add_pin(cname, w, show=show_pins)

        # compute size
        xr = dcap_inst0.array_box.right_unit
        yt = clk_inst1.array_box.top_unit
        self.array_box = BBox(0, 0, xr, yt, self.grid.resolution, unit_mode=True)
        self.set_size_from_array_box(clk_master1.size[0])

        return clk_inst0, clk_inst1, core_inst, ctle_inst, vdd_list, vss_list, bias_width
Ejemplo n.º 28
0
    def draw_layout(self):
        # type: () -> None
        nin0 = self.params['nin0']
        nin1 = self.params['nin1']
        res_params = self.params['res_params']
        mux_params = self.params['mux_params']
        fill_config = self.params['fill_config']
        nout = self.params['nout']
        top_layer = self.params['top_layer']
        fill_orient_mode = self.params['fill_orient_mode']
        show_pins = self.params['show_pins']

        if nout <= 0:
            raise ValueError('nout must be positive.')

        res = self.grid.resolution
        num_mux_left = nout // 2
        num_mux_right = nout - num_mux_left
        num_col = 2**nin0
        num_row = 2**nin1
        nbits_tot = nin0 + nin1

        # make masters
        r_params = res_params.copy()
        r_params['nx'] = num_col
        r_params['ny'] = num_row
        r_params['show_pins'] = False
        res_master = self.new_template(params=r_params, temp_cls=ResLadderTop)
        sup_layer = res_master.top_layer + 1
        if top_layer is None:
            top_layer = res_master.top_layer + 1
        elif top_layer < sup_layer:
            raise ValueError('top_layer must be >= %d' % sup_layer)

        m_params = mux_params.copy()
        m_params['col_nbits'] = nin0
        m_params['row_nbits'] = nin1
        m_params['top_layer'] = res_master.top_layer
        m_params['show_pins'] = False
        if num_mux_left > 0:
            m_params['num_mux'] = num_mux_left
            lmux_master = self.new_template(params=m_params,
                                            temp_cls=RLadderMuxArray)
        else:
            lmux_master = None

        m_params['num_mux'] = num_mux_right
        rmux_master = self.new_template(params=m_params,
                                        temp_cls=RLadderMuxArray)

        # figure out Y coordinates
        mux_warr = rmux_master.get_port('in<1>').get_pins()[0]
        pin_layer = mux_warr.layer_id
        tr_pitch = self.grid.get_track_pitch(pin_layer, unit_mode=True)
        mux_tr = mux_warr.track_id.base_index
        res_tr = res_master.get_port(
            'out<1>').get_pins()[0].track_id.base_index
        res_yo = int(round(max(mux_tr - res_tr, 0))) * tr_pitch
        mux_yo = int(round(max(res_tr - mux_tr, 0))) * tr_pitch

        # place left mux
        sup_table = {'VDD': [], 'VSS': []}
        if lmux_master is not None:
            blk_w, blk_h = self.grid.get_size_dimension(lmux_master.size,
                                                        unit_mode=True)
            lmux_inst = self.add_instance(lmux_master,
                                          loc=(blk_w, mux_yo),
                                          orient='MY',
                                          unit_mode=True)

            # gather supply and re-export inputs
            for port_name, port_list in sup_table.items():
                port_list.extend(lmux_inst.port_pins_iter(port_name))
            for mux_idx in range(num_mux_left):
                self.reexport(lmux_inst.get_port('out<%d>' % mux_idx),
                              show=show_pins)
                for bit_idx in range(nbits_tot):
                    self.reexport(lmux_inst.get_port(
                        'code<%d>' % (bit_idx + mux_idx * nbits_tot)),
                                  show=show_pins)

            vref_left = int(
                round(lmux_inst.get_port('in<1>').get_pins()[0].lower / res))
            xo = blk_w
            self.array_box = lmux_inst.array_box
        else:
            xo = 0
            vref_left = -1
            self.array_box = BBox.get_invalid_bbox()

        # place resistor ladder
        res_inst = self.add_instance(res_master,
                                     loc=(xo, res_yo),
                                     unit_mode=True)
        for port_name, port_list in sup_table.items():
            port_list.extend(res_inst.port_pins_iter(port_name))
        if vref_left < 0:
            vref_left = int(
                round(res_inst.get_port('out<1>').get_pins()[0].lower / res))

        res_w, res_h = self.grid.get_size_dimension(res_master.size,
                                                    unit_mode=True)
        xo += res_w
        # place right mux
        rmux_inst = self.add_instance(rmux_master,
                                      loc=(xo, mux_yo),
                                      unit_mode=True)
        rmux_w, rmux_h = self.grid.get_size_dimension(rmux_master.size,
                                                      unit_mode=True)
        xo += rmux_w
        out_off = num_mux_left
        in_off = num_mux_left * nbits_tot
        for port_name, port_list in sup_table.items():
            port_list.extend(rmux_inst.port_pins_iter(port_name))
        for mux_idx in range(num_mux_right):
            old_name = 'out<%d>' % mux_idx
            new_name = 'out' if nout == 1 else 'out<%d>' % (mux_idx + out_off)
            self.reexport(rmux_inst.get_port(old_name),
                          net_name=new_name,
                          show=show_pins)
            for bit_idx in range(nbits_tot):
                old_name = 'code<%d>' % (bit_idx + mux_idx * nbits_tot)
                new_name = 'code<%d>' % (bit_idx + mux_idx * nbits_tot +
                                         in_off)
                self.reexport(rmux_inst.get_port(old_name),
                              net_name=new_name,
                              show=show_pins)
        vref_right = int(
            round(rmux_inst.get_port('in<1>').get_pins()[0].upper / res))

        for vref_idx in range(2**nbits_tot):
            vref_warr = rmux_inst.get_port('in<%d>' % vref_idx).get_pins()[0]
            vref_tr = vref_warr.track_id.base_index
            vref_layer = vref_warr.track_id.layer_id
            self.add_wires(vref_layer,
                           vref_tr,
                           vref_left,
                           vref_right,
                           unit_mode=True)

        # set size
        yo = max(mux_yo + rmux_h, res_yo + res_h)
        blk_w, blk_h = self.grid.get_fill_size(top_layer,
                                               fill_config,
                                               unit_mode=True)
        nfill_x = -(-xo // blk_w)  # type: int
        nfill_y = -(-yo // blk_h)
        bnd_box = BBox(0,
                       0,
                       nfill_x * blk_w,
                       nfill_y * blk_h,
                       res,
                       unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.array_box = bnd_box
        self.add_cell_boundary(bnd_box)

        # connect supplies
        vdd_list = sup_table['VDD']
        vss_list = sup_table['VSS']
        flip_fill = (fill_orient_mode & 2 != 0)
        fill_width, fill_space, space, space_le = fill_config[sup_layer]
        vdd_list, vss_list = self.do_power_fill(sup_layer,
                                                space,
                                                space_le,
                                                vdd_warrs=vdd_list,
                                                vss_warrs=vss_list,
                                                fill_width=fill_width,
                                                fill_space=fill_space,
                                                flip=flip_fill,
                                                unit_mode=True)
        # add fill cells
        if top_layer > sup_layer:
            fill_params = dict(
                fill_config=fill_config,
                bot_layer=sup_layer,
                top_layer=top_layer,
                show_pins=False,
            )
            orient = PowerFill.get_fill_orient(fill_orient_mode)
            x0 = 0 if (fill_orient_mode & 1 == 0) else 1
            y0 = 0 if (fill_orient_mode & 2 == 0) else 1
            loc = (x0 * blk_w, y0 * blk_h)
            fill_master = self.new_template(params=fill_params,
                                            temp_cls=PowerFill)
            fill_inst = self.add_instance(fill_master,
                                          'XFILL',
                                          loc=loc,
                                          orient=orient,
                                          nx=nfill_x,
                                          ny=nfill_y,
                                          spx=blk_w,
                                          spy=blk_h,
                                          unit_mode=True)
            vdd_list = fill_inst.get_all_port_pins('VDD')
            vss_list = fill_inst.get_all_port_pins('VSS')

        self.add_pin('VDD', self.connect_wires(vdd_list), show=show_pins)
        self.add_pin('VSS', self.connect_wires(vss_list), show=show_pins)

        res_sch_params = res_master.sch_params.copy()
        mux_sch_params = rmux_master.mux_params.copy()
        del res_sch_params['nout']
        del mux_sch_params['nin0']
        del mux_sch_params['nin1']
        self._sch_params = dict(
            nin0=nin0,
            nin1=nin1,
            nout=nout,
            res_params=res_sch_params,
            mux_params=mux_sch_params,
        )
Ejemplo n.º 29
0
    def draw_boundaries(
            self,  # type: LaygoTech
            template,  # type: TemplateBase
            laygo_info,  # type: LaygoBaseInfo
            num_col,  # type: int
            yt,  # type: int
            bot_end_master,  # type: LaygoEndRow
            top_end_master,  # type: LaygoEndRow
            edgel_infos,  # type: List[Tuple[int, str, Dict[str, Any]]]
            edger_infos,  # type: List[Tuple[int, str, Dict[str, Any]]]
    ):
        # type: (...) -> Tuple[BBox, List[WireArray], List[WireArray]]
        """Draw boundaries for LaygoBase/DigitalBase.

        Parameters
        ----------
        template : TemplateBase
            the LaygoBase/DigitalBase object to draw layout in.
        laygo_info : LaygoBaseInfo
            the LaygoBaseInfo object.
        num_col : int
            number of primitive columns in the template.
        yt : int
            the top Y coordinate of the template.  Used to determine top end row placement.
        bot_end_master: LaygoEndRow
            the bottom LaygoEndRow master.
        top_end_master : LaygoEndRow
            the top LaygoEndRow master.
        edgel_infos:  List[Tuple[int, str, Dict[str, Any]]]
            a list of Y coordinate, orientation, and parameters for left edge blocks.
        edger_infos:  List[Tuple[int, str, Dict[str, Any]]]
            a list of Y coordinate, orientation, and parameters for right edge blocks.

        Returns
        -------
        arr_box : BBox
            the array box.
        vdd_warrs : List[WireArray]
            any VDD wires in the edge block due to guard ring.
        vss_warrs : List[WireArray]
            any VSS wires in the edge block due to guard ring.
        """
        end_mode = laygo_info.end_mode
        guard_ring_nf = laygo_info.guard_ring_nf
        col_width = laygo_info.col_width

        nx = num_col
        spx = col_width

        emargin_l, emargin_r = laygo_info.edge_margins
        ewidth_l, ewidth_r = laygo_info.edge_widths
        xoffset = emargin_l + ewidth_l

        # draw top and bottom end row

        inst = template.add_instance(bot_end_master,
                                     inst_name='XRBOT',
                                     loc=(xoffset, 0),
                                     nx=nx,
                                     spx=spx,
                                     unit_mode=True)
        arr_box = inst.array_box
        inst = template.add_instance(top_end_master,
                                     inst_name='XRBOT',
                                     loc=(xoffset, yt),
                                     orient='MX',
                                     nx=nx,
                                     spx=spx,
                                     unit_mode=True)
        arr_box = arr_box.merge(inst.array_box)
        # draw corners
        left_end = (end_mode & 4) != 0
        right_end = (end_mode & 8) != 0
        edge_inst_list = []
        xr = laygo_info.tot_width
        for orient, y, master in (('R0', 0, bot_end_master), ('MX', yt,
                                                              top_end_master)):
            for x, is_end, flip_lr in ((emargin_l, left_end, False),
                                       (xr - emargin_r, right_end, True)):
                edge_params = dict(
                    is_end=is_end,
                    guard_ring_nf=guard_ring_nf,
                    adj_blk_info=master.get_left_edge_info(),
                    name_id=master.get_layout_basename(),
                    layout_info=master.get_edge_layout_info(),
                    is_laygo=True,
                )
                edge_master = template.new_template(params=edge_params,
                                                    temp_cls=AnalogEdge)
                if flip_lr:
                    eorient = 'MY' if orient == 'R0' else 'R180'
                else:
                    eorient = orient
                edge_inst_list.append(
                    template.add_instance(edge_master,
                                          orient=eorient,
                                          loc=(x, y),
                                          unit_mode=True))

        # draw edge blocks
        for y, flip_ud, edge_params in edgel_infos:
            orient = 'MX' if flip_ud else 'R0'
            edge_master = template.new_template(params=edge_params,
                                                temp_cls=AnalogEdge)
            edge_inst_list.append(
                template.add_instance(edge_master,
                                      orient=orient,
                                      loc=(emargin_l, y),
                                      unit_mode=True))
        for y, flip_ud, edge_params in edger_infos:
            orient = 'R180' if flip_ud else 'MY'
            edge_master = template.new_template(params=edge_params,
                                                temp_cls=AnalogEdge)
            edge_inst_list.append(
                template.add_instance(edge_master,
                                      orient=orient,
                                      loc=(xr - emargin_r, y),
                                      unit_mode=True))

        gr_vss_warrs = []
        gr_vdd_warrs = []
        conn_layer = self.get_dig_conn_layer()
        for inst in edge_inst_list:
            if inst.has_port('VDD'):
                gr_vdd_warrs.extend(
                    inst.get_all_port_pins('VDD', layer=conn_layer))
            elif inst.has_port('VSS'):
                gr_vss_warrs.extend(
                    inst.get_all_port_pins('VSS', layer=conn_layer))
            arr_box = arr_box.merge(inst.array_box)

        # connect body guard rings together
        gr_vdd_warrs = template.connect_wires(gr_vdd_warrs)
        gr_vss_warrs = template.connect_wires(gr_vss_warrs)

        arr_box_x = laygo_info.get_placement_info(num_col).arr_box_x
        arr_box = BBox(arr_box_x[0],
                       arr_box.bottom_unit,
                       arr_box_x[1],
                       arr_box.top_unit,
                       arr_box.resolution,
                       unit_mode=True)
        return arr_box, gr_vdd_warrs, gr_vss_warrs
Ejemplo n.º 30
0
    def draw_layout(self):
        # type: () -> None
        bot_layer = self.params['bot_layer']
        top_layer = self.params['top_layer']
        width = self.params['width']
        height = self.params['height']
        margin = self.params['margin']
        in_tid = self.params['in_tid']
        out_tid = self.params['out_tid']
        port_tr_w = self.params['port_tr_w']
        options = self.params['options']
        fill_config = self.params['fill_config']
        fill_dummy = self.params['fill_dummy']
        fill_pitch = self.params['fill_pitch']
        mos_type = self.params['mos_type']
        threshold = self.params['threshold']
        half_blk_x = self.params['half_blk_x']
        half_blk_y = self.params['half_blk_y']
        show_pins = self.params['show_pins']

        res = self.grid.resolution

        io_layer = top_layer + 1
        w_tot = width + 2 * margin
        h_tot = height + 2 * margin
        if fill_config is None:
            w_blk, h_blk = self.grid.get_block_size(io_layer,
                                                    unit_mode=True,
                                                    half_blk_x=half_blk_x,
                                                    half_blk_y=half_blk_y)
        else:
            w_blk, h_blk = self.grid.get_fill_size(io_layer,
                                                   fill_config,
                                                   unit_mode=True,
                                                   half_blk_x=half_blk_x,
                                                   half_blk_y=half_blk_y)
        w_tot = -(-w_tot // w_blk) * w_blk
        h_tot = -(-h_tot // h_blk) * h_blk

        # set size
        self.array_box = bnd_box = BBox(0,
                                        0,
                                        w_tot,
                                        h_tot,
                                        res,
                                        unit_mode=True)
        self.set_size_from_bound_box(io_layer, bnd_box)
        self.add_cell_boundary(bnd_box)

        # get input/output track location
        io_horiz = self.grid.get_direction(io_layer) == 'x'
        mid_coord = bnd_box.yc_unit if io_horiz else bnd_box.xc_unit
        io_tidx = self.grid.coord_to_nearest_track(io_layer,
                                                   mid_coord,
                                                   half_track=True,
                                                   mode=0,
                                                   unit_mode=True)
        if in_tid is None:
            in_tidx = io_tidx
            in_tr_w = 2
        else:
            in_tidx, in_tr_w = in_tid
        if out_tid is None:
            out_tidx = io_tidx
            out_tr_w = 2
        else:
            out_tidx, out_tr_w = out_tid
        in_tid = TrackID(io_layer, in_tidx, width=in_tr_w)
        out_tid = TrackID(io_layer, out_tidx, width=out_tr_w)

        # setup capacitor options
        # get port width dictionary.  Make sure we can via up to top_layer + 1
        in_w = self.grid.get_track_width(io_layer, in_tr_w, unit_mode=True)
        out_w = self.grid.get_track_width(io_layer, out_tr_w, unit_mode=True)
        top_port_tr_w = self.grid.get_min_track_width(top_layer,
                                                      top_w=max(in_w, out_w),
                                                      unit_mode=True)
        top_port_tr_w = max(top_port_tr_w, port_tr_w)
        port_tr_w_dict = {
            lay: port_tr_w
            for lay in range(bot_layer, top_layer + 1)
        }
        port_tr_w_dict[top_layer] = top_port_tr_w
        if options is None:
            options = dict(port_widths=port_tr_w_dict)
        else:
            options = options.copy()
            options['port_widths'] = port_tr_w_dict

        # draw cap
        cap_xl = (bnd_box.width_unit - width) // 2
        cap_yb = (bnd_box.height_unit - height) // 2
        cap_box = BBox(cap_xl,
                       cap_yb,
                       cap_xl + width,
                       cap_yb + height,
                       res,
                       unit_mode=True)
        num_layer = top_layer - bot_layer + 1
        cap_ports = self.add_mom_cap(cap_box, bot_layer, num_layer, **options)

        # connect input/output, draw metal resistors
        cout, cin = cap_ports[top_layer]
        cin = cin[0]
        cout = cout[0]
        in_min_len = self.grid.get_min_length(io_layer,
                                              in_tr_w,
                                              unit_mode=True)
        res_upper = cin.track_id.get_bounds(self.grid, unit_mode=True)[0]
        res_lower = res_upper - in_min_len
        in_lower = min(0, res_lower - in_min_len)
        self.connect_to_tracks(cin,
                               in_tid,
                               track_lower=in_lower,
                               unit_mode=True)
        self.add_res_metal_warr(io_layer,
                                in_tidx,
                                res_lower,
                                res_upper,
                                width=in_tr_w,
                                unit_mode=True)
        in_warr = self.add_wires(io_layer,
                                 in_tidx,
                                 in_lower,
                                 res_lower,
                                 width=in_tr_w,
                                 unit_mode=True)

        out_min_len = self.grid.get_min_length(io_layer,
                                               out_tr_w,
                                               unit_mode=True)
        res_lower = cout.track_id.get_bounds(self.grid, unit_mode=True)[1]
        res_upper = res_lower + out_min_len
        out_upper = max(w_tot, res_upper + out_min_len)
        self.connect_to_tracks(cout,
                               out_tid,
                               track_upper=out_upper,
                               unit_mode=True)
        self.add_res_metal_warr(io_layer,
                                out_tidx,
                                res_lower,
                                res_upper,
                                width=out_tr_w,
                                unit_mode=True)
        out_warr = self.add_wires(io_layer,
                                  out_tidx,
                                  res_upper,
                                  out_upper,
                                  width=out_tr_w,
                                  unit_mode=True)

        self.add_pin('plus', in_warr, show=show_pins)
        self.add_pin('minus', out_warr, show=show_pins)

        if fill_dummy:
            for lay in range(1, io_layer + 1):
                self.do_max_space_fill(lay, bnd_box, fill_pitch=fill_pitch)
            dum_params = dict(mos_type=mos_type,
                              threshold=threshold,
                              width=w_tot,
                              height=h_tot)
            master_dum = self.new_template(params=dum_params,
                                           temp_cls=DummyFillActive)
            self.add_instance(master_dum, unit_mode=True)

        lay_unit = self.grid.layout_unit
        self._sch_params = dict(
            res_in_info=(io_layer, in_w * res * lay_unit,
                         in_min_len * res * lay_unit),
            res_out_info=(io_layer, out_w * res * lay_unit,
                          out_min_len * res * lay_unit),
        )