예제 #1
0
    async def get_driver_cin(self, driver_summary, vdd_out, c_ext,
                             cap_in_search_params, dig_buf_params,
                             dig_tbm_specs, num_units) -> dict:

        pin_names = [
            'din', 'tristate', 'tristateb', 'weak_pden', 'weak_puenb',
            'n_enb_drv<0>', 'n_enb_drv<1>', 'p_en_drv<0>', 'p_en_drv<1>'
        ]

        helper = GatherHelper()
        dut = await self.async_new_dut('cin_driver_dut', STDCellWrapper,
                                       driver_summary['dut_params'])
        for pin in pin_names:
            helper.append(
                self._get_driver_input_cap(pin, driver_summary['dut_params'],
                                           vdd_out, c_ext, num_units,
                                           dig_tbm_specs, dig_buf_params,
                                           cap_in_search_params, dut))
        results = await helper.gather_err()
        cdict = {}
        for idx, pin in enumerate(pin_names):
            # extract data cap and max of all ctrl pin caps
            cin = results[idx]
            if pin == 'din':
                cdict['data'] = cin
            else:
                c_cur = cdict.get('ctrl', -float('inf'))
                if cin > c_cur:
                    cdict['ctrl'] = cin
        return cdict
예제 #2
0
    async def async_measure_performance(self, name: str, sim_dir: Path, sim_db: SimulationDB,
                                        dut: Optional[DesignInstance]) -> Mapping[str, Any]:
        helper = GatherHelper()
        for idx in range(2):
            helper.append(self.async_meas_case(name, sim_dir, sim_db, dut, idx))

        meas_results = await helper.gather_err()
        ans = self.compute_passives(meas_results)

        return ans
예제 #3
0
    async def _measure_times(self, sim_envs: Sequence[str],
                             tbm_dict: Dict[str,
                                            DigitalTranTB], dut_params: Param,
                             tbm_params: Mapping[str, Any], tbit: float,
                             nbits: int, name: str) -> Dict[str, Any]:
        gen_params = dict(
            cls_name=PhaseInterpolatorWithDelay.get_qualified_name(),
            params=dut_params,
        )
        dut = await self.async_new_dut('phase_interp', GenericWrapper,
                                       gen_params)

        helper = GatherHelper()
        for corner in sim_envs:
            helper.append(
                self._measure_times_at_corner(tbm_dict[corner], dut,
                                              tbm_params, tbit, nbits,
                                              f'{name}_{corner}'))
        results = await helper.gather_err()

        dct = {
            k: []
            for k in
            ['tdrs', 'tdfs', 'tdrs_dc', 'tdfs_dc', 'tdr_step', 'tdf_step']
        }
        max_steps, min_steps, max_dly = [], [], []
        for idx, corner in enumerate(sim_envs):
            tdr, tdf, tdr_dc, tdf_dc = results[idx]
            max_dly.append(max(np.min(tdr), np.min(tdf)))
            tdr = np.vstack((tdr, (tdr[0] + tdr_dc)[None, ...]))
            tdf = np.vstack((tdf, (tdf[0] + tdf_dc)[None, ...]))
            tdr_step = np.diff(tdr, axis=0)
            tdf_step = np.diff(tdf, axis=0)
            dct['tdr_step'].append(tdr_step)
            dct['tdf_step'].append(tdf_step)
            dct['tdrs'].append(tdr)
            dct['tdfs'].append(tdf)
            dct['tdrs_dc'].append(tdr_dc)
            dct['tdfs_dc'].append(tdf_dc)
            max_steps.append(max(np.max(tdr_step), np.max(tdf_step)))
            min_steps.append(min(np.min(tdr_step), np.min(tdf_step)))
        for k in [
                'tdrs', 'tdfs', 'tdrs_dc', 'tdfs_dc', 'tdr_step', 'tdf_step'
        ]:
            dct[k] = np.array(dct[k])
        max_idx = cast(int, np.argmax(np.array(max_steps)))
        min_idx = cast(int, np.argmin(np.array(min_steps)))
        dct['max_corner'] = sim_envs[max_idx]
        dct['min_corner'] = sim_envs[min_idx]
        dct['max_step'] = max_steps[max_idx]
        dct['min_step'] = min_steps[min_idx]
        dct['max_dly'] = max(max_dly)
        return dct
예제 #4
0
    async def _measure_times(self, nand_outer_seg: int, nand_inner_seg: int,
                             stack: int, ncodes: int, cload: float,
                             num_core: int, nrows: int, ncols: int,
                             pinfo: Mapping[str,
                                            Any], sim_params: Mapping[str,
                                                                      Any]):
        dut_params = self._get_dut_params(nand_outer_seg, nand_inner_seg,
                                          stack, ncodes, num_core, nrows,
                                          ncols, pinfo)
        dut = await self.async_new_dut('dly_line_chain', STDCellWrapper,
                                       dut_params)

        tper = sim_params['tper']
        ncycles = sim_params['ncycles']
        sim_id_pref = f'dly_no{nand_outer_seg}_ni{nand_inner_seg}_s{stack}'
        helper = GatherHelper()
        for code in range(0, ncodes - 1):
            tbm_params = self._get_tbm_params(code, ncodes, cload, sim_params)
            sim_id = f'{sim_id_pref}_c{code}'
            helper.append(
                self._get_delay(sim_id,
                                dut,
                                tbm_params,
                                t_start=tper * (ncycles - 1),
                                t_stop=tper * ncycles))
        ret_list = await helper.gather_err()
        tdr_list, tdf_list = [x[0] for x in ret_list], [x[1] for x in ret_list]

        res_arr = dict()

        tdr_arr = np.stack(tdr_list, axis=-1)
        res_arr['tdr_arr'] = tdr_arr
        tdf_arr = np.stack(tdf_list, axis=-1)
        res_arr['tdf_arr'] = tdf_arr
        tdr_per_code = np.diff(tdr_arr, axis=-1)[..., ::2]
        res_arr['tdr_per_code'] = tdr_per_code
        tdf_per_code = np.diff(tdf_arr, axis=-1)[..., ::2]
        res_arr['tdf_per_code'] = tdf_per_code

        tdr_max = np.max(tdr_per_code)
        res_arr['tdr_max'] = tdr_max
        tdf_max = np.max(tdf_per_code)
        res_arr['tdf_max'] = tdf_max
        tdr_min = np.min(tdr_per_code)
        res_arr['tdr_min'] = tdr_min
        tdf_min = np.min(tdf_per_code)
        res_arr['tdf_min'] = tdf_min

        res_arr['td_max'] = max(tdr_max, tdf_max)
        res_arr['td_min'] = min(tdr_min, tdf_min)

        return res_arr
예제 #5
0
    async def _get_resistance(
            self, sim_id: str, dut_params: Mapping[str, Any],
            mm_specs: Dict[str, Any]) -> Tuple[np.ndarray, np.ndarray]:
        """Compute resistance from DC I-V measurements.
        """
        gen_params = dict(
            cls_name=PullUpDown.get_qualified_name(),
            draw_taps=True,
            params=dut_params,
        )
        dut = await self.async_new_dut('unit_cell',
                                       STDCellWrapper,
                                       gen_params,
                                       flat=True)

        extract = self._sim_db.extract
        netlist_type = DesignOutput.CDL if extract else self._sim_db.prj.sim_access.netlist_type

        # Create a new netlist that allows for the insertion of dc sources
        offset_netlist = Path(
            *dut.netlist_path.parts[:-1],
            f'netlist_with_sources.{netlist_type.extension}')
        v_offset_map = add_internal_sources(dut.netlist_path, offset_netlist,
                                            netlist_type, ['d'])

        mm_specs['v_offset_map'] = v_offset_map
        mm_specs['extract'] = extract

        # Create a DesignInstance with the newly created netlist
        new_dut = DesignInstance(dut.cell_name, dut.sch_master, dut.lay_master,
                                 offset_netlist, dut.cv_info_list)

        all_corners = get_tech_global_info(
            'aib_ams')['signoff_envs']['all_corners']
        res_pd = np.array([])
        res_pu = np.array([])

        helper = GatherHelper()
        for env in all_corners['envs']:
            helper.append(
                self._run_get_resistance(env, sim_id, new_dut, mm_specs,
                                         all_corners))

        results = await helper.gather_err()
        for idx in range(len(results)):
            res_pu = np.append(res_pu, results[idx][0])
            res_pd = np.append(res_pd, results[idx][1])

        return res_pu, res_pd
예제 #6
0
    async def _design_chain_step(
            self, nand_outer_seg: int, nand_inner_seg: int, stack: int,
            ncodes: int, cload: float, num_core: int, nrows: int, ncols: int,
            pinfo: Mapping[str, Any],
            sim_params: Mapping[str, Any]) -> Tuple[float, float]:
        mid = ncodes // 2
        dut_params = self._get_dut_params(nand_outer_seg, nand_inner_seg,
                                          stack, ncodes, num_core, nrows,
                                          ncols, pinfo)
        # dut = await self.async_new_dut('dly_line_chain', STDCellWrapper, dut_params)
        dut = await self.async_new_dut('dly_line_chain', GenericWrapper,
                                       dut_params)

        tper = sim_params['tper']
        ncycles = sim_params['ncycles']
        sim_id_pref = f'dly_no{nand_outer_seg}_ni{nand_inner_seg}_s{stack}'
        helper = GatherHelper()
        for code in [0, 1, mid, mid + 1, ncodes - 2, ncodes - 1]:
            tbm_params = self._get_tbm_params(code, ncodes, cload, sim_params)
            sim_id = f'{sim_id_pref}_c{code}'
            helper.append(
                self._get_delay(sim_id,
                                dut,
                                tbm_params,
                                t_start=tper * (ncycles - 1),
                                t_stop=tper * ncycles))
        ret_list = await helper.gather_err()
        tdr_list, tdf_list = [x[0] for x in ret_list], [x[1] for x in ret_list]

        tdr_arr = np.stack(tdr_list, axis=-1)
        tdf_arr = np.stack(tdf_list, axis=-1)
        tdr_per_code = np.diff(tdr_arr, axis=-1)[..., ::2]
        tdf_per_code = np.diff(tdf_arr, axis=-1)[..., ::2]

        tdr_max = np.max(tdr_per_code)
        tdf_max = np.max(tdf_per_code)
        tdr_min = np.min(tdr_per_code)
        tdf_min = np.min(tdf_per_code)

        td_max = max(tdr_max, tdf_max)
        td_min = min(tdr_min, tdf_min)

        return td_max, td_min
예제 #7
0
    async def sign_off(self, se_params: Dict[str, Any]) -> Mapping[str, Any]:
        sign_off_envs: Sequence[str] = self.dsn_specs['sign_off_envs']

        dut = await self.async_wrapper_dut('SE_TO_DIFF', SingleToDiff,
                                           se_params)

        gatherer = GatherHelper()
        for sim_env in sign_off_envs:
            mm_specs = self._td_specs.copy()
            mm_specs['tbm_specs'] = tbm_specs = mm_specs['tbm_specs'].copy()
            tbm_specs['sim_envs'] = [sim_env]

            mm = self.make_mm(CombLogicTimingMM, mm_specs)
            gatherer.append(
                self.async_simulate_mm_obj(
                    f'sign_off_{sim_env}_{dut.cache_name}', dut, mm))

        result_list = await gatherer.gather_err()

        ans = {}
        pin_list = ['outp', 'outn']
        for sim_env, meas_result in zip(sign_off_envs, result_list):
            timing_data = meas_result.data['timing_data']

            cur_results = {}
            for pin_name in pin_list:
                data = timing_data[pin_name]
                cur_results[f'td_{pin_name}'] = (data['cell_fall'],
                                                 data['cell_rise'])
                cur_results[f'trf_{pin_name}'] = (data['fall_transition'],
                                                  data['rise_transition'])

            td_outp = cur_results['td_outp']
            td_outn = cur_results['td_outn']
            td_avg_rise = (td_outp[1] + td_outn[0]) / 2
            td_avg_fall = (td_outp[0] + td_outn[1]) / 2
            err_rise = abs(td_outp[1] - td_outn[0]) / 2 / td_avg_rise
            err_fall = abs(td_outp[0] - td_outn[1]) / 2 / td_avg_fall
            cur_results['td_out_avg'] = (td_avg_fall, td_avg_rise)
            cur_results['td_err'] = (err_fall, err_rise)
            ans[sim_env] = cur_results

        return ans
예제 #8
0
    async def sign_off(self, se_params: Mapping[str, Any], match_params: Mapping[str, Any]
                       ) -> Mapping[str, Any]:
        sign_off_envs: Sequence[str] = self.dsn_specs['sign_off_envs']

        gatherer = GatherHelper()
        dut_se = await self.get_dut(se_params, False)
        dut_match = await self.get_dut(match_params, True)
        for sim_env in sign_off_envs:
            gatherer.append(self.get_delays_dut(dut_se, False, sim_env))
            gatherer.append(self.get_delays_dut(dut_match, True, sim_env))

        result_list = await gatherer.gather_err()

        ans = {}
        for idx, sim_env in enumerate(sign_off_envs):
            se_data = result_list[2 * idx]
            match_data = result_list[2 * idx + 1]
            ans[sim_env] = cur_result = {}
            for name, td_data in [('se_en', se_data), ('match', match_data)]:
                td_outp = td_data.outp
                td_outn = td_data.outn
                td_rise_avg = td_data.td_rise_avg
                td_fall_avg = td_data.td_fall_avg
                err_rise = abs(td_outp[1] - td_outn[0]) / 2 / td_rise_avg
                err_fall = abs(td_outp[0] - td_outn[1]) / 2 / td_fall_avg
                cur_result[name] = dict(
                    td_outp=td_outp,
                    td_outn=td_outn,
                    td_avg=(td_fall_avg, td_rise_avg),
                    td_err=(err_fall, err_rise),
                )

        return ans
예제 #9
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
예제 #10
0
    async def async_measure_performance(
            self, name: str, sim_dir: Path, sim_db: SimulationDB,
            dut: Optional[DesignInstance]) -> Dict[str, Any]:
        specs = self.specs
        in_cap_min: float = specs['in_cap_min_default']
        out_max_trf: float = specs['out_max_trf']
        out_min_fanout: float = specs['out_min_fanout']
        in_cap_table: Mapping[str, float] = specs['in_cap_table']
        out_io_info_table: Mapping[str,
                                   Mapping[str,
                                           Any]] = specs['out_io_info_table']
        custom_meas: Mapping[str, Mapping[str, Any]] = specs['custom_meas']

        # setup input capacitance measurements
        ans = {}
        out_io_pins = []
        gatherer = GatherHelper()
        for pin_name, term_type in dut.sch_master.pins.items():
            basename, bus_range = parse_cdba_name(pin_name)
            if bus_range is None:
                ans[pin_name] = pin_info = {}
                if term_type is TermType.input:
                    gatherer.append(
                        self._measure_in_cap(name, sim_dir, sim_db, dut,
                                             pin_name, in_cap_table, pin_info))
                else:
                    out_io_pins.append(pin_name)
            else:
                for bus_idx in bus_range:
                    bit_name = get_bus_bit_name(basename, bus_idx, cdba=True)
                    ans[bit_name] = pin_info = {}
                    if term_type is TermType.input:
                        gatherer.append(
                            self._measure_in_cap(name, sim_dir, sim_db, dut,
                                                 bit_name, in_cap_table,
                                                 pin_info))
                    else:
                        out_io_pins.append(bit_name)

        # record input capacitances
        if gatherer:
            in_cap_min = min((val for val in await gatherer.gather_err()
                              if val is not None))

        # get parameters needed for output pin measurement
        out_cap_min = in_cap_min * out_min_fanout

        # compute inout and output pin cap/timing information
        gatherer.clear()
        for bit_name in out_io_pins:
            pin_info = out_io_info_table.get(bit_name, None)
            if pin_info is None:
                continue

            cap_info: Mapping[str, Any] = pin_info.get('cap_info', None)
            tinfo_list: Optional[Sequence[Mapping[str, Any]]] = pin_info.get(
                'timing_info', None)

            output_table = ans[bit_name]
            if cap_info is not None:
                related: str = cap_info.get('related', '')
                max_cap: Optional[float] = cap_info.get('max_cap', None)
                max_trf: float = cap_info.get('max_trf', out_max_trf)
                cond: Mapping[str, int] = cap_info.get('cond', {})

                gatherer.append(
                    self._measure_out_cap(name, sim_dir, sim_db, dut, bit_name,
                                          related, max_cap, max_trf, cond,
                                          out_cap_min, output_table))

            if tinfo_list is not None:
                output_table['timing'] = timing_output = []
                for idx, tinfo in enumerate(tinfo_list):
                    related: str = tinfo['related']
                    sense_str: str = tinfo['sense']
                    cond: Mapping[str, int] = tinfo.get('cond', {})
                    timing_type: str = tinfo.get('timing_type',
                                                 'combinational')
                    zero_delay: bool = tinfo.get('zero_delay', False)
                    data: Optional[Mapping[str, Any]] = tinfo.get('data', None)

                    related_str = cdba_to_unusal(related)
                    out_str = cdba_to_unusal(bit_name)
                    sim_id = f'comb_delay_{related_str}_{out_str}_{idx}'
                    gatherer.append(
                        self._measure_delay(name, sim_id, sim_dir, sim_db, dut,
                                            bit_name, related, sense_str, cond,
                                            timing_type, zero_delay, data,
                                            timing_output))
        # add custom and flop measurements
        for meas_name, meas_params in custom_meas.items():
            meas_cls: str = meas_params['meas_class']
            meas_specs: Mapping[str, Any] = meas_params['meas_specs']
            gatherer.append(
                self._measure_custom(name, sim_dir, sim_db, dut, meas_name,
                                     meas_cls, meas_specs, ans))

        for seq_name, seq_mm in self._seq_mm_table.items():
            gatherer.append(
                self._measure_flop(name, sim_dir, sim_db, dut, seq_name,
                                   seq_mm, ans))

        # run all simulation in parallel
        await gatherer.run()
        return ans
예제 #11
0
    async def _design_for_mc(self,
                             outer_seg: int,
                             inner_seg: int,
                             stack: int,
                             cload: float,
                             std_dev_max: float,
                             num_core: int,
                             pinfo: Mapping[str, Any],
                             sim_params: Mapping[str, Any],
                             mc_dsn_env: str,
                             mc_params: Mapping[str, Any],
                             ncodes: int,
                             max_iter: int = 5) -> Tuple[int, int]:
        # ncodes in this part can be a small value (i.e. 3)
        global_info = self.dsn_tech_info
        indx = 0
        cur_std_max = float('inf')
        n_factor = 1
        tstart = sim_params['tper'] * (sim_params['ncycles'] - 1)
        tstop = sim_params['tper'] * sim_params['ncycles']
        # finish if maximum number of iteration reached
        while cur_std_max > std_dev_max:
            if indx > max_iter:
                raise ValueError(
                    f'Reached the maximum niter {max_iter}, but have not reached '
                    f'std spec')
            _factor = int(np.ceil(outer_seg * n_factor)) / outer_seg
            outer_seg = int(np.ceil(outer_seg * _factor))
            inner_seg = int(np.ceil(inner_seg * _factor))
            cload *= _factor
            self.log(
                f'Computed fudge factor: {n_factor}, actual factor: {_factor}')
            self.log(f'New outer NAND Seg: {outer_seg}')
            self.log(f'New inner NAND Seg: {inner_seg}')
            self.log(f'New cload: {cload}')

            # put all cells in a single row
            dut_params = self._get_dut_params(outer_seg,
                                              inner_seg,
                                              stack,
                                              ncodes=ncodes,
                                              num_core=num_core,
                                              nrows=1,
                                              ncols=ncodes + 2,
                                              pinfo=pinfo)
            dut = await self.async_new_dut('dly_line_chain', STDCellWrapper,
                                           dut_params)
            helper = GatherHelper()
            for code in range(ncodes):
                mc_sim_params = dict(deepcopy(sim_params))
                mc_sim_params['sim_envs'] = global_info['dsn_envs'][
                    mc_dsn_env]['mc_env']
                mc_tb_params = self._get_tbm_params(code, ncodes, cload,
                                                    mc_sim_params)
                mc_tb_params['monte_carlo_params'] = mc_params
                sim_id = f'dly_no{outer_seg}_ni{inner_seg}_s{stack}_mc{indx}_c{code}'
                self.log("Running Monte Carlo on design")
                helper.append(
                    self._get_delay(sim_id,
                                    dut,
                                    mc_tb_params,
                                    t_start=tstart,
                                    t_stop=tstop))
            ret_list = await helper.gather_err()
            tdr_list, tdf_list = [x[0]
                                  for x in ret_list], [x[1] for x in ret_list]

            tdr = np.stack(tdr_list, axis=0)
            tdf = np.stack(tdf_list, axis=0)

            steps_r = np.diff(tdr, axis=0).squeeze()
            steps_f = np.diff(tdf, axis=0).squeeze()

            sdr = np.std(steps_r)
            sdf = np.std(steps_f)

            cur_std_max = max(sdr, sdf)
            print('=' * 80)
            self.log(
                f"Standard deviation of the rising delay: {sdr}, Spec = {std_dev_max}"
            )
            self.log(
                f"Standard deviation of the falling delay: {sdf}, Spec = {std_dev_max}"
            )
            print('=' * 80)

            diff_factor = cur_std_max / std_dev_max
            n_factor = diff_factor**2
            indx += 1

        return outer_seg, inner_seg
예제 #12
0
    async def _get_init_rc(self) -> RCData:
        specs = self.dsn_specs
        inv_char_params: Mapping[str, Any] = specs['inv_char_params']
        pg_char_params: Mapping[str, Any] = specs['pg_char_params']

        inv_params = dict(
            pinfo=self._pinfo,
            seg=inv_char_params['seg'],
            w_p=inv_char_params['w_p'],
            w_n=inv_char_params['w_n'],
        )
        pg_params = dict(
            pinfo=self._pinfo,
            seg=pg_char_params['seg'],
            w_p=pg_char_params['w_p'],
            w_n=pg_char_params['w_n'],
        )

        # get initial inverter and passgate DUT
        gatherer = GatherHelper()
        gatherer.append(self.async_wrapper_dut('INV_CHAR', InvCore,
                                               inv_params))
        gatherer.append(
            self.async_wrapper_dut('PG_CHAR', PassGateCore, pg_params))
        dut_inv, dut_pg = await gatherer.gather_err()

        # get inverter and passgate RC
        inv_mm = self.make_mm(RCDelayCharMM, self._rc_inv_specs)
        pg_mm = self.make_mm(PassGateRCDelayCharMM, self._rc_pg_specs)
        gatherer.clear()
        gatherer.append(
            self.async_simulate_mm_obj('rc_inv_char', dut_inv, inv_mm))
        gatherer.append(self.async_simulate_mm_obj('rc_pg_char', dut_pg,
                                                   pg_mm))
        inv_result, pg_result = await gatherer.gather_err()

        w_inv = inv_params['w_n'] * inv_params['seg']
        w_pg = pg_params['w_n'] * pg_params['seg']
        rc_inv = _format_inv_rc(inv_result.data, w_inv)
        rc_pg = _format_pg_rc(pg_result.data, w_pg)
        return RCData(rc_inv, rc_pg)
예제 #13
0
    async def async_design(self,
                           nsync: int,
                           cload: float,
                           fmax: float,
                           fmin: float,
                           dcd_max: float,
                           rel_del_max: float,
                           pinfo: Mapping[str, any],
                           core_params: Optional[Dict[str, Any]] = None,
                           sync_params: Optional[Dict[str, Any]] = None,
                           buf_params: Optional[Dict[str, Any]] = None,
                           **kwargs: Mapping[str, Any]) -> Mapping[str, Any]:
        """
        This design method is basically a logical-effort sizing and a sign-off in the end.
        If there are sizes passed in through optional parameters they will be used and this
        function will only execute the sign-off part.

        Parameters
        ----------
        nsync: int 
            Number of synchronizer flops.
        cload: float
            Loading cap.
        fmax: float
            Max. frequency for sign-off.
        fmin: float
            Min. frequency for sign-off.
        dcd_max: float
            Max. duty cycle distortion allowed.
        rel_del_max: float
            Max. relative delay requirement between launch and measure edges at output.
        pinfo: Mapping[str, any]:
            pinfo for layout.
        core_params: Dict[str, Any]
            Optional. If provided core design part will be skipped.
        sync_params: Dict[str, Any]
            Optional. If provided synchronizer design part will be skipped.
        buf_params: Dict[str, Any]
            Optional. If provided buffer design part will be skipped.

        Returns
        -------
        summary: Mapping[str, Any]
            Design summary.
        """
        tech_globals = get_tech_global_info('aib_ams')

        core_params = self._default_core_params(
        ) if core_params is None else core_params
        sync_params = self._default_sync_params(
        ) if sync_params is None else sync_params
        buf_params = self._default_buf_params(
        ) if buf_params is None else buf_params
        gen_specs: Optional[Mapping[str,
                                    Any]] = kwargs.get('gen_cell_specs', None)
        gen_cell_args: Optional[Mapping[str, Any]] = kwargs.get(
            'gen_cell_args', None)

        if 'width' not in pinfo['row_specs'][0] and 'width' not in pinfo[
                'row_specs'][1]:
            pinfo['row_specs'][0]['width'] = 2 * tech_globals['w_minn']
            pwidth = int(
                np.round(tech_globals['inv_beta'] * 2 *
                         tech_globals['w_minn']))
            pinfo['row_specs'][1]['width'] = pwidth

        gen_params = dict(
            cls_name=self.get_dut_lay_class().get_qualified_name(),
            draw_taps=True,
            params=dict(
                pinfo=pinfo,
                core_params=core_params,
                sync_params=sync_params,
                buf_params=buf_params,
                nsync=nsync,
            ),
        )

        dut = await self.async_new_dut("dcc_helper", STDCellWrapper,
                                       gen_params)

        helper = GatherHelper()
        for env_str in tech_globals['signoff_envs']['all_corners']['envs']:
            for freq in [fmin, fmax]:
                helper.append(
                    self._sim_and_check_specs(dut, env_str, freq, cload,
                                              dcd_max, fmax, rel_del_max))

        results = await helper.gather_err()

        dcd_dict = {}
        del_rel_dict = {}
        idx = 0
        for env_str in tech_globals['signoff_envs']['all_corners']['envs']:
            for freq in ['fmin', 'fmax']:
                if freq == 'fmax':
                    dcd_dict[env_str] = results[idx][1]
                    del_rel_dict[env_str] = results[idx][2]
                idx += 1

        dcd_min = min(dcd_dict.values())
        dcd_max = max(dcd_dict.values())
        del_rel_min = min(del_rel_dict.values())
        del_rel_max = max(del_rel_dict.values())
        self.log(
            f'|DCD| ranges from {dcd_min*100:.4f}% to {dcd_max*100:.4f}%.')
        self.log(
            f'Relative delay ranges from {del_rel_min*100:.4f}% to {del_rel_max*100:.4f}%'
        )

        if gen_specs is not None and gen_cell_args is not None:
            gen_cell_specs = dict(
                lay_class=STDCellWrapper.get_qualified_name(),
                cls_name=DCCHelper.get_qualified_name(),
                params=gen_params,
                **gen_specs,
            )
            return dict(gen_specs=gen_cell_specs, gen_args=gen_cell_args)

        return gen_params
예제 #14
0
    async def async_measure_performance(
            self, name: str, sim_dir: Path, sim_db: SimulationDB,
            dut: Optional[DesignInstance]) -> Dict[str, Any]:
        specs = self.specs
        in_pin: str = specs['in_pin']
        out_pin: str = specs['out_pin']
        c_in: float = specs.get('c_in', 0)
        t_step_min: float = specs.get('t_step_min', 0.1e-12)
        plot: bool = specs.get('plot', False)

        cin_mm = sim_db.make_mm(CombLogicTimingMM, self._cin_specs)
        td_mm = sim_db.make_mm(CombLogicTimingMM, self._td_specs)

        gatherer = GatherHelper()
        gatherer.append(
            sim_db.async_simulate_mm_obj(f'{name}_cin', sim_dir / 'cin', dut,
                                         cin_mm))
        gatherer.append(
            sim_db.async_simulate_mm_obj(f'{name}_td', sim_dir / 'td', dut,
                                         td_mm))
        cin_output, td_output = await gatherer.gather_err()

        t_unit = 10 * t_step_min
        sim_envs = cin_output.data['sim_envs']
        r_src = cin_output.data['sim_params']['r_src']
        cin_timing = cin_output.data['timing_data'][in_pin]
        td_cin_rise = cin_timing['cell_rise']
        td_cin_fall = cin_timing['cell_fall']
        rin_rise, cin_rise = self.fit_rc_in(td_cin_rise, r_src, c_in, t_unit)
        rin_fall, cin_fall = self.fit_rc_in(td_cin_fall, r_src, c_in, t_unit)

        td_timing = td_output.data['timing_data'][out_pin]
        c_load = td_output.data['sim_params']['c_load']
        td_out_rise = td_timing['cell_rise']
        td_out_fall = td_timing['cell_fall']
        rout_rise, cout_rise = self.fit_rc_out(td_out_rise, c_load, t_unit)
        rout_fall, cout_fall = self.fit_rc_out(td_out_fall, c_load, t_unit)

        if plot:
            from matplotlib import pyplot as plt
            if len(sim_envs) > 100:
                raise ValueError('Can only plot with num. sim_envs < 100')
            for idx in range(len(sim_envs)):
                ri_r = rin_rise[idx]
                ri_f = rin_fall[idx]
                ci_r = cin_rise[idx]
                ci_f = cin_fall[idx]
                ro_r = rout_rise[idx]
                ro_f = rout_fall[idx]
                co_r = cout_rise[idx]
                co_f = cout_fall[idx]

                rs = r_src[idx, ...]
                cl = c_load[idx, ...]
                td_cin_r = td_cin_rise[idx, ...]
                td_cin_f = td_cin_fall[idx, ...]
                td_out_r = td_out_rise[idx, ...]
                td_out_f = td_out_fall[idx, ...]

                plt.figure(idx * 100 + 1)
                plt.title(f'{sim_envs[idx]} c_in')
                plt.plot(rs, td_cin_r, 'bo', label='td_rise')
                plt.plot(rs, td_cin_f, 'ko', label='td_fall')
                plt.plot(rs,
                         np.log(2) * rs * (ci_r + c_in) + ri_r * ci_r,
                         '-r',
                         label='td_rise_fit')
                plt.plot(rs,
                         np.log(2) * rs * (ci_f + c_in) + ri_f * ci_f,
                         '-g',
                         label='td_fall_fit')
                plt.legend()

                plt.figure(idx * 100 + 2)
                plt.title(f'{sim_envs[idx]} rc_out')
                plt.plot(cl, td_out_r, 'bo', label='td_rise')
                plt.plot(cl, td_out_f, 'ko', label='td_fall')
                plt.plot(cl, ro_r * (co_r + cl), '-r', label='td_rise_fit')
                plt.plot(cl, ro_f * (co_f + cl), '-g', label='td_fall_fit')
                plt.legend()

            plt.show()

        ans = dict(
            sim_envs=sim_envs,
            r_in=(rin_fall, rin_rise),
            c_in=(cin_fall, cin_rise),
            c_out=(cout_fall, cout_rise),
            r_out=(rout_fall, rout_rise),
        )

        self.log(f'Measurement {name} done, result:\n{pprint.pformat(ans)}')
        write_yaml(sim_dir / f'{name}.yaml', ans)
        return ans