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}')
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', {})
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)
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)
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)
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', {})
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', {})
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', {})
def initialize(self, sim_db: SimulationDB, dut: DesignInstance) -> Tuple[bool, MeasInfo]: return False, MeasInfo("up_rising", {})