def get_db(spec_file, intent, interp_method='spline', sim_env='tt'): # initialize transistor database from simulation data mos_db = MOSDBDiscrete([spec_file], interp_method=interp_method) # set process corners mos_db.env_list = [sim_env] # set layout parameters mos_db.set_dsn_params(intent=intent) return mos_db
def get_db(mos_type, dsn_specs): mos_specs = dsn_specs[mos_type] spec_file = mos_specs['spec_file'] interp_method = mos_specs.get('interp_method', 'spline') sim_env = mos_specs.get('sim_env', 'tt') layout_kwargs = mos_specs['layout_kwargs'] db = MOSDBDiscrete([spec_file], interp_method=interp_method) db.env_list = [sim_env] db.set_dsn_params(**layout_kwargs) return db
def design(amp_dsn_specs, amp_char_specs_fname, amp_char_specs_out_fname): nch_config = amp_dsn_specs['nch_config'] pch_config = amp_dsn_specs['pch_config'] print('create transistor database') nch_db = MOSDBDiscrete([nch_config]) pch_db = MOSDBDiscrete([pch_config]) nch_db.set_dsn_params(**amp_dsn_specs['nch']) pch_db.set_dsn_params(**amp_dsn_specs['pch']) result = design_amp(amp_dsn_specs, nch_db, pch_db) if result is None: raise ValueError('No solution.') pprint.pprint(result) # update characterization spec file amp_char_specs = read_yaml(amp_char_specs_fname) # update bias var_dict = amp_char_specs['measurements'][0]['testbenches']['ac'][ 'sim_vars'] for key in ('vtail', 'vindc', 'voutdc'): var_dict[key] = result[key] for key in ('vdd', 'cload'): var_dict[key] = amp_dsn_specs[key] # update segments seg_dict = amp_char_specs['layout_params']['seg_dict'] for key in ('in', 'load', 'tail'): seg_dict[key] = result['seg_' + key] with open_file(amp_char_specs_out_fname, 'w') as f: yaml.dump(amp_char_specs, f) return result
def design_only(): interp_method = 'spline' nch_conf_list = [ 'data/nch_w4_stack/specs.yaml', ] pch_conf_list = [ 'data/pch_w4_stack/specs.yaml', ] amp_specs_fname = 'specs_design/opamp_two_stage_1e8.yaml' print('create transistor database') nch_db = MOSDBDiscrete(nch_conf_list, interp_method=interp_method) pch_db = MOSDBDiscrete(pch_conf_list, interp_method=interp_method) top_specs = read_yaml(amp_specs_fname) design(top_specs, nch_db, pch_db)
def get_db(nch_dir, pch_dir, intent='standard', interp_method='spline', sim_env='tt'): env_list = [sim_env] nch_db = MOSDBDiscrete([nch_dir], interp_method=interp_method) pch_db = MOSDBDiscrete([pch_dir], interp_method=interp_method) nch_db.env_list = pch_db.env_list = env_list nch_db.set_dsn_params(intent=intent) pch_db.set_dsn_params(intent=intent) return nch_db, pch_db
def query(vgs=None, vds=None, vbs=0.0, vstar=None, env_list=None): """Get interpolation function and plot/query.""" spec_list = [spec_file] if env_list is None: env_list = [env_default] # initialize transistor database from simulation data nch_db = MOSDBDiscrete(spec_list, interp_method=interp_method) # set process corners nch_db.env_list = env_list # set layout parameters nch_db.set_dsn_params(intent=intent) # returns a dictionary of smal-signal parameters return nch_db.query(vbs=vbs, vds=vds, vgs=vgs, vstar=vstar)
def design_close_loop(prj, funity_min_first=None, max_iter=100): interp_method = 'spline' nch_conf_list = [ 'data/nch_w4_stack/specs.yaml', ] pch_conf_list = [ 'data/pch_w4_stack/specs.yaml', ] amp_specs_fname = 'specs_design/opamp_two_stage_1e8.yaml' ver_specs_fname = 'specs_verification/opamp_two_stage_1e8.yaml' iter_cnt = 0 f_unit_min_sim = -1 k_max = 2.0 k_min = 1.1 print('create transistor database') nch_db = MOSDBDiscrete(nch_conf_list, interp_method=interp_method) pch_db = MOSDBDiscrete(pch_conf_list, interp_method=interp_method) top_specs = read_yaml(amp_specs_fname) funity_dsn_targ = funity_targ = top_specs['dsn_specs']['f_unit'] sim, dsn_info = None, None summary = None while f_unit_min_sim < funity_targ and iter_cnt < max_iter: print('Iteration %d, f_unit_dsn_targ = %.4g' % (iter_cnt, funity_dsn_targ)) top_specs['dsn_specs']['f_unit'] = funity_dsn_targ if dsn_info is not None: top_specs['dsn_specs']['i1_min_size'] = dsn_info['i1_size'] if funity_min_first is not None and iter_cnt == 0: generate = False f_unit_min_dsn = funity_min_first else: generate = True dsn = design(top_specs, nch_db, pch_db) dsn_info = dsn.get_dsn_info() f_unit_min_dsn = min(dsn_info['f_unit']) ver_specs = dsn.get_specs_verification(top_specs) with open_file(ver_specs_fname, 'w') as f: yaml.dump(ver_specs, f) sim = DesignManager(prj, ver_specs_fname) sim.characterize_designs(generate=generate, measure=True, load_from_file=False) dsn_name = list(sim.get_dsn_name_iter())[0] summary = sim.get_result(dsn_name)['opamp_ac'] funity_list = summary['funity'] print('Iteration %d, result:' % iter_cnt) pprint.pprint(summary) f_unit_min_sim = min(funity_list) k = funity_targ / f_unit_min_sim k_real = max(k_min, min(k, k_max)) print('k = %.4g, k_real = %.4g' % (k, k_real)) funity_dsn_targ = f_unit_min_dsn * k_real iter_cnt += 1 print('close loop design done. Final result:') pprint.pprint(summary) return dsn_info
def plot_data(name='ibias', bounds=None, unit_val=None, unit_label=None): """Get interpolation function and plot/query.""" env_list = [env_default] vbs = 0.0 nvds = 41 nvgs = 81 spec_list = [spec_file] print('create transistor database') nch_db = MOSDBDiscrete(spec_list, interp_method=interp_method) nch_db.env_list = env_list nch_db.set_dsn_params(intent=intent) f = nch_db.get_function(name) vds_min, vds_max = f.get_input_range(1) vgs_min, vgs_max = f.get_input_range(2) if bounds is not None: if 'vgs' in bounds: v0, v1 = bounds['vgs'] if v0 is not None: vgs_min = max(vgs_min, v0) if v1 is not None: vgs_max = min(vgs_max, v1) if 'vds' in bounds: v0, v1 = bounds['vds'] if v0 is not None: vds_min = max(vds_min, v0) if v1 is not None: vds_max = min(vds_max, v1) # query values. vds_test = (vds_min + vds_max) / 2 vgs_test = (vgs_min + vgs_max) / 2 pprint.pprint(nch_db.query(vbs=vbs, vds=vds_test, vgs=vgs_test)) vbs_vec = [vbs] vds_vec = np.linspace(vds_min, vds_max, nvds, endpoint=True) vgs_vec = np.linspace(vgs_min, vgs_max, nvgs, endpoint=True) vbs_mat, vds_mat, vgs_mat = np.meshgrid(vbs_vec, vds_vec, vgs_vec, indexing='ij', copy=False) arg = np.stack((vbs_mat, vds_mat, vgs_mat), axis=-1) ans = f(arg) vds_mat = vds_mat.reshape((nvds, nvgs)) vgs_mat = vgs_mat.reshape((nvds, nvgs)) ans = ans.reshape((nvds, nvgs, len(env_list))) formatter = ticker.ScalarFormatter(useMathText=True) formatter.set_scientific(True) formatter.set_powerlimits((-2, 3)) if unit_label is not None: zlabel = '%s (%s)' % (name, unit_label) else: zlabel = name for idx, env in enumerate(env_list): fig = plt.figure(idx + 1) ax = fig.add_subplot(111, projection='3d') cur_val = ans[..., idx] if unit_val is not None: cur_val = cur_val / unit_val ax.plot_surface(vds_mat, vgs_mat, cur_val, rstride=1, cstride=1, linewidth=0, cmap=cm.cubehelix) ax.set_title('%s (corner=%s)' % (name, env)) ax.set_xlabel('Vds (V)') ax.set_ylabel('Vgs (V)') ax.set_zlabel(zlabel) ax.w_zaxis.set_major_formatter(formatter) plt.show()