def simulate(prj, temp_lib, impl_lib, tb_name, cell_name, sim_params): # generate tb schematic print("Generating testbench ...") dsn = prj.create_design_module(temp_lib, tb_name) dsn.design(impl_lib=impl_lib, cell_name=cell_name) dsn.implement_design(impl_lib, top_cell_name=tb_name) # configure tb tb = prj.configure_testbench(tb_lib=impl_lib, tb_cell=tb_name) tb.set_parameter('Rsense', sim_params['Rsense']) tb.update_testbench() # rum simulation tb.run_simulation() print(tb.save_dir) # Get results results = load_sim_results(tb.save_dir) print(results) print('Gain=', results['dc_gain']) print('BW=', results['band_width'] / (10**6), 'MHz') print('GBW=', results['unity_gain'] / (10**9), 'GHz') print('PM=', results['phase_margin']) gain = results['amp_gain'] phase = results['amp_phase'] freq = results['freq'] return gain, phase, freq
def simulate_Opamp(prj, temp_lib, impl_lib, sch_params): # generate tb schematic dsn = prj.create_design_module(temp_lib, 'opamp_folded_cascode') dsn.design(**sch_params) dsn.implement_design(impl_lib, top_cell_name='opamp_folded_cascode') dsn = prj.create_design_module(temp_lib, 'tb_opamp_folded_cascode') dsn.design(impl_lib=impl_lib, cell_name='opamp_folded_cascode') dsn.implement_design(impl_lib, top_cell_name='tb_opamp_folded_cascode') # configure tb tb = prj.configure_testbench(tb_lib=impl_lib, tb_cell='tb_opamp_folded_cascode') tb.set_parameter('cm_cap', sch_params['comp_cap']) tb.update_testbench() # rum simulation tb.run_simulation() # Get DC results results = load_sim_results(tb.save_dir) I_in = results['I_branch1'] I_branch = results['I_branch2'] Vgs_sf = results['Vgs_sf'] res_dir = tb.save_dir return I_in, I_branch, Vgs_sf, res_dir
def simulate_RC(prj, temp_lib, impl_lib, tb_name, cell_name, sim_params): # generate tb schematic print("Generating testbench ...") dsn = prj.create_design_module(temp_lib, tb_name) dsn.design(impl_lib=impl_lib, cell_name=cell_name) dsn.implement_design(impl_lib, top_cell_name=tb_name) # configure tb tb = prj.configure_testbench(tb_lib=impl_lib, tb_cell=tb_name) scale_ratio = sim_params['scale_ratio'] print(" Running simulation... scale ratio is", scale_ratio) print(' (R = R /', scale_ratio, ' C = C *', scale_ratio, ')') tb.set_parameter('R1A', sim_params['rc']['R']['1A'] / scale_ratio) tb.set_parameter('R2A', sim_params['rc']['R']['2A'] / scale_ratio) tb.set_parameter('R3A', sim_params['rc']['R']['3A'] / scale_ratio) tb.set_parameter('R1B', sim_params['rc']['R']['1B'] / scale_ratio) tb.set_parameter('R2B', sim_params['rc']['R']['2B'] / scale_ratio) tb.set_parameter('R3B', sim_params['rc']['R']['3B'] / scale_ratio) tb.set_parameter('C1A', sim_params['rc']['C']['1A'] * scale_ratio) tb.set_parameter('C1B', sim_params['rc']['C']['1B'] * scale_ratio) tb.set_parameter('C2A', sim_params['rc']['C']['2A'] * scale_ratio) tb.set_parameter('C2B', sim_params['rc']['C']['2B'] * scale_ratio) # not completed yet... tb.update_testbench() # rum simulation tb.run_simulation() print(tb.save_dir) results = load_sim_results(tb.save_dir) # Get results gain = results['vodm_dB'] freq = results['freq'] int_noise = results['int_noise'] R2_noise = results['R2_noise'] NM0_noise = results['NM0_noise'] phase = results['vodm_phase'] # plt.figure() # plt.subplot(2, 1, 1) # plt.semilogx(freq, gain) # plt.subplot(2, 1, 2) # plt.semilogx(freq, phase) print(" NM0_noise is ", NM0_noise, " R2_noise is", R2_noise) flag = True if R2_noise < NM0_noise: flag = False return gain, freq, int_noise, flag
def simulate(prj, specs, dsn_name): view_name = specs['view_name'] sim_envs = specs['sim_envs'] dsn_specs = specs[dsn_name] data_dir = dsn_specs['data_dir'] impl_lib = dsn_specs['impl_lib'] gen_cell = dsn_specs['gen_cell'] testbenches = dsn_specs['testbenches'] results_dict = {} for name, info in testbenches.items(): tb_params = info['tb_params'] tb_gen_cell = '%s_%s' % (gen_cell, name) # setup testbench ADEXL state print('setting up %s' % tb_gen_cell) tb = prj.configure_testbench(impl_lib, tb_gen_cell) print('tb object created!') # set testbench parameters values for key, val in tb_params.items(): tb.set_parameter(key, val) print('parameters are set!') # set config view, i.e. schematic vs extracted tb.set_simulation_view(impl_lib, gen_cell, view_name) print(f'changed the config view to {view_name}!') # set process corners tb.set_simulation_environments(sim_envs) print(f'set tb environment to {sim_envs}') # commit changes to ADEXL state back to database tb.update_testbench() print('updated changes to ADEXL') # start simulation print('running simulation') tb.run_simulation() # import simulation results to Python print('simulation done, load results') results = load_sim_results(tb.save_dir) # save simulation data as HDF5 format save_sim_results(results, os.path.join(data_dir, '%s.hdf5' % tb_gen_cell)) results_dict[name] = results print('all simulation done') return results_dict
def simulate(prj, temp_lib, impl_lib, tb_name, cell_name, sim_params, show_plot=True): # generate tb schematic print("Generating testbench ...") dsn = prj.create_design_module(temp_lib, tb_name) dsn.design(impl_lib=impl_lib, cell_name=cell_name) dsn.implement_design(impl_lib, top_cell_name=tb_name) # configure tb tb = prj.configure_testbench(tb_lib=impl_lib, tb_cell=tb_name) tb.set_parameter('supply', sim_params[0]) tb.set_parameter('in_bias', sim_params[1]) tb.set_parameter('nf', sim_params[2]) tb.update_testbench() # rum simulation tb.run_simulation() print(tb.save_dir) results = load_sim_results(tb.save_dir) out_dc = results['out_dc'] freq = results['freq'] out_ac_amp = results['out_ac_amp'] out_ac_phase = results['out_ac_phase'] if show_plot: print(f"Output dc is {out_dc}") plt.figure() plt.subplot(2, 1, 1) plt.semilogx(freq, out_ac_amp) plt.subplot(2, 1, 2) plt.semilogx(freq, out_ac_phase) plt.show(block=False) return out_dc, out_ac_amp, out_ac_phase
def simulate(prj, temp_lib, impl_lib, tb_name, cell_name, sim_params, show_plot=True): # generate tb schematic print("Generating testbench ...") dsn = prj.create_design_module(temp_lib, tb_name) dsn.design(impl_lib=impl_lib, cell_name=cell_name) dsn.implement_design(impl_lib, top_cell_name=tb_name) # configure tb tb = prj.configure_testbench(tb_lib=impl_lib, tb_cell=tb_name) tb.set_parameter('vdd', sim_params[0]) tb.update_testbench() # rum simulation tb.run_simulation() print(tb.save_dir) results = load_sim_results(tb.save_dir) print(results) gain = results['gain'] freq = results['freq'] return gain, freq
def simulate(self): """ Runs a batch of simulations on the generated TB's. All parameters for simulation are set within the spec file """ print('Running Simulation') impl_lib = self.specs['impl_lib'] impl_cell = self.specs['impl_cell'] results_dict = {} for tb_impl_cell, info in self.specs['tb_params'].items(): tb_params = info['tb_sim_params'] view_name = info['view_name'] sim_envs = info['sim_envs'] data_dir = info['data_dir'] # setup testbench ADEXL state print('setting up %s' % tb_impl_cell) tb = self.prj.configure_testbench(impl_lib, tb_impl_cell) # set testbench parameters values for key, val in tb_params.items(): tb.set_parameter(key, val) # set config view, i.e. schematic vs extracted tb.set_simulation_view(impl_lib, impl_cell, view_name) # set process corners tb.set_simulation_environments(sim_envs) # commit changes to ADEXL state back to database tb.update_testbench() print('running simulation') tb.run_simulation() print('simulation done, load results') results = load_sim_results(tb.save_dir) save_sim_results(results, os.path.join(data_dir, '%s.hdf5' % tb_impl_cell)) results_dict[tb_impl_cell] = results print('all simulation done') return results_dict
def redesign_Opamp(prj, temp_lib, impl_lib, sch_params): # generate tb schematic print("Re-generating Op-amp schematic ...") # increasing the W/L with relative ratio sch_params['mos_l']['L_in'] = sch_params['mos_l']['L_in'] + 200e-9 sch_params['mos_l']['L_N'] = sch_params['mos_l']['L_N'] + 150e-9 sch_params['mos_l']['L_P'] = sch_params['mos_l']['L_P'] + 150e-9 sch_params['mos_w']['W_in'] = sch_params['mos_w']['W_in'] + 240e-9 sch_params['mos_w']['W_N'] = sch_params['mos_w']['W_P'] + 180e-9 sch_params['mos_w']['W_P'] = sch_params['mos_w']['W_P'] + 180e-9 sch_params['comp_cap'] = sch_params['comp_cap'] + 100e-15 I_in, I_branch, Vgs_sf, dir = simulate_Opamp(prj, temp_lib, impl_lib, sch_params) while (I_in < 140e-6) or (I_in > 160e-6): print() print('Step 3/4: Re-designing Op-Amp') print(' Running 1/3 --Sizing input branch') print(' Now I_in=', I_in * 10**6, 'uA --Goal: 140~160uA') sch_params['mos_nf']['N_in'] = sch_params['mos_nf']['N_in'] + 2 if ( I_in < 140e-6) else sch_params['mos_nf']['N_in'] - 2 I_in, I_branch, Vgs_sf, res_dir = simulate_Opamp( prj, temp_lib, impl_lib, sch_params) print('Step 3/4: Re-designing Op-Amp') print(' Done 1/3 --Sizing input branch') flag = 0 direc = 0 if I_branch < 2e-6: direc = 1 while (I_branch < 2e-6) or (I_branch > 9e-6): print() print('Step 3/4: Re-designing Op-Amp') print(' Running 2/3 --Sizing main branch') print(' Now I_branch=', I_branch * 10**6, 'uA --Goal: 2~9uA') sch_params['mos_nf']['N_N'] = sch_params['mos_nf']['N_N'] + 2 if ( I_branch < 2e-6) else sch_params['mos_nf']['N_N'] - 2 I_in, I_branch, Vgs_sf, res_dir = simulate_Opamp( prj, temp_lib, impl_lib, sch_params) if (direc == 0 and I_branch > 9e-6) or (direc == 1 and I_branch < 2e-6): flag = 1 break if flag == 1 and direc == 1: sch_params['mos_nf']['N_N'] = sch_params['mos_nf']['N_N'] + 2 print('Step 3/4: Re-designing Op-Amp') print(' Done 2/3 --Sizing main branch') while (Vgs_sf < 0.48) or (Vgs_sf > 0.55): print() print('Step 3/4: Re-designing Op-Amp') print(' Running 3/3 --Sizing output stage (source follower)') print(' Now Vgs_sf=', Vgs_sf, 'V --Goal: 0.48~0.55V') sch_params['mos_nf']['N_OS'] = sch_params['mos_nf']['N_OS'] - 4 if ( Vgs_sf < 0.48) else sch_params['mos_nf']['N_OS'] + 4 I_in, I_branch, Vgs_sf, res_dir = simulate_Opamp( prj, temp_lib, impl_lib, sch_params) print('Step 3/4: Re-designing Op-Amp') print(' Done 3/3 --Sizing output stage (source follower)') I_in, I_branch, Vgs_sf, res_dir = simulate_Opamp(prj, temp_lib, impl_lib, sch_params) print() print('Step 3/4: Re-designing Op-Amp finished') print('Now DC is set at:') print(' I_in=', I_in * 10**6, 'uA (Ref: 150uA)') print(' I_branch=', I_branch * 10**6, 'uA (Ref: 5uA)') print(' Vgs_sf=', Vgs_sf, 'V (Ref: 0.5V)') print() results = load_sim_results(res_dir) print('The re-designed Op-Amp has:') print(' Gain=', results['dc_gain']) print(' BW=', results['band_width'] / (10**6), 'MHz') print(' GBW=', results['unity_gain'] / (10**9), 'GHz') print(' PM=', results['phase_margin']) return sch_params
tb_sch = prj.create_design_module(tb_lib, tb_cell) print('design TB') tb_sch.design(fname=fname, dut_lib=impl_lib, dut_cell=dut_cell) print('create TB schematic') tb_sch.implement_design(impl_lib, top_cell_name=tb_cell) print('configure TB state') tb = prj.configure_testbench(impl_lib, tb_cell) tb.set_sweep_parameter(cap_var, values=cap_swp_list) tb.add_output('in', """getData("/in" ?result 'tran)""") tb.add_output('out', """getData("/out" ?result 'tran)""") print('update TB state') tb.update_testbench() print('run simulation') tb.run_simulation() results = load_sim_results(tb.save_dir) print('simulation done, plot results') tvec = results['time'] vin = results['in'][0, :] cload0 = results['cload'][0] cload1 = results['cload'][1] vout0 = results['out'][0, :] vout1 = results['out'][1, :] plt.figure(1) plt.plot(tvec, vin, 'b') plt.plot(tvec, vout0, 'r', label='C=%.4g fF' % (cload0 * 1e15)) plt.plot(tvec, vout1, 'g', label='C=%.4g fF' % (cload1 * 1e15)) plt.legend() plt.show()