示例#1
0
    def write_out_specs_yaml(self, summary_in: Dict[str, Any], yaml_fname: str) -> None:
        from bag.io.file import write_yaml

        dict_to_write = summary_in.copy()
        self.prep_lvshift_dict(dict_to_write, 'ctrl_lvshift')
        self.prep_lvshift_dict(dict_to_write, 'data_lvshift')
        self.prep_driver_dict(dict_to_write, 'driver')

        write_yaml(yaml_fname, dict_to_write)
        self.log(f'Wrote final layout specifications to {yaml_fname}.')
示例#2
0
def main() -> None:
    config_fname, output_dir = parse_options()

    output_dir.mkdir(parents=True, exist_ok=True)

    config = read_yaml(config_fname)

    netlist_map, inc_list, prim_files = get_info(config, output_dir)
    netlist_map.update(netlist_map_default)
    result = {
        'prim_files': prim_files,
        'inc_list': inc_list,
        'netlist_map': netlist_map,
    }

    write_yaml(output_dir / 'netlist_setup.yaml', result)
示例#3
0
    async def async_measure_performance(
            self, name: str, sim_dir: Path, sim_db: SimulationDB,
            dut: Optional[DesignInstance]) -> Dict[str, Any]:
        """A coroutine that performs measurement.

        The measurement is done like a FSM.  On each iteration, depending on the current
        state, it creates a new testbench (or reuse an existing one) and simulate it.
        It then post-process the simulation data to determine the next FSM state, or
        if the measurement is done.

        Parameters
        ----------
        name : str
            name of this measurement.
        sim_dir : Path
            simulation directory.
        sim_db : SimulationDB
            the simulation database object.
        dut : Optional[DesignInstance]
            the DUT to measure.

        Returns
        -------
        output : Dict[str, Any]
            the last dictionary returned by process_output().
        """
        specs = self.specs
        out_rise: bool = specs.get('out_rise', True)
        out_fall: bool = specs.get('out_fall', True)
        fake: bool = specs.get('fake', False)
        wait_cycles: int = specs.get('wait_cycles', 0)
        add_src_res: bool = specs.get('add_src_res', False)
        extra_loads: Optional[Sequence[Mapping[str, Any]]] = specs.get(
            'load_list', None)

        rs = 'r_src' if add_src_res else ''
        load_list: List[Mapping[str, Any]] = [
            dict(pin=p_, type='cap', value='c_load') for p_ in self._out_list
        ]
        if extra_loads:
            load_list.extend(extra_loads)
        pulse_list = [
            dict(pin=p_,
                 tper='2*t_bit',
                 tpw='t_bit',
                 trf='t_rf',
                 td='t_bit',
                 pos=True,
                 rs=rs) for p_ in self._in_list
        ]
        num_bits = 3 + 2 * wait_cycles

        tbm_specs, tb_params = setup_digital_tran(specs,
                                                  dut,
                                                  pulse_list=pulse_list,
                                                  load_list=load_list,
                                                  skip_src=True)
        save_set = set(
            chain(self._in_list, self._out_list, self._start_list,
                  self._stop_list))
        if add_src_res:
            save_set.update(
                (DigitalTranTB.get_r_src_pin(p_) for p_ in self._in_list))
        tbm_specs['save_outputs'] = list(save_set)

        tbm = cast(DigitalTranTB, sim_db.make_tbm(DigitalTranTB, tbm_specs))
        tbm.sim_params[
            't_sim'] = f't_rst+t_rst_rf/{tbm.trf_scale:.2f}+{num_bits}*t_bit'

        if fake:
            raise ValueError('fake mode is broken')
        else:
            results = await self._run_sim(name,
                                          sim_db,
                                          sim_dir,
                                          dut,
                                          tbm,
                                          tb_params,
                                          wait_cycles,
                                          out_rise,
                                          out_fall,
                                          is_mc=False)

        self.log(f'Measurement {name} done, recording results.')

        mc_params = specs.get('mc_params', {})
        if mc_params:
            mc_name = f'{name}_mc'
            self.log('Starting Monte Carlo simulation')
            mc_tbm_specs = tbm_specs.copy()
            mc_tbm_specs['sim_envs'] = [specs.get('mc_corner', 'tt_25')]
            mc_tbm_specs['monte_carlo_params'] = mc_params
            mc_tbm = cast(DigitalTranTB,
                          sim_db.make_tbm(DigitalTranTB, mc_tbm_specs))
            mc_tbm.sim_params[
                't_sim'] = f't_rst+t_rst_rf/{mc_tbm.trf_scale:.2f}+{num_bits}*t_bit'

            mc_results = await self._run_sim(mc_name,
                                             sim_db,
                                             sim_dir,
                                             dut,
                                             mc_tbm,
                                             tb_params,
                                             wait_cycles,
                                             out_rise,
                                             out_fall,
                                             is_mc=True)
            results = dict(
                tran=results,
                mc=mc_results,
            )

        write_yaml(sim_dir / f'{name}.yaml', results)
        return results
    async def async_design(self, **kwargs: Any) -> Mapping[str, Any]:
        """This function extracts design parameters and calls sub-hierarchy design functions.
        It passes parameters between the results of each sub-hierarchy design to accomplish
        logical-effort based design. If layout parameters are passed in through the design
        specs, they will be returned instead of running the design procedures.

        Passed in kwargs are the same as self.dsn_specs.

        Parameters
        ----------
        kwargs: Any
            data_lv_specs: Mapping[str, Any]
                Data Level Shifter design parameters
            se_en_specs: Mapping[str, Any]
                Single Ended to Differential design parameters
            ctrl_lv_specs: Mapping[str, Any]
                Control / Enable Level Shifters design parameters
            por_lv_specs: Mapping[str, Any]
                POR Level Shifter design parameters
            c_load: float
                Target load capacitance on odat
            c_odat_async: float
                Target load capacitance on odat_async
            c_por_vccl_tx: float
                Target load capacitance from the TX on por_vccl
            fanout_odat_async: float
                Target fanout for odat_async output inverter
            w_n_inv: Union[int, float]
                NMOS width for POR Level Shifter input buffer
            w_p_inv: Union[int, float]
                PMOS width for POR Level Shifter input buffer
            yaml_file: str
                Output file location to write designed generator parameters
            data_lv_results: Optional[Mapping[str, Any]]
                If provided, return these generator parameters instead of running the design
                procedures
            se_en_results: Optional[Mapping[str, Any]]
                If provided, return these generator parameters instead of running the design
                procedures
            ctrl_lv_results: Optional[Mapping[str, Any]]
                If provided, return these generator parameters instead of running the design
                procedures
            por_lv_results: Optional[Mapping[str, Any]]
                If provided, return these generator parameters instead of running the design
                procedures

            Below are global specs shared and passed to each of the designers
            w_min: Union[int, float]
                Minimum width
            w_res: Union[int, float]
                Width resolution
            c_unit_n: float
                Unit NMOS transistor capacitance for w=1, seg=1
            c_unit_p: float
                Unit PMOS transistor capacitance for w=1, seg=1
            dig_tran_specs: Mapping[str, Any]
                DigitalTranTB testbench specs
            search_params: Mapping[str, Any]
                Parameters used for capacitor size binary search
            search_step: int
                Binary search step size
            max_iter: int
                Maximum allowed iterations to search for converge in binary search
            buf_config: Mapping[str, Any]
                Buffer parameters, used in DigitalTranTB and capacitor size search
            sign_off_envs: Sequence[str]
                Corners used for sign off
            sup_values: Mapping[str, Any]
                Per-corner supply values
            tile_name: str
                Tile name for layout.
            tile_specs: Mapping[str, Any]
                Tile specifications for layout.
            ridx_n: int
                NMOS transistor row
            ridx_p: int
                PMOS transistor Row

        Returns
        -------
        ans: Mapping[str, Any]
            Design summary
        """
        specs = self.dsn_specs
        yaml_file: str = specs.get('yaml_file', '')

        data_lv_results = await self.design_data_lv()
        se_en_results = await self.design_se_en(data_lv_results['c_in'])

        c_en = max(se_en_results['c_en_se'], se_en_results['c_en_match'])
        ctrl_lv_results = await self.design_ctrl_lv(c_en)

        c_por_vccl = max(ctrl_lv_results['c_rst_out'],
                         ctrl_lv_results['c_rst_casc']) * 2
        c_por_vccl += self.dsn_specs['c_por_vccl_tx']

        por_lv_results = await self.design_por_lv(c_por_vccl)

        c_por_core = max(data_lv_results['c_rst_out'],
                         data_lv_results['c_rst_casc']) * 2
        c_por_core += por_lv_results['c_in']
        buf_por_lv_params = self.get_buf_params(c_por_core)

        inv_params = self.get_inv_params(self.dsn_specs['c_odat_async'],
                                         self.dsn_specs['fanout_odat_async'])

        se_params = se_en_results['se_params']
        match_params = se_en_results['match_params']
        data_lv_params = data_lv_results['lv_params']
        por_lv_params = por_lv_results['lv_params']

        for table in [se_params, match_params, data_lv_params, por_lv_params]:
            table.pop('pinfo', None)
            table.pop('ridx_n', None)
            table.pop('ridx_p', None)

        rx_params = dict(
            se_params=se_params,
            match_params=match_params,
            inv_params=inv_params,
            data_lv_params=data_lv_params,
            ctrl_lv_params=ctrl_lv_results['dut_params']['lv_params'],
            por_lv_params=por_lv_params,
            buf_ctrl_lv_params=ctrl_lv_results['dut_params']['in_buf_params'],
            buf_por_lv_params=buf_por_lv_params,
        )
        ans = dict(rx_params=rx_params, )

        if yaml_file:
            write_yaml(self.work_dir / yaml_file, ans)

        return ans
示例#5
0
    async def async_measure_performance(self, name: str, sim_dir: Path, sim_db: SimulationDB,
                                        dut: Optional[DesignInstance]) -> Dict[str, Any]:
        """
        A coroutine that performs measurement.
        This will...
        1. Acquire every sweep point/configuration (get_swp_list)
        2. Run simulation for each sweep point (_run_sim)
        3. Aggregate results and return (aggregate_results)

        Parameters
        ----------
        name : str
            name of measurement
        sim_dir : Path
            simulation directory
        sim_db : SimulationDB
            the simulation database object
        dut : Optional[DesignInstance]
            the DUT to measure

        Returns
        -------
        results dictionary

        """
        assert len(self._sim_envs) > 0
        self.tbm_dict: Dict[str, TestbenchManager] = {k: None for k in self.tbm_order}

        res = {}

        for idx, tbm_name in enumerate(self.tbm_order):
            if not self._run_tbm[tbm_name]:
                continue

            tbm = self.add_tbm(tbm_name)
            sim_results = await sim_db.async_simulate_tbm_obj(tbm_name, sim_dir / tbm_name, dut, tbm, tb_params={})
            data = sim_results.data

            ss_fname = str(sim_dir / 'ss_params.hdf5')

            if tbm_name == 'ibias':
                tbm: MOSIdTB
                vgs_range = tbm.get_vgs_range(data)
                if self._run_tbm['sp']:
                    self.specs['tbm_specs']['sp']['vgs_range'] = vgs_range
                if self._run_tbm['noise']:
                    self.specs['tbm_specs']['noise']['vgs_range'] = vgs_range
                self.commit()
                res['vgs_range'] = vgs_range

            elif tbm_name == 'sp':
                tbm: MOSSPTB
                ss_params = tbm.get_ss_params(data)
                # save SS parameters
                save_sim_results(ss_params, ss_fname)

                res['ss_file'] = ss_fname

            elif tbm_name == 'noise':
                # TODO: needs to be verified
                tbm: MOSNoiseTB
                temp = self.specs['noise_temp_kelvin']
                fstart = self.specs['noise_integ_fstart']
                fstop = self.specs['noise_integ_fstop']
                scale = self.specs.get('noise_integ_scale', 1.0)

                ss_params = load_sim_file(ss_fname)
                ss_params = tbm.get_integrated_noise(data, ss_params, temp, fstart, fstop, scale=scale)
                save_sim_results(ss_params, ss_fname)

                res['ss_file'] = ss_fname

            else:
                raise ValueError(f"Unknown tbm name {tbm_name}")

        write_yaml(sim_dir / f'{name}.yaml', res)

        return res
    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