def process_output(self, cur_info: MeasInfo, sim_results: Union[SimResults, MeasureResult]
                       ) -> Tuple[bool, MeasInfo]:
        state = cur_info.state
        if state == 'init':
            tbm = self._tbm_info[0]
            in_pin: str = self.specs['in_pin']

            sim_data = sim_results.data
            t0 = tbm.get_t_rst_end(sim_data)
            buf_mid, buf_out = get_in_buffer_pin_names(in_pin)
            tr = tbm.calc_delay(sim_data, buf_mid, buf_out, EdgeType.FALL,
                                EdgeType.RISE, t_start=t0)
            tf = tbm.calc_delay(sim_data, buf_mid, buf_out, EdgeType.RISE,
                                EdgeType.FALL, t_start=t0)
            return False, MeasInfo('cap_rise', dict(tr_ref=tr.item(), tf_ref=tf.item()))
        elif state == 'cap_rise':
            data = sim_results.data['c_load']
            new_result = cur_info.prev_results.copy()
            new_result['cap_rise'] = data['value']
            new_result['tr_adj'] = data['td_adj']
            return False, MeasInfo('cap_fall', new_result)
        elif state == 'cap_fall':
            data = sim_results.data['c_load']
            new_result = cur_info.prev_results.copy()
            new_result['cap_fall'] = data['value']
            new_result['tf_adj'] = data['td_adj']
            return True, MeasInfo('done', new_result)
        else:
            raise ValueError(f'Unknown state: {state}')
Esempio n. 2
0
    def initialize(self, sim_db: SimulationDB,
                   dut: DesignInstance) -> Tuple[bool, MeasInfo]:
        specs = self.specs
        in_pin: str = specs['in_pin']
        out_pin: str = specs['out_pin']
        fake: str = specs.get('fake', False)

        if fake:
            return True, MeasInfo(
                'done', dict(cap=100.0e-15, tr=20.0e-12, tf=20.0e-12))

        load_list = [dict(pin=out_pin, type='cap', value='c_load')]
        wrapper_params = get_digital_wrapper_params(specs, dut, [in_pin])
        mm_specs = {
            k: specs[k]
            for k in
            ['in_pin', 'out_pin', 'max_trf', 'search_params', 'tbm_specs']
        }
        mm_specs['adj_name'] = 'c_load'
        mm_specs['adj_sign'] = True
        mm_specs['use_dut'] = True
        mm_specs['wrapper_params'] = wrapper_params
        mm_specs['load_list'] = load_list
        self._mm = sim_db.make_mm(MaxRiseFallTime, mm_specs)

        return False, MeasInfo('max_trf', {})
Esempio n. 3
0
 def process_output(
     self, cur_info: MeasInfo,
     sim_results: Union[SimResults,
                        MeasureResult]) -> Tuple[bool, MeasInfo]:
     delay = sim_results.data['t_delay']['value']
     t_bit = self.specs['tbm_specs']['sim_params']['t_bit']
     delay = abs(delay - t_bit / 2)
     if cur_info.state == 'up_rising':
         return False, MeasInfo("down_falling", dict(up_delay=delay))
     else:
         dct = cur_info.prev_results
         dct['down_delay'] = delay
         return True, MeasInfo("", dct)
Esempio n. 4
0
    def process_output(
        self, cur_info: MeasInfo,
        sim_results: Union[SimResults,
                           MeasureResult]) -> Tuple[bool, MeasInfo]:
        tbm: DigitalTranTB = self._tbm_info[0]

        sim_params = tbm.sim_params
        t_bit = sim_params['t_bit']

        data = cast(SimResults, sim_results).data
        t_rf = tbm.get_param_value('t_rf',
                                   data) / (tbm.thres_hi - tbm.thres_lo)

        t_launch = tbm.get_t_rst_end(data) + 9 * t_bit
        t0_launch = t_launch - t_rf / 2
        t_meas = t_launch + t_bit
        t0_meas = t0_launch + t_bit

        td_launch = tbm.calc_cross(
            data, 'ckout', EdgeType.RISE, t_start=t0_launch) - t_launch
        td_meas = tbm.calc_cross(data, 'ckout', EdgeType.FALL,
                                 t_start=t0_meas) - t_meas
        tr_launch = tbm.calc_trf(data, 'ckout', True, t_start=t0_launch)
        tf_meas = tbm.calc_trf(data, 'ckout', False, t_start=t0_meas)

        if td_launch.shape[0] == 1:
            td_launch = td_launch[0, ...]
            td_meas = td_meas[0, ...]
            tr_launch = tr_launch[0, ...]
            tf_meas = tf_meas[0, ...]
        result = _get_result_table(td_launch, td_meas, tr_launch, tf_meas)
        self.log(f'result:\n{pprint.pformat(result, width=100)}')

        return True, MeasInfo('done', result)
Esempio n. 5
0
 def process_output(
     self, cur_info: MeasInfo,
     sim_results: Union[SimResults,
                        MeasureResult]) -> Tuple[bool, MeasInfo]:
     data = cast(MeasureResult, sim_results).data['c_load']
     new_result = dict(cap=data['value'], tr=data['tr'], tf=data['tf'])
     return True, MeasInfo('done', new_result)
Esempio n. 6
0
    def initialize(self, sim_db: SimulationDB,
                   dut: DesignInstance) -> Tuple[bool, MeasInfo]:
        specs = self.specs
        vdd = specs['vdd']
        v_offset_map = specs['v_offset_map']

        gate_bias = self.default_gate_bias.copy()
        if 'gate_bias' in specs:
            gate_bias.update(specs['gate_bias'])

        specs['stack_pu'] = dut.sch_master.params['stack_p']
        specs['stack_pd'] = dut.sch_master.params['stack_n']
        self._dut = dut

        mos_mapping = specs['mos_mapping'][
            'lay' if specs['extract'] else 'sch']

        # Find all transistors that match the passed in transistor names
        # The passed in transistor name can match multiple "transistors" in the netlist
        # in cases like seg > 1 or stack > 1
        # TODO: allow for more complex name matching (e.g., via regex)
        for mos, term in mos_mapping.items():
            voff_list = [
                v for k, v in v_offset_map.items()
                if term in k and k.endswith('_d')
            ]
            if len(voff_list) == 0:
                raise ValueError(f"No matching transistor found for {term}")
            self._mos_mapping[mos] = voff_list

        for k, v in gate_bias.items():
            if v == 'full':
                gate_bias[k] = vdd if k == 'pd' else 0
            else:
                gate_bias = self._eval_expr(v)

        sup_values = dict(VDD=vdd,
                          pden=gate_bias['pd'],
                          puenb=gate_bias['pu'],
                          out=vdd / 2)

        tbm_specs = dict(**specs['tbm_specs'])
        tbm_specs['sweep_var'] = 'v_out'
        tbm_specs['sweep_options'] = dict(type='LINEAR')
        for k in ['pwr_domain', 'sim_params', 'pin_values']:
            if k not in tbm_specs:
                tbm_specs[k] = {}
        tbm_specs['dut_pins'] = list(dut.sch_master.pins.keys())
        tbm_specs['load_list'] = []
        tbm_specs['sup_values'] = sup_values

        # Set all internal DC sources to 0 (since these are just used for current measurements)
        tbm_specs['sim_params'].update({k: 0 for k in v_offset_map.values()})

        tbm = cast(DCTB, sim_db.make_tbm(DCTB, tbm_specs))
        self._tbm_info = tbm, {}

        return False, MeasInfo('pd', {})
Esempio n. 7
0
    def initialize(self, sim_db: SimulationDB,
                   dut: DesignInstance) -> Tuple[bool, MeasInfo]:
        specs = self.specs
        fake: bool = specs.get('fake', False)

        load_list = [dict(pin='ckout', type='cap', value='c_load')]
        pulse_list = [
            dict(pin='launch',
                 tper='2*t_bit',
                 tpw='t_bit',
                 trf='t_rf',
                 td='t_bit',
                 pos=True),
            dict(pin='measure',
                 tper='2*t_bit',
                 tpw='t_bit',
                 trf='t_rf',
                 td='2*t_bit',
                 pos=True)
        ]
        pin_values = dict(dcc_byp=0, clk_dcd=0)
        save_outputs = ['launch', 'measure', 'ckout']
        tbm_specs, tb_params = setup_digital_tran(specs,
                                                  dut,
                                                  pulse_list=pulse_list,
                                                  load_list=load_list,
                                                  pin_values=pin_values,
                                                  save_outputs=save_outputs)
        tbm = cast(DigitalTranTB, sim_db.make_tbm(DigitalTranTB, tbm_specs))

        if fake:
            td = np.full(tbm.sweep_shape[1:], 50.0e-12)
            trf = np.full(td.shape, 20.0e-12)
            result = _get_result_table(td, td, trf, trf)
            return True, MeasInfo('done', result)

        tbm.sim_params['t_sim'] = 't_rst+t_rst_rf+11*t_bit'
        self._tbm_info = tbm, tb_params
        return False, MeasInfo('sim', {})
    def process_output(self, cur_info: MeasInfo, sim_results: Union[SimResults, MeasureResult]
                       ) -> Tuple[bool, MeasInfo]:
        cur_state = cur_info.state
        if cur_state.startswith('bin'):
            info_table = self.process_output_helper(cur_info, sim_results, self._remaining)

            any_next = False
            for key, ((low, high), result, accept) in info_table.items():
                search = self._table[key][0]
                search.set_interval(low, high=high)
                any_next = any_next or search.has_next()
                if accept:
                    self._result[key] = result

            if any_next:
                return False, MeasInfo(f'bin_{int(cur_state[4:]) + 1}', self._result)
            else:
                return True, MeasInfo('done', self._result)
        else:
            self._result, done = self.process_init(cur_info, sim_results)
            if done:
                return True, MeasInfo('done', self._result)
            else:
                return False, MeasInfo('bin_0', self._result)
    def initialize(self, sim_db: SimulationDB, dut: DesignInstance) -> Tuple[bool, MeasInfo]:
        tmp = self.init_search(sim_db, dut)
        tbm, tb_params, intv_params, intv_defaults, has_init, use_dut = tmp
        if tbm.swp_info:
            self.error('Parameter sweep is not supported.')
        if tbm.num_sim_envs != 1:
            self.error('Corner sweep is not supported.')

        self._table.clear()
        self._remaining.clear()
        self._result.clear()
        self._use_dut = use_dut
        any_next = False
        for adj_name, search_params in intv_params.items():
            low: float = _get('low', search_params, intv_defaults)
            high: Optional[float] = _get('high', search_params, intv_defaults)
            step: float = _get('step', search_params, intv_defaults)
            tol: float = _get('tol', search_params, intv_defaults)
            max_err: float = _get('max_err', search_params, intv_defaults)
            overhead_factor: float = _get('overhead_factor', search_params, intv_defaults)
            guess: Optional[Union[float, Tuple[float, float]]] = _get(
                'guess', search_params, intv_defaults, None)
            single_first: bool = _get('single_first', search_params, intv_defaults, False)

            tmp = FloatIntervalSearch(low, high, overhead_factor, tol=tol, guess=guess,
                                      search_step=step, max_err=max_err)
            any_next = any_next or tmp.has_next()
            self._table[adj_name] = (tmp, single_first)
            self._result[adj_name] = self.get_init_result(adj_name)
            self._remaining.add(adj_name)

        if not any_next:
            return True, MeasInfo('done', self._result)

        self._tbm_info = (tbm, tb_params)
        return False, MeasInfo('init' if has_init else 'bin_0', {})
Esempio n. 10
0
    def process_output(
        self, cur_info: MeasInfo,
        sim_results: Union[SimResults,
                           MeasureResult]) -> Tuple[bool, MeasInfo]:
        specs = self.specs
        state = cur_info.state
        data = cast(SimResults, sim_results).data
        mos_mapping = self._mos_mapping[state]
        stack = specs[f'stack_{state}']

        # Compute the total current by the following:
        # Find the drain current of all the unit transistors (the number of these transistors is seg * stack)
        # Add all these currents together, then divide by the number of stacks (to approximate
        # the sum of currents for each "finger"/parallel path of stacked transistors).
        # This calculation assumes that the junction leakage is negligible compared to the measured current.
        total_current = np.zeros(data.data_shape)
        for sig in data.signals:
            if any(filter(lambda x: x in sig, mos_mapping)):
                total_current += data._cur_ana[sig]
        total_current /= stack

        # Calculate resistance
        swp_options = self._tbm_info[0].specs['sweep_options']
        if swp_options['num'] == 1:
            res = swp_options['start'] / total_current[:, 0]
        else:
            res = (swp_options['stop'] - swp_options['start']) / (
                total_current[:, 1] - total_current[:, 0])
        res = np.abs(res)

        result = cur_info.prev_results.copy()
        if state == 'pd':
            result['sim_envs'] = data.sim_envs
        result[f'res_{state}'] = res

        next_state = 'done' if state == 'pu' else 'pu'
        return next_state == 'done', MeasInfo(next_state, result)
    def initialize(self, sim_db: SimulationDB, dut: DesignInstance) -> Tuple[bool, MeasInfo]:
        specs = self.specs
        in_pin: str = specs['in_pin']
        search_params = specs['search_params']
        buf_params: Optional[Mapping[str, Any]] = specs.get('buf_params', None)
        buf_config: Optional[Mapping[str, Any]] = specs.get('buf_config', None)
        fake: bool = specs.get('fake', False)
        load_list: Sequence[Mapping[str, Any]] = specs.get('load_list', [])

        if fake:
            return True, MeasInfo('done', dict(cap_rise=1.0e-12, cap_fall=1.0e-12,
                                               tr_ref=50.0e-12, tf_ref=50.0e-12,
                                               tr_adj=50.0e-12, tf_adj=50.0e-12))

        if buf_params is None and buf_config is None:
            raise ValueError('one of buf_params or buf_config must be specified.')

        if buf_params is None:
            lch: int = buf_config['lch']
            w_p: int = buf_config['w_p']
            w_n: int = buf_config['w_n']
            th_p: str = buf_config['th_p']
            th_n: str = buf_config['th_n']
            cinv_unit: float = buf_config['cinv_unit']
            cin_guess: float = buf_config['cin_guess']
            fanout_in: float = buf_config['fanout_in']
            fanout_buf: float = buf_config.get('fanout_buf', 4)

            seg1 = int(round(max(cin_guess / fanout_in / cinv_unit, 1.0)))
            seg0 = int(round(max(seg1 / fanout_buf, 1.0)))
            buf_params = dict(
                export_pins=True,
                inv_params=[
                    dict(lch=lch, w_p=w_p, w_n=w_n, th_p=th_p, th_n=th_n, seg=seg0),
                    dict(lch=lch, w_p=w_p, w_n=w_n, th_p=th_p, th_n=th_n, seg=seg1),
                ],
            )
            specs['buf_params'] = buf_params
            self.log(f'buf_params:\n{pprint.pformat(buf_params, width=100)}')
            search_params = dict(**search_params)
            search_params['guess'] = (cin_guess * 0.8, cin_guess * 1.2)

        # create testbench for measuring reference delay
        pulse_list = [dict(pin=in_pin, tper='2*t_bit', tpw='t_bit', trf='t_rf',
                           td='t_bit', pos=True)]
        self._wrapper_params = get_digital_wrapper_params(specs, dut, [in_pin])
        tbm_specs, tb_params = setup_digital_tran(specs, dut, wrapper_params=self._wrapper_params,
                                                  pulse_list=pulse_list, load_list=load_list)
        buf_mid, buf_out = get_in_buffer_pin_names(in_pin)
        tbm_specs['save_outputs'] = [buf_mid, buf_out]
        # remove input pin from reset list
        reset_list: Sequence[Tuple[str, bool]] = tbm_specs.get('reset_list', [])
        new_reset_list = [ele for ele in reset_list if ele[0] != in_pin]
        tbm_specs['reset_list'] = new_reset_list

        tbm = cast(DigitalTranTB, sim_db.make_tbm(DigitalTranTB, tbm_specs))
        if tbm.swp_info:
            self.error('Parameter sweep is not supported.')
        if tbm.num_sim_envs != 1:
            self.error('Corner sweep is not supported.')
        tbm.sim_params['t_sim'] = f'{tbm.t_rst_end_expr}+3*t_bit'

        self._tbm_info = tbm, tb_params

        # create DelayMatch
        mm_tbm_specs = {k: v for k, v in tbm.specs.items()
                        if k not in {'pwr_domain', 'sup_values', 'dut_pins', 'pin_values',
                                     'pulse_load', 'reset_list', 'load_list', 'diff_list'}}
        gnd_name, pwr_name = DigitalTranTB.get_pin_supplies(in_pin, tbm_specs['pwr_domain'])
        sup_values: Mapping[str, Union[float, Mapping[str, float]]] = tbm_specs['sup_values']
        gnd_val = sup_values[gnd_name]
        pwr_val = sup_values[pwr_name]
        pwr_tup = ('VSS', 'VDD')
        mm_tbm_specs['pwr_domain'] = {}
        mm_tbm_specs['sup_values'] = dict(VSS=gnd_val, VDD=pwr_val)
        mm_tbm_specs['pin_values'] = {}

        thres_lo: float = mm_tbm_specs['thres_lo']
        thres_hi: float = mm_tbm_specs['thres_hi']
        t_start_expr = f't_rst+t_bit+(t_rst_rf-t_rf/2)/{thres_hi - thres_lo:.2f}'
        mm_specs = dict(
            adj_name='c_load',
            adj_sign=True,
            adj_params=dict(in_name='mid', out_name='out', t_start=t_start_expr),
            ref_delay=0,
            use_dut=False,
            search_params=search_params,
            tbm_specs=mm_tbm_specs,
            wrapper_params=dict(
                lib='bag3_digital',
                cell='inv_chain',
                params=buf_params,
                pins=['in', 'out', 'mid', 'VDD', 'VSS'],
                pwr_domain={'in': pwr_tup, 'out': pwr_tup, 'mid': pwr_tup},
            ),
            pulse_list=[dict(pin='in', tper='2*t_bit', tpw='t_bit', trf='t_rf',
                             td='t_bit', pos=True)],
            load_list=[dict(pin='out', type='cap', value='c_load')],
        )
        mm_specs.update(search_params)
        self._mm = sim_db.make_mm(DelayMatch, mm_specs)

        return False, MeasInfo('init', {})
Esempio n. 12
0
 def initialize(self, sim_db: SimulationDB,
                dut: DesignInstance) -> Tuple[bool, MeasInfo]:
     return False, MeasInfo("up_rising", {})