示例#1
0
    async def _upsize_gate_for_del_spec(
        self,
        dut_params: Dict[str, Any],
        tspec: float,
        seg_cur: int,
        is_nand: bool,
        tbm: CombLogicTimingTB,
        seg_even: bool,
        spec_type: str,
        seg_max: Optional[int] = None,
    ) -> Tuple[int, np.ndarray, np.ndarray]:
        if spec_type != 'delay' and spec_type != 'slope':
            raise ValueError("spec_type must be either 'delay' or 'slope'.")

        bin_iter = BinaryIterator(seg_cur, seg_max, step=1 << seg_even)
        while bin_iter.has_next():
            new_seg = bin_iter.get_next()
            dut_params['params'][
                'seg_nand' if is_nand else 'seg_nor'] = new_seg
            dut = await self.async_new_dut('nand_nor_upsize', STDCellWrapper,
                                           dut_params)
            sim_results = await self.async_simulate_tbm_obj(
                'nand_nor_upsize_sim', dut, tbm, self._tb_params)
            if spec_type == 'slope':
                ans = CombLogicTimingTB.get_output_trf(
                    sim_results.data, tbm.specs,
                    'nand_pu' if is_nand else 'nor_pd')
                gate_tr, gate_tf = ans
            else:
                ans = CombLogicTimingTB.get_output_delay(
                    sim_results.data,
                    tbm.specs,
                    'in',
                    'nand_pu' if is_nand else 'nor_pd',
                    out_invert=True)
                gate_tf, gate_tr = ans

            trf_metric = gate_tf if is_nand else gate_tr
            if np.max(trf_metric) > tspec:
                bin_iter.up(np.max(trf_metric) - tspec)
            else:
                bin_iter.down(np.max(trf_metric) - tspec)
                bin_iter.save_info((new_seg, gate_tr, gate_tf))

        info = bin_iter.get_last_save_info()
        if info is None:
            gate_str = "nand" if is_nand else "nor"
            err_str = f'Could not find a size for {gate_str} to meet the target spec of {tspec}.'
            self.error(err_str)
        seg, tr, tf = info

        return seg, tr, tf
示例#2
0
    async def run_nand_nor_signoff(self, dut, del_err, tbm_specs,
                                   tech_globals):
        tbm_specs['env_params'] = dict(vdd=dict())
        tbm_specs['env_params']['vdd'] = tech_globals['signoff_envs'][
            'all_corners']['vddio']
        nand_tdf = []
        nand_tdr = []
        nor_tdf = []
        nor_tdr = []
        for env in tech_globals['signoff_envs']['all_corners']['envs']:
            tbm_specs['sim_envs'] = [env]
            tbm_specs['sim_params']['vdd'] = tbm_specs['env_params']['vdd'][
                env]
            tbm = cast(CombLogicTimingTB,
                       self.make_tbm(CombLogicTimingTB, tbm_specs))
            sim_results = await self.async_simulate_tbm_obj(
                f'signoff_delay_match_{env}', dut, tbm, self._tb_params)
            pu_tdf, pu_tdr = CombLogicTimingTB.get_output_delay(
                sim_results.data,
                tbm.specs,
                'in',
                'nand_pu',
                out_invert=True,
                out_pwr='vdd')
            pd_tdf, pd_tdr = CombLogicTimingTB.get_output_delay(
                sim_results.data,
                tbm.specs,
                'in',
                'nor_pd',
                out_invert=True,
                out_pwr='vdd')
            nand_tdf.append(pu_tdf)
            nand_tdr.append(pu_tdr)
            nor_tdf.append(pd_tdf)
            nor_tdr.append(pd_tdr)

        err_cur = np.abs(np.subtract(nand_tdf, nor_tdr))
        msg = f'del_err: {np.max(err_cur)} [wanted: {del_err}]'
        if np.any(err_cur > del_err):
            self.error(
                f'Unable to match NAND/NOR gate delays to within target, {msg}'
            )
        self.log(msg)
示例#3
0
    async def async_design(self,
                           c_max: float,
                           trf_in: float,
                           w_p: int,
                           w_n: int,
                           r_targ: float,
                           tile_specs: Mapping[str, Any],
                           del_err: float,
                           tile_name: str,
                           seg_even: Optional[bool] = False,
                           **kwargs: Any) -> Mapping[str, Any]:
        """This function designs the main output driver unit cell
        1) Calls DriverPullUpDownDesigner to design output pull up / pull down
        2) Design input NAND and NOR
        3) Characterize and sign off

        Parameters
        ----------
        c_max: float
            Target load capacitance
        trf_in: float
            Input rise / fall time in simulation
        w_p: int
            Initial output PMOS width
        w_n: int
            Initial output NMOS width
        r_targ: float:
            Target nominal (strong) output resistance.
        tile_name: str
            Tile name for layout.
        del_err: float
            Delay mismatch tolerance, for sizing NAND + NOR
        tile_specs: Mapping[str, Any]
            Tile specifications for layout.
        seg_even: Optional[bool]
            True to force segments to be even
        kwargs: Any
            Additional keyword arguments. Unused here

        Returns
        -------
        ans: Mapping[str, Any]
            Design summary, including performance specs and generator parameters
        """
        tinfo_table = TileInfoTable.make_tiles(self.grid, tile_specs)
        self.pinfo = tinfo_table[tile_name]

        self.out_w_p = w_p
        self.out_w_n = w_n

        self.dsn_specs['w_p'] = self.out_w_p
        self.dsn_specs['w_n'] = self.out_w_n

        driver_designer = DriverPullUpDownDesigner(self._root_dir,
                                                   self._sim_db,
                                                   self.dsn_specs)
        summary = await driver_designer.async_design(
            **driver_designer.dsn_specs)

        seg_p: int = summary['seg_p']
        seg_n: int = summary['seg_n']
        self.out_w_p = summary['w_p']
        self.out_w_n = summary['w_n']

        tbm_specs: dict = dict(sim_envs=get_tech_global_info('aib_ams')
                               ['dsn_envs']['slow_io']['env'],
                               thres_lo=0.1,
                               thres_hi=0.9,
                               tstep=None,
                               sim_params=dict(
                                   vdd=get_tech_global_info('aib_ams')
                                   ['dsn_envs']['slow_io']['vddio'],
                                   cload=c_max,
                                   tbit=20 * r_targ * c_max,
                                   trf=trf_in,
                               ),
                               rtol=1e-8,
                               atol=1e-22,
                               save_outputs=['out', 'nand_pu', 'nor_pd', 'in'])
        gate_sizes = await self._size_nand_nor(seg_p, seg_n, trf_in, tbm_specs,
                                               del_err, seg_even)
        nand_seg, nor_seg, nand_p_w_del, nor_n_w_del, w_nom = gate_sizes

        # Characterize Final design
        dut_params = self._get_unit_cell_params(self.pinfo,
                                                seg_p,
                                                seg_n,
                                                nand_seg,
                                                nor_seg,
                                                nand_p_w_del,
                                                nor_n_w_del,
                                                w_min=w_nom)
        dut = await self.async_new_dut('unit_cell', STDCellWrapper, dut_params)

        all_corners = get_tech_global_info(
            'aib_ams')['signoff_envs']['all_corners']
        tdr_worst = -float('inf')
        tdf_worst = -float('inf')
        pu_tr_worst = -float('inf')
        pu_tf_worst = -float('inf')
        pd_tr_worst = -float('inf')
        pd_tf_worst = -float('inf')
        duty_err_worst = 0
        for env in all_corners['envs']:
            tbm_specs['sim_envs'] = [env]
            tbm_specs['sim_params']['vdd'] = all_corners['vddio'][env]
            tbm = cast(CombLogicTimingTB,
                       self.make_tbm(CombLogicTimingTB, tbm_specs))
            sim_results = await self.async_simulate_tbm_obj(
                f'sim_final_{env}', dut, tbm, self._tb_params)

            tdr, tdf = CombLogicTimingTB.get_output_delay(
                sim_results.data, tbm_specs, 'in', 'out', False)
            pu_tr, pu_tf = CombLogicTimingTB.get_output_trf(
                sim_results.data, tbm_specs, 'nand_pu')
            pd_tr, pd_tf = CombLogicTimingTB.get_output_trf(
                sim_results.data, tbm_specs, 'nor_pd')

            tdr_worst = self.set_worst_spec(tdr, tdr_worst)
            tdf_worst = self.set_worst_spec(tdf, tdf_worst)
            pu_tr_worst = self.set_worst_spec(pu_tr, pu_tr_worst)
            pu_tf_worst = self.set_worst_spec(pu_tf, pu_tf_worst)
            pd_tr_worst = self.set_worst_spec(pd_tr, pd_tr_worst)
            pd_tf_worst = self.set_worst_spec(pd_tf, pd_tf_worst)

            duty_err = tdr - tdf
            if np.abs(duty_err) > np.abs(duty_err_worst):
                duty_err_worst = duty_err

        return dict(tdr=tdr_worst,
                    tdf=tdf_worst,
                    pu_tr=pu_tr_worst,
                    pu_tf=pu_tf_worst,
                    pd_tr=pd_tr_worst,
                    pd_tf=pd_tf_worst,
                    duty_err=duty_err_worst,
                    dut_params=dut_params)
示例#4
0
    async def _size_nand_nor(
            self,
            seg_p: int,
            seg_n: int,
            trf: float,
            tbm_specs: dict,
            del_err: float,
            seg_even: Optional[bool] = False,
            nand_p_w_del: Optional[int] = None,
            nor_n_w_del: Optional[int] = None,
            w_nom: Optional[int] = -1) -> Tuple[int, int, int, int, int]:

        # Check for defaults and set them if needed.
        tech_globals = get_tech_global_info('aib_ams')
        if nand_p_w_del is None:
            nand_p_w_del = 0
        if nor_n_w_del is None:
            nor_n_w_del = 0

        if w_nom == -1:
            w_nom = max(tech_globals['w_nomp'], tech_globals['w_nomn'])

        # binary search: up size both nand and nor to meet the slope rate trf
        nand_seg = nor_seg = 1
        max_nand_seg = int(np.round(seg_p / tech_globals['min_fanout']))
        max_nor_seg = int(np.round(seg_n / tech_globals['min_fanout']))
        dut_params = self._get_unit_cell_params(self.pinfo,
                                                seg_p,
                                                seg_n,
                                                nand_seg,
                                                nor_seg,
                                                nand_p_w_del,
                                                nor_n_w_del,
                                                w_min=w_nom)

        tbm_specs['sim_envs'] = tech_globals['dsn_envs']['slow_io']['env']
        tbm_specs['sim_params']['vdd'] = tech_globals['dsn_envs']['slow_io'][
            'vddio']
        tbm = cast(CombLogicTimingTB,
                   self.make_tbm(CombLogicTimingTB, tbm_specs))
        nand_seg, _, tf = await self._upsize_gate_for_trf(
            dut_params, trf, nand_seg, True, tbm, seg_even, max_nand_seg)
        nor_seg, tr, _ = await self._upsize_gate_for_trf(
            dut_params, trf, nor_seg, False, tbm, seg_even, max_nor_seg)

        # Change tbm_spec to design for delay matching in tt corner
        dut_params_new = self._get_unit_cell_params(self.pinfo,
                                                    seg_p,
                                                    seg_n,
                                                    nand_seg,
                                                    nor_seg,
                                                    nand_p_w_del,
                                                    nor_n_w_del,
                                                    w_min=w_nom)
        tbm_specs['sim_envs'] = tech_globals['dsn_envs']['center']['env']
        tbm_specs['sim_params']['vdd'] = tech_globals['dsn_envs']['center'][
            'vddio']
        tbm = cast(CombLogicTimingTB,
                   self.make_tbm(CombLogicTimingTB, tbm_specs))
        dut = await self.async_new_dut('nand_nor_check_delay', STDCellWrapper,
                                       dut_params_new)
        sim_results = await self.async_simulate_tbm_obj(
            'check_delay', dut, tbm, self._tb_params)

        nand_tdf, nand_tdr = CombLogicTimingTB.get_output_delay(
            sim_results.data,
            tbm.specs,
            'in',
            'nand_pu',
            out_invert=True,
            out_pwr='vdd')
        nor_tdf, nor_tdr = CombLogicTimingTB.get_output_delay(sim_results.data,
                                                              tbm.specs,
                                                              'in',
                                                              'nor_pd',
                                                              out_invert=True,
                                                              out_pwr='vdd')

        err_cur = np.abs(nand_tdf - nor_tdr)
        if np.max(err_cur) > del_err:
            # up_size the slower side to make it faster
            if np.max(nor_tdr) < np.max(nand_tdf):
                nand_seg, nand_tdr, nand_tdf = await self._upsize_gate_for_delay(
                    dut_params, np.max(nor_tdr), nand_seg, True, tbm, seg_even,
                    max_nand_seg)
            else:
                nor_seg, nor_tdr, nor_tdf = await self._upsize_gate_for_delay(
                    dut_params, np.max(nand_tdf), nor_seg, False, tbm,
                    seg_even, max_nor_seg)

        # check if t_rise_nand < t_rise_nor and t_fall_nor < t_fall_nand
        rerun = False
        if not np.all(nand_tdr < nor_tdr):
            rerun = nand_p_w_del + 1 + w_nom <= tech_globals['w_maxp']
            new_nand_p_w_del = nand_p_w_del + 1 if rerun else nand_p_w_del
        else:
            new_nand_p_w_del = nand_p_w_del

        if not np.all(nor_tdf < nand_tdf):
            rerun = nor_n_w_del + 1 + w_nom <= tech_globals['w_maxn']
            new_nor_n_w_del = nor_n_w_del + 1 if rerun else nor_n_w_del
        else:
            new_nor_n_w_del = nor_n_w_del

        if rerun:
            await self._size_nand_nor(seg_p, seg_n, trf, tbm_specs, del_err,
                                      seg_even, new_nand_p_w_del,
                                      new_nor_n_w_del, w_nom)

        await self.run_nand_nor_signoff(dut, del_err, tbm_specs, tech_globals)

        return nand_seg, nor_seg, nand_p_w_del, nor_n_w_del, w_nom
示例#5
0
    async def _design_lvl_shift_inv_pun(self, pseg: int, nseg: int,
                                        inv_nseg: int, out_inv_m: int,
                                        fanout: float, pinfo: Any,
                                        tbm_specs: Dict[str, Any], has_rst,
                                        dual_output, vin,
                                        vout) -> Tuple[int, int]:
        """
        Given the NMOS pull down size, this function will design the PMOS pull up so that the delay
        mismatch is minimized.
        # TODO: Need to double check on how this handles corners
        """
        inv_beta = get_tech_global_info('bag3_digital')['inv_beta']
        tb_params = self._get_full_tb_params()
        # Use a binary iterator to find the PMOS size
        load_seg = nseg + (pseg if has_rst else 0)
        inv_pseg_nom = int(
            np.round(inv_beta * load_seg / ((1 + inv_beta) * fanout)))
        inv_pseg_nom = 1 if inv_pseg_nom == 0 else inv_pseg_nom
        iterator = BinaryIterator(-inv_pseg_nom + 1, 0)
        err_best = float('inf')
        inv_in_nseg, inv_in_pseg = self._size_input_inv_for_fanout(
            inv_pseg_nom, inv_nseg, pseg, nseg, fanout, has_rst)
        all_corners = get_tech_global_info(
            'bag3_digital')['signoff_envs']['all_corners']

        while iterator.has_next():
            pseg_off = iterator.get_next()
            inv_pseg = inv_pseg_nom + pseg_off
            dut_params = self._get_lvl_shift_params_dict(
                pinfo, pseg, nseg, inv_pseg, inv_nseg, inv_in_nseg,
                inv_in_pseg, out_inv_m, has_rst, dual_output)
            dut = await self.async_new_dut('lvshift', STDCellWrapper,
                                           dut_params)

            err_worst = -1 * float('Inf')
            for env in all_corners['envs']:
                tbm_specs['sim_envs'] = [env]
                tbm_specs['sim_params']['vdd_in'] = all_corners[vin][env]
                tbm_specs['sim_params']['vdd'] = all_corners[vout][env]
                tbm = cast(CombLogicTimingTB,
                           self.make_tbm(CombLogicTimingTB, tbm_specs))
                sim_results = await self.async_simulate_tbm_obj(
                    f'sim_inv_pseg_{inv_pseg}_{env}', dut, tbm, tb_params)
                tdr_cur, tdf_cur = CombLogicTimingTB.get_output_delay(
                    sim_results.data,
                    tbm.specs,
                    'in',
                    'out',
                    False,
                    in_pwr='vdd_in',
                    out_pwr='vdd')
                '''
                plt.figure()
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['in'].flatten(), 'b')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['inb_buf'].flatten(), 'g')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['in_buf'].flatten(), 'r')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['midn'].flatten(), 'k')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['midp'].flatten(), 'c')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['out'].flatten(), 'm')
                plt.legend(['in', 'inb_buf', 'in_buf', 'midn', 'midp', 'out'])
                plt.title(f'pseg_off: {pseg_off}, pseg: {inv_pseg}, nseg: {inv_nseg-pseg_off}, fanout: {fanout}')
                plt.show(block=False)
                '''

                # Error checking
                if math.isinf(np.max(tdr_cur)) or math.isinf(np.max(tdf_cur)):
                    raise ValueError("Got infinite delay!")
                if np.min(tdr_cur) < 0 or np.min(tdf_cur) < 0:
                    raise ValueError("Got negative delay.")

                err_cur = np.abs(tdr_cur[0] - tdf_cur[0])
                if err_cur > err_worst:
                    err_worst = err_cur
                    worst_env = env
                    tdr = tdr_cur[0]
                    tdf = tdf_cur[0]
            '''
            print(f'iter: {inv_pseg}')
            print(f'env: {worst_env}, tdr: {tdr}, tdf: {tdf}')
            breakpoint()
            '''

            if tdr < tdf:
                iterator.down(tdr - tdf)
            else:
                iterator.up(tdr - tdf)

            err_abs = np.abs(tdr - tdf)
            if err_abs < err_best:
                err_best = err_abs
                iterator.save_info(pseg_off)

        pseg_off = iterator.get_last_save_info()
        pseg_off = 0 if pseg_off is None else pseg_off  # Should only hit this case if inv_pseg_nom = 1
        inv_pseg = inv_pseg_nom + pseg_off

        return inv_pseg, inv_nseg - 0 * pseg_off
示例#6
0
    async def _design_output_inverter(self, inv_in_pseg: int, inv_in_nseg: int,
                                      pseg: int, nseg: int, inv_nseg: int,
                                      inv_pseg: int, out_inv_m: int,
                                      fanout: float, pinfo: Any,
                                      tbm_specs: Dict[str, Any], has_rst, vin,
                                      vout) -> int:
        """
        Given all other sizes and total output inverter segments, this function will optimize the output inverter
        to minimize rise/fall mismatch.
        """
        tb_params = self._get_full_tb_params()
        # Use a binary iterator to find the PMOS size
        iterator = BinaryIterator(-out_inv_m + 1, out_inv_m - 1)
        err_best = float('inf')
        all_corners = get_tech_global_info(
            'bag3_digital')['signoff_envs']['all_corners']

        while iterator.has_next():
            pseg_off = iterator.get_next()
            dut_params = self._get_lvl_shift_params_dict(pinfo,
                                                         pseg,
                                                         nseg,
                                                         inv_pseg,
                                                         inv_nseg,
                                                         inv_in_nseg,
                                                         inv_in_pseg,
                                                         out_inv_m,
                                                         has_rst,
                                                         dual_output=False,
                                                         skew_out=True,
                                                         out_pseg_off=pseg_off)
            dut = await self.async_new_dut('lvshift', STDCellWrapper,
                                           dut_params)

            err_worst = -1 * float('Inf')
            worst_env = ''
            sim_worst = None
            for env in all_corners['envs']:
                tbm_specs['sim_envs'] = [env]
                tbm_specs['sim_params']['vdd_in'] = all_corners[vin][env]
                tbm_specs['sim_params']['vdd'] = all_corners[vout][env]
                tbm = cast(CombLogicTimingTB,
                           self.make_tbm(CombLogicTimingTB, tbm_specs))
                sim_results = await self.async_simulate_tbm_obj(
                    f'sim_output_inv_pseg_{pseg_off}_{env}', dut, tbm,
                    tb_params)
                tdr_cur, tdf_cur = CombLogicTimingTB.get_output_delay(
                    sim_results.data,
                    tbm.specs,
                    'in',
                    'out',
                    False,
                    in_pwr='vdd_in',
                    out_pwr='vdd')

                if math.isinf(np.max(tdr_cur)) or math.isinf(np.max(tdf_cur)):
                    raise ValueError("Got infinite delay!")
                if tdr_cur[0] < 0 or tdf_cur[0] < 0:
                    raise ValueError("Got negative delay.")

                err_cur = np.abs(tdr_cur[0] - tdf_cur[0])
                if err_cur > err_worst:
                    err_worst = err_cur
                    worst_env = env
                    tdr = tdr_cur[0]
                    tdf = tdf_cur[0]
                    sim_worst = sim_results
            '''
            print(f'iter: {pseg_off}')
            print(f'env: {worst_env}, tdr: {tdr}, tdf: {tdf}')
            breakpoint()
            '''

            if tdr < tdf:
                iterator.down(tdr - tdf)
            else:
                iterator.up(tdr - tdf)

            err_abs = np.abs(tdr - tdf)
            if err_abs < err_best:
                err_best = err_abs
                iterator.save_info(pseg_off)

        pseg_off = iterator.get_last_save_info()
        if pseg_off is None:
            raise ValueError("Could not find PMOS size to match target delay")

        self.log(f'Calculated output inverter to skew PMOS by {pseg_off}.')

        return pseg_off
示例#7
0
    async def _design_lvl_shift_inv_pdn(self, pseg: int, nseg: int,
                                        out_inv_m: int, fanout: float,
                                        pinfo: Any, tbm_specs: Dict[str, Any],
                                        has_rst, dual_output, vin,
                                        vout) -> int:
        """
        This function figures out the NMOS nseg for the inverter given the target delay
        TODO: Make this use digitaldB instead
        """
        min_fanout: float = get_tech_global_info('bag3_digital')['min_fanout']
        inv_beta: float = get_tech_global_info('bag3_digital')['inv_beta']
        tb_params = self._get_full_tb_params()

        # Use a binary iterator to find the NMOS size
        max_nseg = int(np.round(nseg / min_fanout))
        iterator = BinaryIterator(1, max_nseg)
        load_seg = nseg + (pseg if has_rst else 0)
        inv_pseg = int(
            np.round(inv_beta * load_seg / ((1 + inv_beta) * fanout)))
        inv_pseg = 1 if inv_pseg == 0 else inv_pseg

        all_corners = get_tech_global_info(
            'bag3_digital')['signoff_envs']['all_corners']
        while iterator.has_next():
            inv_nseg = iterator.get_next()
            inv_in_nseg, inv_in_pseg = self._size_input_inv_for_fanout(
                inv_pseg, inv_nseg, pseg, nseg, fanout, has_rst)

            dut_params = self._get_lvl_shift_params_dict(
                pinfo, pseg, nseg, inv_pseg, inv_nseg, inv_in_pseg,
                inv_in_nseg, out_inv_m, has_rst, dual_output)
            dut = await self.async_new_dut('lvshift', STDCellWrapper,
                                           dut_params)
            err_worst = -1 * float('Inf')
            for env in all_corners['envs']:
                tbm_specs['sim_envs'] = [env]
                tbm_specs['sim_params']['vdd_in'] = all_corners[vin][env]
                tbm_specs['sim_params']['vdd'] = all_corners[vout][env]
                tbm = cast(CombLogicTimingTB,
                           self.make_tbm(CombLogicTimingTB, tbm_specs))

                sim_results = await self.async_simulate_tbm_obj(
                    f'sim_inv_nseg_{inv_nseg}_{env}', dut, tbm, tb_params)
                tdr_cur, tdf_cur = CombLogicTimingTB.get_output_delay(
                    sim_results.data,
                    tbm.specs,
                    'inb_buf',
                    'in_buf',
                    True,
                    in_pwr='vdd_in',
                    out_pwr='vdd_in')
                target_cur, _ = CombLogicTimingTB.get_output_delay(
                    sim_results.data,
                    tbm.specs,
                    'inb_buf',
                    'midp',
                    True,
                    in_pwr='vdd_in',
                    out_pwr='vdd')

                # Check for error conditions
                if math.isinf(np.max(tdr_cur)) or math.isinf(
                        np.max(tdf_cur)) or math.isinf(np.max(target_cur)):
                    raise ValueError(
                        "Got infinite delay in level shifter design script (sizing inverter NMOS)."
                    )
                if np.min(tdr_cur) < 0 or np.min(target_cur) < 0:
                    raise ValueError(
                        "Got negative delay in level shifter design script (sizing inverter NMOS). "
                    )

                err_cur = tdr_cur[0] - target_cur[0]
                if err_cur > err_worst:
                    err_worst = err_cur
                    worst_env = env
                    tdr = tdr_cur[0]
                    target = target_cur[0]
            '''
            print(f'iter: {inv_nseg}')
            print(f'env: {worst_env}, tdr: {tdr}, target: {target}')
            '''

            if tdr < target:
                iterator.down(target - tdr)
                iterator.save_info(inv_nseg)
            else:
                iterator.up(target - tdr)

        tmp_inv_nseg = iterator.get_last_save_info()
        if tmp_inv_nseg is None:
            tmp_inv_nseg = max_nseg
            self.warn(
                "Could not size pull down of inverter to meet required delay, picked the "
                "max inv_nseg based on min_fanout.")

        return tmp_inv_nseg
示例#8
0
    async def signoff_dut(
        self,
        dut,
        cload,
        vin,
        vout,
        dmax,
        trf_in,
        is_ctrl,
        has_rst,
        exception_on_dmax: bool = True
    ) -> Tuple[float, float, str, float, str]:

        tech_info = get_tech_global_info('bag3_digital')
        all_corners = tech_info['signoff_envs']['all_corners']

        # Run level shifter extreme corner signoff
        envs = tech_info['signoff_envs']['lvl_func']['env']
        vdd_out = tech_info['signoff_envs']['lvl_func']['vddo']
        vdd_in = tech_info['signoff_envs']['lvl_func']['vddi']

        tbm_specs = self._get_tbm_params(envs, vdd_in, vdd_out, trf_in, cload,
                                         10 * dmax)
        tbm_specs['save_outputs'] = [
            'in', 'inbar', 'inb_buf', 'in_buf', 'midn', 'midp', 'out', 'outb'
        ]
        tbm = cast(CombLogicTimingTB,
                   self.make_tbm(CombLogicTimingTB, tbm_specs))

        # sign off signal path
        tb_params = self._get_full_tb_params()
        sim_results = await self.async_simulate_tbm_obj(
            f'signoff_lvlshift_extreme', dut, tbm, tb_params)
        tdr, tdf = CombLogicTimingTB.get_output_delay(sim_results.data,
                                                      tbm_specs,
                                                      'in',
                                                      'out',
                                                      False,
                                                      in_pwr='vdd_in',
                                                      out_pwr='vdd')

        td = max(tdr, tdf)
        if td < float('inf'):
            self.log(
                'Level shifter signal path passed extreme corner signoff.')
        else:
            plt.plot(sim_results.data['time'].flatten(),
                     sim_results.data['in'].flatten(), 'b')
            plt.plot(sim_results.data['time'].flatten(),
                     sim_results.data['out'].flatten(), 'g')
            plt.show(block=False)
            raise ValueError(
                'Level shifter design failed extreme corner signoff.')

        # sign off reset
        if has_rst:
            tbm_specs['stimuli_pwr'] = 'vdd'
            tbm = cast(CombLogicTimingTB,
                       self.make_tbm(CombLogicTimingTB, tbm_specs))
            rst_tb_params = self._get_rst_tb_params()
            sim_results = await self.async_simulate_tbm_obj(
                f'signoff_lvlshift_rst_extreme', dut, tbm, rst_tb_params)
            tdr, tdf = CombLogicTimingTB.get_output_delay(sim_results.data,
                                                          tbm_specs,
                                                          'in',
                                                          'out',
                                                          False,
                                                          in_pwr='vdd_in',
                                                          out_pwr='vdd')
            self.log(f"Reset Delay Overall: tdr: {tdr}, tdf: {tdf} ")
            td = max(tdr, tdf)
            if td < float('inf'):
                self.log(
                    'Level shifter reset path passed extreme corner signoff.')
            else:
                plt.plot(sim_results.data['time'].flatten(),
                         sim_results.data['in'].flatten(), 'b')
                plt.plot(sim_results.data['time'].flatten(),
                         sim_results.data['out'].flatten(), 'g')
                plt.show(block=False)
                raise ValueError(
                    'Level shifter design failed reset extreme corner signoff.'
                )

        envs = all_corners['envs']
        worst_trst = -float('inf')
        worst_td = -float('inf')
        worst_tdf = -float('inf')
        worst_tdr = -float('inf')
        worst_var = 0
        worst_env = ''
        worst_var_env = ''

        for env in envs:
            vdd_in = all_corners[vin][env]
            vdd_out = all_corners[vout][env]
            tbm_specs = self._get_tbm_params([env], vdd_in, vdd_out, trf_in,
                                             cload, 10 * dmax)
            tbm_specs['stimuli_pwr'] = 'vdd_in'
            tbm_specs['save_outputs'] = [
                'in', 'inb_buf', 'in_buf', 'midn', 'midp', 'out'
            ]
            tbm = cast(CombLogicTimingTB,
                       self.make_tbm(CombLogicTimingTB, tbm_specs))

            # sign off signal path
            tb_params = self._get_full_tb_params()
            sim_results = await self.async_simulate_tbm_obj(
                f'signoff_lvlshift_{env}', dut, tbm, tb_params)
            tdr, tdf = CombLogicTimingTB.get_output_delay(sim_results.data,
                                                          tbm_specs,
                                                          'in',
                                                          'out',
                                                          False,
                                                          in_pwr='vdd_in',
                                                          out_pwr='vdd')
            self.log(f"Delay Overall: tdr: {tdr}, tdf: {tdf} ")

            td = max(tdr, tdf)
            if td > worst_td:
                worst_td = td
                worst_tdf = tdf
                worst_tdr = tdr
                worst_env = env

            if not is_ctrl:
                delay_var = (tdr - tdf)
                if np.abs(delay_var) > np.abs(worst_var):
                    worst_var = delay_var
                    worst_var_env = env
            '''
            # Debug
            # -----
            td_iinv_r, td_iinv_f = CombLogicTimingTB.get_output_delay(sim_results.data, tbm.specs, 'in',
                                                          'inb_buf', True, in_pwr='vdd_in',
                                                          out_pwr='vdd_in')
            td_minv_r, td_minv_f = CombLogicTimingTB.get_output_delay(sim_results.data, tbm.specs, 'inb_buf',
                                                          'in_buf', True, in_pwr='vdd_in',
                                                          out_pwr='vdd_in')
            td_pdn_r, td_pdn_f = CombLogicTimingTB.get_output_delay(sim_results.data, tbm.specs, 'in_buf',
                                                          'midn', True, in_pwr='vdd_in',
                                                          out_pwr='vdd')
            td_oinv_r, td_oinv_f = CombLogicTimingTB.get_output_delay(sim_results.data, tbm.specs, 'midn',
                                                          'out', True, in_pwr='vdd_in',
                                                          out_pwr='vdd')
            td_pdp_r, td_pdp_f = CombLogicTimingTB.get_output_delay(sim_results.data, tbm.specs, 'inb_buf',
                                                          'midp', True, in_pwr='vdd_in',
                                                          out_pwr='vdd')
            td_pun_r, td_pun_f = CombLogicTimingTB.get_output_delay(sim_results.data, tbm.specs, 'midp',
                                                          'midn', True, in_pwr='vdd',
                                                          out_pwr='vdd')

            if env == 'ss_125':
                plt.figure()
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['in'].flatten(), 'b')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['inb_buf'].flatten(), 'g')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['in_buf'].flatten(), 'r')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['midn'].flatten(), 'k')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['midp'].flatten(), 'c')
                plt.plot(sim_results.data['time'].flatten(), sim_results.data['out'].flatten(), 'm')
                plt.legend(['in', 'inb_buf', 'in_buf', 'midn', 'midp', 'out'])
                plt.title(f'{env}')
                plt.show(block=False)

                print(f'Path rise out: {td_iinv_r} + {td_minv_f} + {td_pdn_r} + {td_oinv_f}')
                print(f'Path fall out: {td_iinv_f} + {td_pdp_r} + {td_pun_f} + {td_oinv_r}')
                breakpoint()
            # ----
            '''

            # sign off reset
            if has_rst:
                tbm_specs['stimuli_pwr'] = 'vdd'
                tbm = cast(CombLogicTimingTB,
                           self.make_tbm(CombLogicTimingTB, tbm_specs))
                rst_tb_params = self._get_rst_tb_params()
                sim_results = await self.async_simulate_tbm_obj(
                    f'signoff_lvlshift_rst_{env}', dut, tbm, rst_tb_params)
                tdr, tdf = CombLogicTimingTB.get_output_delay(sim_results.data,
                                                              tbm_specs,
                                                              'in',
                                                              'out',
                                                              False,
                                                              in_pwr='vdd_in',
                                                              out_pwr='vdd')
                self.log(f"Reset Delay Overall: tdr: {tdr}, tdf: {tdf} ")
                td = max(tdr, tdf)
                if td > worst_trst:
                    worst_trst = td
                    worst_trst_env = env

        td_target = 20 * trf_in if is_ctrl else dmax
        self.log(
            f'td_target = {td_target}, worst_tdr = {worst_tdr}, worst_tdf = {worst_tdf}, '
            f'worst_env = {worst_env}')
        #breakpoint()

        if worst_tdr > td_target or worst_tdf > td_target:
            msg = 'Level shifter delay did not meet target.'
            if exception_on_dmax:
                raise RuntimeError(msg)
            else:
                self.log(msg)
        if has_rst:
            self.log(
                f'worst_trst = {worst_trst}, worst_trst_env = {worst_trst_env}'
            )

        if worst_tdr > 20 * trf_in or worst_tdf > 20 * trf_in:
            raise RuntimeError(
                "Level shifter reset delay exceeded simulation period.")
        return worst_tdr, worst_tdf, worst_env, worst_var, worst_var_env
示例#9
0
    async def _find_tgate_and_tint(self, inv_in_pseg, inv_in_nseg, pseg, nseg,
                                   inv_nseg, inv_pseg, out_inv_m, pseg_off,
                                   inv_input_cap, cload, k_ratio, pinfo,
                                   tbm_specs, is_ctrl, has_rst, dual_output,
                                   vin, vout,
                                   worst_env) -> Tuple[dict, dict, float]:

        # Setup nominal parameters and delay
        lv_params = dict(
            pinfo=pinfo,
            seg_p=pseg,
            seg_n=nseg,
            seg_inv_p=inv_pseg,
            seg_inv_n=inv_nseg,
            seg_in_inv_n=inv_in_nseg,
            seg_in_inv_p=inv_in_pseg,
            out_inv_m=out_inv_m,
            out_pseg_off=pseg_off,
        )
        tb_params = self._get_full_tb_params()
        dut_params = self._get_lvl_shift_params_dict(**lv_params,
                                                     has_rst=has_rst,
                                                     dual_output=False,
                                                     skew_out=True)
        dut = await self.async_new_dut('lvshift', STDCellWrapper, dut_params)
        all_corners = get_tech_global_info(
            'bag3_digital')['signoff_envs']['all_corners']
        tbm_specs['sim_envs'] = [worst_env]
        tbm_specs['sim_params']['vdd_in'] = all_corners[vin][worst_env]
        tbm_specs['sim_params']['vdd'] = all_corners[vout][worst_env]
        tbm = cast(CombLogicTimingTB,
                   self.make_tbm(CombLogicTimingTB, tbm_specs))
        sim_results_orig = await self.async_simulate_tbm_obj(
            f'sim_output_inv_pseg_{pseg_off}', dut, tbm, tb_params)
        tdr_nom, tdf_nom = CombLogicTimingTB.get_output_delay(
            sim_results_orig.data,
            tbm.specs,
            'in',
            'out',
            False,
            in_pwr='vdd_in',
            out_pwr='vdd')

        slope_dict = dict()
        tot_sense_dict = dict()
        tint_dict = dict()
        segs_out = cload / inv_input_cap
        tweak_vars = [
            ('seg_in_inv_p', 'in', 'inb_buf', 'fall', True, 'vdd_in', 'vdd_in',
             inv_in_pseg + inv_in_nseg,
             nseg + inv_nseg + inv_pseg + (pseg if has_rst else 0), 0),
            ('seg_n', 'inb_buf', 'midp', 'rise', True, 'vdd_in', 'vdd', nseg,
             pseg, 1 / k_ratio),
            ('seg_p', 'midp', 'midn', 'fall', True, 'vdd', 'vdd', pseg,
             2 * out_inv_m - pseg_off, 1),
            ('out_inv_m', 'midn', 'out', 'rise', True, 'vdd', 'vdd',
             2 * out_inv_m - pseg_off, segs_out, 0)
        ]
        tint_tot = 0
        for var_tuple in tweak_vars:
            var, node_in, node_out, in_edge, invert, in_sup, out_sup, seg_in, seg_load, fan_min = var_tuple
            tdr_stg_nom, tdf_stg_nom = CombLogicTimingTB.get_output_delay(
                sim_results_orig.data,
                tbm.specs,
                node_in,
                node_out,
                invert,
                in_pwr=in_sup,
                out_pwr=out_sup)

            nom_var = lv_params[var]
            lv_params[var] = nom_var + 1

            dut_params = self._get_lvl_shift_params_dict(**lv_params,
                                                         has_rst=has_rst,
                                                         dual_output=False,
                                                         skew_out=True)
            dut = await self.async_new_dut('lvshift', STDCellWrapper,
                                           dut_params)
            sim_results = await self.async_simulate_tbm_obj(
                f'sim_check_tgate_tint', dut, tbm, tb_params)
            tdr_new, tdf_new = CombLogicTimingTB.get_output_delay(
                sim_results.data,
                tbm.specs,
                'in',
                'out',
                False,
                in_pwr='vdd_in',
                out_pwr='vdd')
            tdr_stg_new, tdf_stg_new = CombLogicTimingTB.get_output_delay(
                sim_results.data,
                tbm.specs,
                node_in,
                node_out,
                invert,
                in_pwr=in_sup,
                out_pwr=out_sup)
            td_new, td_nom = (tdr_stg_new,
                              tdr_stg_nom) if in_edge == 'rise' else (
                                  tdf_stg_new, tdf_stg_nom)

            slope_dict[var] = (td_nom[0] -
                               td_new[0]) / (seg_load / seg_in - seg_load /
                                             (seg_in + 1))
            tot_sense_dict[var] = tdf_nom[0] - tdf_new[0]
            tint_dict[var] = td_nom[0] - slope_dict[var] * seg_load / seg_in
            lv_params[var] = nom_var
            tint_tot += fan_min * slope_dict[var] + tint_dict[var]

        return slope_dict, tint_dict, tint_tot
示例#10
0
    async def async_design(self,
                           num_units: int,
                           num_units_nom: int,
                           num_units_min: int,
                           trf_max: float,
                           r_targ: float,
                           r_min_weak: float,
                           c_ext: float,
                           freq: float,
                           trf_in: float,
                           rel_err: float,
                           del_err: float,
                           tile_name: str,
                           tile_specs: Mapping[str, Any],
                           res_mm_specs: Dict[str, Any],
                           ridx_p: int = 1,
                           ridx_n: int = 1,
                           stack_max: int = 10,
                           tran_options: Optional[Mapping[str, Any]] = None,
                           max_iter: int = 10,
                           **kwargs: Any) -> Mapping[str, Any]:
        """ Design the Output Driver Cell

        1) Calls functions to get initial design for main driver unit cell and weak driver
        2) Characterize design
        3) Iterate on main driver design to account for additional loading from other unit cells

        Parameters
        ----------
        num_units: int
            Number of unit cells. Must be between 3 and 6
        num_units_nom: int
            ???
        num_units_min: int
            Min. number of unit cells
        trf_max: float
            Max. output rise / fall time
        r_targ: float
            Target output resistance
        r_min_weak: float
            Target output resistance for weak driver
        c_ext: float
            Load capacitance
        freq: float
            Operating switching frequency
        trf_in: float
            Input rise / fall time
        rel_err: float
            Output resistance error tolerance, used in DriverPullUpDownDesigner
        del_err: float
            Delay mismatch tolerance, used in DriverUnitCellDesigner for sizing NAND + NOR
        tile_name: str
            Tile name for layout.
        tile_specs: Mapping[str, Any]
            Tile specifications for layout.
        res_mm_specs: Mapping[str, Any]
            MeasurementManager specs for DriverPullUpDownMM, used in DriverPullUpDownDesigner
        ridx_n: int
            NMOS transistor row
        ridx_p: int
            PMOS transistor row
        stack_max: int
            Max. number of stacks possible in pull up / pull down driver
        tran_options: Optional[Mapping[str, Any]]
            Additional transient simulation options dictionary, used in DriverPullUpDownDesigner
        max_iter: int
            Max. number of iterations for final main driver resizing
        kwargs: Any
            Additional keyword arguments. Unused here

        Returns
        -------
        ans: Mapping[str, Any]
            Design summary, including generator parameters and performance summary

        """
        tech_info = get_tech_global_info('aib_ams')
        w_p = tech_info['w_maxp']
        w_n = tech_info['w_maxn']
        tile_specs['place_info'][tile_name]['row_specs'][0]['width'] = w_n
        tile_specs['place_info'][tile_name]['row_specs'][1]['width'] = w_p
        self._dsn_specs['tile_specs']['place_info'][tile_name]['row_specs'][0][
            'width'] = w_n
        self._dsn_specs['tile_specs']['place_info'][tile_name]['row_specs'][1][
            'width'] = w_p
        core_params = dict(
            r_targ=r_targ * num_units,
            stack_max=stack_max,
            trf_max=trf_max,
            c_min=c_ext / num_units,
            c_max=c_ext / num_units_min,
            w_p=w_p,
            w_n=w_n,
            freq=freq,
            vdd=tech_info['dsn_envs']['slow_io']['vddio'],
            vdd_max=tech_info['signoff_envs']['vmax']['vddio'],
            trf_in=trf_in,
            rel_err=rel_err,
            del_err=del_err,
            tile_specs=tile_specs,
            tile_name=tile_name,
            tran_options=tran_options,
            res_mm_specs=res_mm_specs,
        )
        weak_params = core_params.copy()
        weak_params['w_p'] = tech_info['w_minp']
        weak_params['w_n'] = tech_info['w_minn']
        weak_params['r_targ'] = r_min_weak
        weak_params['is_weak'] = True

        # Design weak pull-up/pull-down
        weak_designer = DriverPullUpDownDesigner(self._root_dir, self._sim_db,
                                                 self._dsn_specs)
        weak_designer.set_dsn_specs(weak_params)
        weak_results = await weak_designer.async_design(**weak_params)

        # Design main output driver
        core_designer = DriverUnitCellDesigner(self._root_dir, self._sim_db,
                                               self._dsn_specs)
        core_designer.set_dsn_specs(core_params)
        summary = await core_designer.async_design(**core_params)

        # Characterize the initial design
        result_params = summary['dut_params']['params']
        tinfo_table = TileInfoTable.make_tiles(self.grid, tile_specs)
        pinfo = tinfo_table[tile_name]
        dut_params = dict(cls_name='aib_ams.layout.driver.AIBOutputDriver',
                          draw_taps=True,
                          params=dict(
                              pinfo=pinfo,
                              pupd_params=dict(
                                  seg_p=weak_results['seg_p'],
                                  seg_n=weak_results['seg_n'],
                                  stack=weak_results['stack'],
                                  w_p=weak_results['w_p'],
                                  w_n=weak_results['w_n'],
                              ),
                              unit_params=dict(
                                  seg_p=result_params['seg_p'],
                                  seg_n=result_params['seg_n'],
                                  seg_nand=result_params['seg_nand'],
                                  seg_nor=result_params['seg_nor'],
                                  w_p=result_params['w_p'],
                                  w_n=result_params['w_n'],
                                  w_p_nand=result_params['w_p_nand'],
                                  w_n_nand=result_params['w_n_nand'],
                                  w_p_nor=result_params['w_p_nor'],
                                  w_n_nor=result_params['w_n_nor']),
                              export_pins=True,
                          ))
        tbm_specs: Dict[str, Any] = dict(thres_lo=0.1,
                                         thres_hi=0.9,
                                         tstep=None,
                                         sim_params=dict(
                                             cload=c_ext,
                                             tbit=20 * r_targ * c_ext,
                                             trf=trf_in,
                                         ),
                                         rtol=1e-8,
                                         atol=1e-22,
                                         tran_options=tran_options,
                                         save_outputs=['out', 'in'])

        if num_units == 3:
            n_enb_str = 'VDD'
            p_en_str = 'VSS'
        elif num_units == 4:
            n_enb_str = 'VDD,VSS'
            p_en_str = 'VSS,VDD'
        elif num_units == 5:
            n_enb_str = 'VSS,VDD'
            p_en_str = 'VDD,VSS'
        elif num_units == 6:
            n_enb_str = 'VSS,VSS'
            p_en_str = 'VDD,VDD'
        else:
            raise ValueError('Number of units must be between 3 and 6.')

        tb_params = dict(load_list=[('out', 'cload')],
                         dut_conns={
                             'txpadout': 'out',
                             'din': 'in',
                             'n_enb_drv<1:0>': n_enb_str,
                             'p_en_drv<1:0>': p_en_str,
                             'tristate': 'VSS',
                             'tristateb': 'VDD',
                             'weak_pden': 'VSS',
                             'weak_puenb': 'VDD'
                         })

        all_corners = tech_info['signoff_envs']['all_corners']
        trf_worst = -float('inf')
        tdr_worst = -float('inf')
        tdf_worst = -float('inf')
        tf_worst = -float('inf')
        tr_worst = -float('inf')
        worst_env = ''
        duty_err_worst = 0
        dut = await self.async_new_dut('output_driver', STDCellWrapper,
                                       dut_params)
        for env in all_corners['envs']:
            tbm_specs['sim_envs'] = [env]
            tbm_specs['sim_params']['vdd'] = all_corners['vddio'][env]
            tbm = cast(CombLogicTimingTB,
                       self.make_tbm(CombLogicTimingTB, tbm_specs))
            sim_results = await self.async_simulate_tbm_obj(
                f'sim_final_{env}', dut, tbm, tb_params)
            tdr, tdf = CombLogicTimingTB.get_output_delay(
                sim_results.data, tbm_specs, 'in', 'out', False)

            if tdr[0] > tdr_worst:
                tdr_worst = tdr[0]
            if tdf[0] > tdf_worst:
                tdf_worst = tdf[0]

            duty_err = tdr[0] - tdf[0]
            if np.abs(duty_err) > np.abs(duty_err_worst):
                duty_err_worst = duty_err

            tr, tf = CombLogicTimingTB.get_output_trf(sim_results.data,
                                                      tbm_specs, 'out')
            trf = max(np.max(tr), np.max(tf))

            if trf > trf_worst:
                trf_worst = trf
                tr_worst = tr[0]
                tf_worst = tf[0]
                worst_env = env

        self.logger.info('---')
        self.logger.info("Completed initial design.")
        self.logger.info(f'Target R per segment was: {core_params["r_targ"]}')
        self.logger.info(
            f'Worst trf was: {trf_worst} / rise: {tr_worst}, fall: {tf_worst}'
            + f'in corner {worst_env}')
        self.logger.info(f'Worst delay was: {max(tdr_worst, tdf_worst)}')
        self.logger.info(f'Worst duty cycle error was: {duty_err_worst}')
        self.logger.info('---')

        # Loop on trf to take into account loading from unit cells that are nominally off
        # but not included in single unit-cell design script.
        for i in range(1, max_iter + 1):
            scale_error = trf_worst / trf_max

            if scale_error < 1:
                break

            core_params['r_targ'] = core_params['r_targ'] / scale_error * (
                1 - 1 / (2 * max_iter))
            self.logger.info(f'Scale error set to {scale_error}.')
            self.logger.info(
                f'New target R per segment set to {core_params["r_targ"]}')

            core_designer.set_dsn_specs(core_params)
            # TODO: Allow designer to start from previous design point and/or guess at scaled
            #       design (improve runtime)
            summary = await core_designer.async_design(**core_params)

            result_params = summary['dut_params']['params']

            dut_params['params']['unit_params'] = dict(
                seg_p=result_params['seg_p'],
                seg_n=result_params['seg_n'],
                seg_nand=result_params['seg_nand'],
                seg_nor=result_params['seg_nor'],
                w_p=result_params['w_p'],
                w_n=result_params['w_n'],
                w_p_nand=result_params['w_p_nand'],
                w_n_nand=result_params['w_n_nand'],
                w_p_nor=result_params['w_p_nor'],
                w_n_nor=result_params['w_n_nor'],
            )

            tbm_specs['sim_params']['tbit'] = 1 / freq
            # tbm_specs['sim_params']['tbit'] = 20 * core_params['r_targ'] * c_ext

            trf_worst = -float('inf')
            tdr_worst = -float('inf')
            tdf_worst = -float('inf')
            duty_err_worst = 0
            worst_env = ''
            duty_env = ''
            dut = await self.async_new_dut('output_driver', STDCellWrapper,
                                           dut_params)
            for env in all_corners['envs']:
                tbm_specs['sim_envs'] = [env]
                tbm_specs['sim_params']['vdd'] = all_corners['vddio'][env]
                tbm = cast(CombLogicTimingTB,
                           self.make_tbm(CombLogicTimingTB, tbm_specs))

                sim_results = await self.async_simulate_tbm_obj(
                    f'sim_final_{i}_{env}', dut, tbm, tb_params)
                tdr, tdf = CombLogicTimingTB.get_output_delay(
                    sim_results.data, tbm_specs, 'in', 'out', False)

                if tdr[0] > tdr_worst:
                    tdr_worst = tdr[0]
                if tdf[0] > tdf_worst:
                    tdf_worst = tdf[0]

                duty_err = tdr[0] - tdf[0]
                if np.abs(duty_err) > np.abs(duty_err_worst):
                    duty_err_worst = duty_err
                    duty_env = env

                tr, tf = CombLogicTimingTB.get_output_trf(
                    sim_results.data, tbm_specs, 'out')
                trf = max(np.max(tr), np.max(tf))

                if trf > trf_worst:
                    trf_worst = trf
                    tr_worst = tr[0]
                    tf_worst = tf[0]
                    worst_env = env

            self.logger.info('---')
            self.logger.info(f'Completed design iteration {i}.')
            self.logger.info(
                f'Worst trf was: {trf_worst} / rise: {tr_worst}, fall: {tf_worst}'
                + f'in corner {worst_env}')
            self.logger.info(
                f'Worst delay was: {max(tdr_worst, tdf_worst)} in corner {worst_env}'
            )
            self.logger.info(
                f'Worst duty cycle error was: {duty_err_worst} in corner {duty_env}'
            )
            self.logger.info('')

        return dict(dut_params=dut_params,
                    tdr=tdr_worst,
                    tdf=tdf_worst,
                    trf_worst=trf_worst,
                    duty_err=duty_err_worst)
示例#11
0
    async def _design_lvl_shift_inv_pun(self, pseg: int, nseg: int,
                                        inv_nseg: int, out_inv_m: int,
                                        fanout: float, pinfo: Any,
                                        tbm_specs: Dict[str, Any], has_rst,
                                        dual_output, vin,
                                        vout) -> Tuple[int, int]:
        """
        Given the NMOS pull down size, this function will design the PMOS pull up so that the delay
        mismatch is minimized.
        """
        inv_beta = get_tech_global_info('bag3_digital')['inv_beta']
        tb_params = self._get_full_tb_params()
        # Use a binary iterator to find the PMOS size
        load_seg = nseg + (pseg if has_rst else 0)
        inv_pseg_nom = int(
            np.round(inv_beta * load_seg / ((1 + inv_beta) * fanout)))
        inv_pseg_nom = 1 if inv_pseg_nom == 0 else inv_pseg_nom
        inv_nseg_nom = inv_nseg  # save the value of nseg coming into this function as nominal
        range_to_vary = min(inv_pseg_nom, inv_nseg)
        iterator = BinaryIterator(
            -range_to_vary + 1,
            1)  # upper limit is exclusive hence using 1 instead of 0
        # variation will be done such that the total P+N segments remains the same
        # This allows the input inverter sizing to be done once at the start

        # iterator = BinaryIterator(-inv_pseg_nom+1, 0)
        # iterator = BinaryIteratorInterval(get_tech_global_info('bag3_digital')['width_interval_list_p'],
        #                                   -inv_pseg_nom+1, 0)
        err_best = float('inf')
        inv_in_nseg, inv_in_pseg = self._size_input_inv_for_fanout(
            inv_pseg_nom, inv_nseg, pseg, nseg, fanout, has_rst)
        all_corners = get_tech_global_info(
            'bag3_digital')['signoff_envs']['all_corners']

        while iterator.has_next():
            pseg_off = iterator.get_next()
            inv_pseg = inv_pseg_nom + pseg_off
            inv_nseg = inv_nseg_nom - pseg_off
            dut_params = self._get_lvl_shift_params_dict(
                pinfo, pseg, nseg, inv_pseg, inv_nseg, inv_in_pseg,
                inv_in_nseg, out_inv_m, has_rst, dual_output)
            dut = await self.async_new_dut('lvshift', STDCellWrapper,
                                           dut_params)

            err_worst = -1 * float('Inf')
            for env in all_corners['envs']:
                tbm_specs['sim_envs'] = [env]
                tbm_specs['sim_params']['vdd_in'] = all_corners[vin][env]
                tbm_specs['sim_params']['vdd'] = all_corners[vout][env]
                tbm = cast(CombLogicTimingTB,
                           self.make_tbm(CombLogicTimingTB, tbm_specs))
                sim_results = await self.async_simulate_tbm_obj(
                    f'sim_inv_pseg_{inv_pseg}_{env}', dut, tbm, tb_params)
                tdr_cur, tdf_cur = CombLogicTimingTB.get_output_delay(
                    sim_results.data,
                    tbm.specs,
                    'in',
                    'out',
                    False,
                    in_pwr='vdd_in',
                    out_pwr='vdd')
                print("Balance rise/fall delays inv_pup Info: ", env, tdr_cur,
                      tdf_cur)
                # Error checking
                if math.isinf(np.max(tdr_cur)) or math.isinf(np.max(tdf_cur)):
                    raise ValueError("Got infinite delay!")
                if np.min(tdr_cur) < 0 or np.min(tdf_cur) < 0:
                    raise ValueError("Got negative delay.")

                err_cur = np.abs(tdr_cur[0] - tdf_cur[0])
                if err_cur > err_worst:
                    err_worst = err_cur
                    worst_env = env
                    tdr = tdr_cur[0]
                    tdf = tdf_cur[0]

            if tdr < tdf:
                iterator.down(tdr - tdf)
            else:
                iterator.up(tdr - tdf)

            err_abs = np.abs(tdr - tdf)
            if err_abs < err_best:
                err_best = err_abs
                iterator.save_info(pseg_off)

        pseg_off = iterator.get_last_save_info()
        pseg_off = 0 if pseg_off is None else pseg_off  # Should only hit this case if inv_pseg_nom = 1
        inv_pseg = inv_pseg_nom + pseg_off
        inv_nseg = inv_nseg_nom - pseg_off

        return inv_pseg, inv_nseg - 0 * pseg_off