Пример #1
0
def run_test(db: TemplateDB, lay_list: List[Tuple[TemplateBase, str]],
             fpath_list: List[Path]) -> None:
    for fpath in fpath_list:
        print(f'creating layout from file: {fpath.name}')
        specs = read_yaml(fpath)
        lay_cls = cast(Type[TemplateBase], import_class(specs['lay_class']))
        params = specs['params']
        master = db.new_template(lay_cls, params=params)
        lay_list.append((master, fpath.stem))
Пример #2
0
    def draw_layout(self):
        cls_name: str = self.params['cls_name']
        params: Mapping[str, Any] = self.params['params']

        gen_cls = cast(Type[ArrayBase], import_class(cls_name))
        master = self.new_template(gen_cls, params=params)

        inst = self.draw_boundaries(master, master.top_layer)
        # pass out schematic parameters
        self.sch_params = master.sch_params

        # re-export pins
        for name in inst.port_names_iter():
            self.reexport(inst.get_port(name))
Пример #3
0
    def draw_layout(self):
        params = self.params
        cls_name: str = params['cls_name']
        dut_params: Param = params['params']
        export_hidden: bool = params['export_hidden']
        half_blk_x: bool = params['half_blk_x']
        half_blk_y: bool = params['half_blk_y']

        gen_cls = cast(Type[MOSBase], import_class(cls_name))
        master = self.new_template(gen_cls, params=dut_params)

        self.wrap_mos_base(master,
                           export_hidden,
                           half_blk_x=half_blk_x,
                           half_blk_y=half_blk_y)
Пример #4
0
    def draw_layout(self) -> None:
        cls_name: str = self.params['cls_name']
        params: Param = self.params['params']
        draw_taps: bool = self.params['draw_taps']
        pwr_gnd_list: List[Tuple[str, str]] = self.params['pwr_gnd_list']

        if draw_taps:
            master = self.new_template(STDCellWithTap,
                                       params=dict(cls_name=cls_name,
                                                   params=params,
                                                   pwr_gnd_list=pwr_gnd_list))
        else:
            gen_cls = cast(Type[MOSBase], import_class(cls_name))
            master = self.new_template(gen_cls, params=params)

        self.wrap_mos_base(master, False)
Пример #5
0
    def draw_layout(self) -> None:
        gen_cls = cast(Type[MOSBase], import_class(self.params['cls_name']))
        pwr_gnd_list: List[Tuple[str, str]] = self.params['pwr_gnd_list']

        master: MOSBase = self.new_template(gen_cls,
                                            params=self.params['params'])
        self._core = master
        self.draw_base(master.draw_base_info)

        num_tiles = master.num_tile_rows
        tap_ncol = max((self.get_tap_ncol(tile_idx=tile_idx)
                        for tile_idx in range(num_tiles)))
        tap_sep_col = self.sub_sep_col
        num_cols = master.num_cols + 2 * (tap_sep_col + tap_ncol)
        self.set_mos_size(num_cols, num_tiles=num_tiles)
        # breakpoint()

        if not pwr_gnd_list:
            pwr_gnd_list = [('VDD', 'VSS')] * num_tiles
        elif len(pwr_gnd_list) != num_tiles:
            raise ValueError('pwr_gnd_list length mismatch.')

        inst = self.add_tile(master, 0, tap_ncol + tap_sep_col)
        sup_names = set()
        for tidx in range(num_tiles):
            pwr_name, gnd_name = pwr_gnd_list[tidx]
            sup_names.add(pwr_name)
            sup_names.add(gnd_name)
            vdd_list = []
            vss_list = []
            self.add_tap(0, vdd_list, vss_list, tile_idx=tidx)
            self.add_tap(num_cols,
                         vdd_list,
                         vss_list,
                         tile_idx=tidx,
                         flip_lr=True)
            self.add_pin(pwr_name, vdd_list, connect=True)
            self.add_pin(gnd_name, vss_list, connect=True)

        for name in inst.port_names_iter():
            if name in sup_names:
                self.reexport(inst.get_port(name), connect=True)
            else:
                self.reexport(inst.get_port(name))

        self.sch_params = master.sch_params
        self._sch_cls = master.get_schematic_class_inst()
Пример #6
0
    async def async_measure_performance(
            self, name: str, sim_dir: Path, sim_db: SimulationDB,
            dut: Optional[DesignInstance]) -> Dict[str, Any]:
        specs = self.specs
        flop_params: Mapping[str, Any] = specs['flop_params']
        tbm_cls_val: Union[str, Type[FlopTimingBase]] = specs['tbm_cls']
        t_rf_list: Sequence[float] = specs['t_rf_list']
        t_clk_rf_list: Sequence[float] = specs['t_clk_rf_list']
        t_clk_rf_first: bool = specs['t_clk_rf_first']

        fake: bool = specs.get('fake', False)
        use_dut: bool = specs.get('use_dut', True)

        meas_dut = dut if use_dut else None

        tbm_cls = cast(Type[FlopTimingBase], import_class(tbm_cls_val))

        mode_list = tbm_cls.get_meas_modes(flop_params)
        out_mode_list = tbm_cls.get_output_meas_modes(flop_params)

        # output timing measurement
        self.log('Measuring output delays')
        timing_table = {}
        gatherer = GatherHelper()
        for out_mode in out_mode_list:
            gatherer.append(
                self.get_out_timing(name, sim_db, meas_dut, sim_dir, tbm_cls,
                                    out_mode, fake, timing_table))

        self.log('Measuring input constraints')
        clk_len = len(t_clk_rf_list)
        in_len = len(t_rf_list)
        arr_shape = (clk_len, in_len) if t_clk_rf_first else (in_len, clk_len)
        for ck_idx, t_clk_rf in enumerate(t_clk_rf_list):
            for rf_idx, t_rf in enumerate(t_rf_list):
                for meas_mode in mode_list:
                    coro = self.get_in_timing(name, sim_db, meas_dut, sim_dir,
                                              meas_mode, fake, t_clk_rf, t_rf,
                                              ck_idx, rf_idx, arr_shape,
                                              t_clk_rf_first, timing_table)
                    gatherer.append(coro)

        await gatherer.gather_err()

        ans = {key: list(val.values()) for key, val in timing_table.items()}
        return ans
Пример #7
0
    def draw_layout(self) -> None:
        params = self.params
        cls_name: str = params['cls_name']
        params: Param = params['params']
        pmos_gr: str = params['pmos_gr']
        nmos_gr: str = params['nmos_gr']
        sep_ncol: Tuple[int, int] = params['sep_ncol']
        edge_ncol: int = params['edge_ncol']

        gen_cls = cast(Type[MOSBase], import_class(cls_name))
        master: MOSBase = self.new_template(gen_cls, params=params)

        _, sup_list = self.draw_guard_ring(master, pmos_gr, nmos_gr, sep_ncol, edge_ncol)
        for tile_idx, (vss_list, vdd_list) in enumerate(sup_list):
            for ridx, warr in enumerate(vss_list):
                self.add_pin(f'VSS_guard_{tile_idx}_{ridx}', warr)
            for ridx, warr in enumerate(vdd_list):
                self.add_pin(f'VDD_guard_{tile_idx}_{ridx}', warr)
Пример #8
0
    def draw_layout(self) -> None:
        ndio_cls_name: str = self.params['ndio_cls']
        pdio_cls_name: str = self.params['pdio_cls']
        ndio_params: Param = self.params['ndio_params']
        pdio_params: Param = self.params['pdio_params']
        fe_params: Param = self.params['fe_params']
        npadout: int = self.params['npadout']
        w_dio_min: int = self.params['w_dio_min']
        dio_margin: int = self.params['dio_margin']
        tb_margin: int = self.params['tb_margin']

        fe_ip_params = dict(
            cls_name='xbase.layout.mos.top.GenericWrapper',
            params=dict(
                cls_name=Frontend.get_qualified_name(),
                params=fe_params,
                export_hidden=True,
                half_blk_x=False,
            ),
        )

        # make masters
        fe_master: TemplateBase = self.new_template(IPMarginTemplate, params=fe_ip_params)
        ndio_cls = cast(Type[TemplateBase], import_class(ndio_cls_name))
        pdio_cls = cast(Type[TemplateBase], import_class(pdio_cls_name))
        nd_master: TemplateBase = self.new_template(ndio_cls, params=ndio_params)
        pd_master: TemplateBase = self.new_template(pdio_cls, params=pdio_params)

        # floorplan
        grid = self.grid
        top_layer = nd_master.top_layer
        w_blk, h_blk = grid.get_block_size(top_layer)
        tb_margin = -(-tb_margin // h_blk) * h_blk
        fe_box = fe_master.bound_box
        nd_box = nd_master.bound_box
        pd_box = pd_master.bound_box
        h_fe = fe_box.h
        h_nd = nd_box.h
        h_pd = pd_box.h
        w_fe = fe_box.w
        w_nd = nd_box.w
        w_pd = pd_box.w
        w_dio = max(w_dio_min + dio_margin, w_nd + w_pd)
        w_tot = w_fe + w_dio
        w_tot = -(-w_tot // w_blk) * w_blk
        h_tot = max(h_fe, h_nd, h_pd) + 2 * tb_margin
        y_fe = (h_tot - h_fe) // (2 * h_blk) * h_blk
        y_nd = (h_tot - h_nd) // (2 * h_blk) * h_blk
        y_pd = (h_tot - h_pd) // (2 * h_blk) * h_blk
        x_nd = w_fe
        x_pd = w_tot - w_pd

        # instantiate blocks
        fe = self.add_instance(fe_master, inst_name='XFE', xform=Transform(0, y_fe))
        nd = self.add_instance(nd_master, inst_name='XND', xform=Transform(x_nd, y_nd))
        pd = self.add_instance(pd_master, inst_name='XPD', xform=Transform(x_pd, y_pd))

        self.set_size_from_bound_box(top_layer, BBox(0, 0, w_tot, h_tot))

        # diode guard ring connections
        vlay = (fe.get_port('VSS').get_single_layer(), 'drawing')
        vdir = Direction.LOWER
        vss_list = []
        vdd_list = []
        vddio_list = []
        vss_bbox: List[BBox] = fe.get_all_port_pins('VSS', layer=vlay[0])
        vdd_bbox: List[BBox] = fe.get_all_port_pins('VDDCore', layer=vlay[0])
        vddio_bbox: List[BBox] = fe.get_all_port_pins('VDDIO', layer=vlay[0])

        vss_pd = pd.get_all_port_pins('gr')
        for bbox in vss_bbox:
            vss_list.extend(self.connect_bbox_to_track_wires(vdir, vlay, bbox, vss_pd))
        vss_list = self.connect_wires(vss_list)

        vddio_nd = nd.get_all_port_pins('gr')
        for bbox in vddio_bbox:
            vddio_list.extend(self.connect_bbox_to_track_wires(vdir, vlay, bbox, vddio_nd))
        vddio_list = self.connect_wires(vddio_list)

        # diode ports
        vddio_pd = pd.get_all_port_pins('sub')
        vss_nd = nd.get_all_port_pins('sub')
        dio_sp_le = grid.get_line_end_space(vss_nd[0].layer_id, vss_nd[0].track_id.width, even=True)
        dio_sp_le2 = dio_sp_le // 2
        if dio_margin < 0:
            dio_margin = dio_sp_le2
        dio_port_xh = w_tot - dio_margin
        x_dio_mid = (nd.bound_box.xh + pd.bound_box.xl) // 2
        vddio_pd = self.extend_wires(vddio_pd, lower=x_dio_mid + dio_sp_le2, upper=dio_port_xh)
        vss_nd = self.extend_wires(vss_nd, lower=x_nd, upper=x_dio_mid - dio_sp_le2)
        self.add_pin('VDDIO', vddio_pd)
        self.add_pin('VSS', vss_nd)
        pad = pd.get_all_port_pins('pad')
        pad.extend(nd.port_pins_iter('pad'))
        pad = self.connect_wires(pad, lower=x_nd, upper=dio_port_xh)[0]
        self.add_pin('iopad', pad)

        # short diode wires so we are LVS clean
        ym_layer = vddio_nd[0].layer_id - 1
        vss_tidx = grid.coord_to_track(ym_layer, x_nd + w_nd, mode=RoundMode.GREATER_EQ)
        vddio_tidx = grid.coord_to_track(ym_layer, x_pd, mode=RoundMode.LESS_EQ)
        iopad_tidx = grid.get_middle_track(vss_tidx, vddio_tidx, round_up=False)
        ym_w = grid.get_min_track_width(ym_layer, top_ntr=vddio_nd[0].track_id.width)
        vddio_pd.extend(vddio_list)
        vss_nd.extend(vss_list)
        self.connect_to_tracks(vddio_pd, TrackID(ym_layer, vddio_tidx, width=ym_w))
        self.connect_to_tracks(vss_nd, TrackID(ym_layer, vss_tidx, width=ym_w))
        self.connect_to_tracks(pad, TrackID(ym_layer, iopad_tidx, width=ym_w))

        # connect iopad and iclkn
        npad = pad.track_id.num
        pad_conn = pad[:npadout]
        iclkn_bnds = [COORD_MAX, COORD_MIN]
        iopad_out_list = []
        for bbox in fe.port_pins_iter('txpadout', layer=vlay[0]):
            warr = self.connect_bbox_to_track_wires(vdir, vlay, bbox, pad_conn)
            iopad_out_list.append(warr)

        for bbox in fe.port_pins_iter('rxpadin', layer=vlay[0]):
            cur_bnds = [0, 0]
            warr = self.connect_bbox_to_track_wires(vdir, vlay, bbox, pad_conn, ret_bnds=cur_bnds)
            iopad_out_list.append(warr)
            iclkn_bnds[0] = min(iclkn_bnds[0], cur_bnds[0])
            iclkn_bnds[1] = max(iclkn_bnds[1], cur_bnds[1])

        # export iopad_out
        pad_conn_tid = pad_conn.track_id
        pad_layer = pad_conn_tid.layer_id
        iopad_out_list = self.connect_wires(iopad_out_list)
        lower = iopad_out_list[0].lower
        pad_bnds = grid.get_wire_bounds(pad_layer, pad_conn_tid.base_index,
                                        width=pad_conn_tid.width)
        pin_len = grid.get_next_length(pad_layer, pad_conn_tid.width, pad_bnds[1] - pad_bnds[0],
                                       even=True)
        ms_params = self.add_res_metal_warr(pad_layer, pad_conn_tid.base_index,
                                            lower + pin_len, lower + 2 * pin_len,
                                            width=pad_conn_tid.width, num=pad_conn_tid.num,
                                            pitch=pad_conn_tid.pitch)

        self.add_pin('iopad_out', WireArray(pad_conn_tid, lower, lower + pin_len))

        bbox_iclkn = fe.get_pin('iclkn', layer=vlay[0])
        bbox_iclkn = bbox_iclkn.set_interval(Orient2D.y, iclkn_bnds[0], iclkn_bnds[1])
        # NOTE: some process require metal to be in same hierarchy as pin
        self.add_rect(vlay, bbox_iclkn)
        self.add_pin_primitive('iclkn', vlay[0], bbox_iclkn)

        # supply connections
        for idx in range(npad):
            tid = vss_nd[idx].track_id
            if idx == 0 or idx == npad - 1:
                cur_list = vdd_list
                cur_bbox = vdd_bbox
            elif idx & 1:
                cur_list = vss_list
                cur_bbox = vss_bbox
            else:
                cur_list = vddio_list
                cur_bbox = vddio_bbox

            for bbox in cur_bbox:
                cur_list.append(self.connect_bbox_to_tracks(vdir, vlay, bbox, tid))

        self.add_pin('VDDCore', self.connect_wires(vdd_list))
        self.add_pin('VDDIO', self.connect_wires(vddio_list))
        self.add_pin('VSS', self.connect_wires(vss_list))
        for name in ['VDDCore', 'VDDIO', 'VSS']:
            self.reexport(fe.get_port(f'{name}_xm'), net_name=name, hide=False)

        # reexport pins
        for name in ['din', 'ipdrv_buf<1>', 'ipdrv_buf<0>',
                     'indrv_buf<1>', 'indrv_buf<0>', 'itx_en_buf', 'weak_pulldownen',
                     'weak_pullupenb']:
            self.reexport(fe.get_port(name))

        for name in ['clk_en', 'data_en', 'por', 'odat', 'odat_async',
                     'oclkp', 'oclkn']:
            self.reexport(fe.get_port(name))

        self.sch_params = dict(
            fe_params=fe_master.sch_params,
            nd_params=nd_master.sch_params,
            pd_params=pd_master.sch_params,
            ms_params=ms_params,
        )