def _add_cell(lib: Library, cell_info: Mapping[str, Any], pin_data: Mapping[str, Mapping[str, Any]] ) -> None: empty_list = [] name: str = cell_info['name'] props: Dict[str, Any] = cell_info['props'] pwr_pins: Dict[str, str] = cell_info['pwr_pins'] gnd_pins: Dict[str, str] = cell_info['gnd_pins'] stdcell_pwr_pins: List[str] = cell_info.get('stdcell_pwr_pins', []) input_pins: List[Dict[str, Any]] = cell_info.get('input_pins', empty_list) output_pins: List[Dict[str, Any]] = cell_info.get('output_pins', empty_list) inout_pins: List[Dict[str, Any]] = cell_info.get('inout_pins', empty_list) cell = lib.create_cell(name, pwr_pins, gnd_pins, props, stdcell_pwr_pins=stdcell_pwr_pins) _add_pins(cell, TermType.input, input_pins, pin_data) _add_pins(cell, TermType.output, output_pins, pin_data) _add_pins(cell, TermType.inout, inout_pins, pin_data)
async def async_generate_liberty(prj: BagProject, lib_config: Mapping[str, Any], sim_config: Mapping[str, Any], cell_specs: Mapping[str, Any], fake: bool = False, extract: bool = False, force_sim: bool = False, force_extract: bool = False, gen_all_env: bool = False, gen_sch: bool = False, export_lay: bool = False, log_level: LogLevel = LogLevel.DEBUG ) -> None: """Generate liberty file for the given cells. Parameters ---------- prj: BagProject BagProject object to be able to generate things lib_config : Mapping[str, Any] library configuration dictionary. sim_config : Mapping[str, Any] simulation configuration dictionary. cell_specs : Mapping[str, Any] cell specification dictionary. fake : bool True to generate fake liberty file. extract : bool True to run extraction. force_sim : bool True to force simulation runs. force_extract : bool True to force extraction runs. gen_all_env : bool True to generate liberty files for all environments. gen_sch : bool True to generate schematics. export_lay : bool Use CAD tool to export layout. log_level : LogLevel stdout logging level. """ gen_specs_file: str = cell_specs['gen_specs_file'] scenario: str = cell_specs.get('scenario', '') gen_specs: Mapping[str, Any] = read_yaml(gen_specs_file) impl_lib: str = gen_specs['impl_lib'] impl_cell: str = gen_specs['impl_cell'] lay_cls: str = gen_specs['lay_class'] dut_params: Mapping[str, Any] = gen_specs['params'] name_prefix: str = gen_specs.get('name_prefix', '') name_suffix: str = gen_specs.get('name_suffix', '') gen_root_dir: Path = Path(gen_specs['root_dir']) lib_root_dir = gen_root_dir / 'lib_gen' sim_precision: int = sim_config['precision'] dsn_options = dict( extract=extract, force_extract=force_extract, gen_sch=gen_sch, log_level=log_level, ) log_file = str(lib_root_dir / 'lib_gen.log') sim_db = prj.make_sim_db(lib_root_dir / 'dsn', log_file, impl_lib, dsn_options=dsn_options, force_sim=force_sim, precision=sim_precision, log_level=log_level) dut = await sim_db.async_new_design(impl_cell, lay_cls, dut_params, export_lay=export_lay, name_prefix=name_prefix, name_suffix=name_suffix) environments: Mapping[str, Any] = lib_config['environments'] nom_voltage_type: str = environments['nom_voltage_type'] name_format: str = environments['name_format'] voltage_precision: int = environments['voltage_precision'] sim_env_list: List[Mapping[str, Any]] = environments['sim_envs'] if not gen_all_env: sim_env_list = [sim_env_list[0]] voltage_fmt = '{:.%df}' % voltage_precision lib_file_base_name = f'{impl_cell}_{scenario}' if scenario else impl_cell for sim_env_config in sim_env_list: sim_env: str = sim_env_config['sim_env'] voltages: Mapping[str, float] = sim_env_config['voltages'] vstr_table = {k: voltage_fmt.format(v).replace('.', 'p') for k, v in voltages.items()} sim_env_name = name_format.format(sim_env=sim_env, **vstr_table) lib_file_name = f'{lib_file_base_name}_{sim_env_name}' cur_lib_config = dict(**lib_config) cur_lib_config.pop('environments') # setup lib config temperature = get_corner_temp(sim_env)[1] env_config = dict( name=sim_env_name, bag_name=sim_env, process=1.0, temperature=temperature, voltage=voltages[nom_voltage_type], ) cur_lib_config['voltages'] = voltages cur_lib_config['sim_envs'] = [env_config] lib = Library(f'{impl_cell}_{sim_env_name}', cur_lib_config) out_file = gen_root_dir / f'{lib_file_name}.lib' lib_data, mm_specs, cur_work_dir = get_cell_info(lib, impl_cell, cell_specs, lib_root_dir, voltage_fmt) mm_specs['fake'] = fake mm_specs['sim_env_name'] = sim_env_name for key in ['tran_tbm_specs', 'buf_params', 'in_cap_search_params', 'out_cap_search_params', 'seq_search_params', 'seq_delay_thres']: mm_specs[key] = sim_config[key] mm = sim_db.make_mm(LibertyCharMM, mm_specs) sim_db.log(f'Characterizing {lib_file_name}.lib') char_results = await sim_db.async_simulate_mm_obj('lib_char', cur_work_dir, dut, mm) pin_data = char_results.data _add_cell(lib, lib_data, pin_data) lib.generate(out_file)
def get_cell_info(lib: Library, impl_cell: str, cell_specs: Mapping[str, Any], lib_root_dir: Path, voltage_fmt: str) -> Tuple[Mapping[str, Any], Dict[str, Any], Path]: sim_envs = lib.sim_envs if len(sim_envs) != 1: raise ValueError('Only support one corner per liberty file.') in_cap_range_scale: float = cell_specs['input_cap_range_scale'] in_cap_min: float = cell_specs.get('input_cap_min', 1.0e-15) in_cap_guess: float = cell_specs.get('input_cap_guess', in_cap_min) out_min_fanout: float = cell_specs.get('min_fanout', 0.5) stdcell_pwr_pins: Sequence[str] = cell_specs.get('stdcell_pwr_pins', []) input_pins: Sequence[Mapping[str, Any]] = cell_specs.get('input_pins', []) output_pins: Sequence[Mapping[str, Any]] = cell_specs.get('output_pins', []) inout_pins: Sequence[Mapping[str, Any]] = cell_specs.get('inout_pins', []) pwr_pins: Mapping[str, str] = cell_specs['pwr_pins'] gnd_pins: Mapping[str, str] = cell_specs['gnd_pins'] in_defaults: Mapping[str, Any] = cell_specs.get('input_pins_defaults', {}) out_defaults: Mapping[str, Any] = cell_specs.get('output_pins_defaults', {}) inout_defaults: Mapping[str, Any] = cell_specs.get('inout_pins_defaults', {}) pin_values: Mapping[str, int] = cell_specs.get('cond_defaults', {}) seq_timing: Mapping[str, Any] = cell_specs.get('seq_timing', {}) cell_props: Mapping[str, Any] = cell_specs.get('props', {}) diff_list: Sequence[Tuple[Sequence[str], Sequence[str]]] = cell_props.get('pin_opposite', []) custom_meas: Mapping[str, Mapping[str, Any]] = cell_specs.get('custom_measurements', {}) # get supply values sup_values: Dict[str, float] = {} for pin, vtype in chain(pwr_pins.items(), gnd_pins.items()): sup_values[pin] = lib.get_voltage(vtype) # gather pin information pwr_domain: Dict[str, Tuple[str, str]] = {} reset_table: Dict[str, bool] = {} in_cap_table: Dict[str, float] = {} in_pin_list = _get_pin_info_list(input_pins, in_defaults, pwr_domain, reset_table, in_cap_table, in_cap_guess) io_pin_list = _get_pin_info_list(inout_pins, inout_defaults, pwr_domain) out_pin_list = _get_pin_info_list(output_pins, out_defaults, pwr_domain) lut_delay = lib.get_lut(LUTType.DELAY) delay_shape = lut_delay.shape delay_swp_info = lut_delay.get_swp_info(dict(trf_src='t_rf', cload='c_load')) seq_swp_info = lut_delay.get_swp_info(dict(trf_src='t_clk_rf', cload='c_load')) lut_cons = lib.get_lut(LUTType.CONSTRAINT) t_rf_list = lut_cons['trf_in'] t_clk_rf_list = lut_cons['trf_src'] cons_swp_order = lut_cons.get_swp_order(dict(trf_src='t_clk_rf', trf_in='t_rf')) out_io_info_table = dict(chain(_pin_info_iter(out_pin_list), _pin_info_iter(io_pin_list))) out_cap_num_freq = len(lib.get_lut(LUTType.MAX_CAP)['freq']) mm_specs = dict( sim_envs=sim_envs, thres_lo=lib.thres_lo, thres_hi=lib.thres_hi, in_cap_min_default=in_cap_min, in_cap_range_scale=in_cap_range_scale, out_max_trf=lib.get_max_input_transition(LogicType.COMB, is_clock=False), out_min_fanout=out_min_fanout, out_cap_num_freq=out_cap_num_freq, in_cap_table=in_cap_table, out_io_info_table=out_io_info_table, seq_timing=seq_timing, custom_meas=custom_meas, delay_shape=delay_shape, delay_swp_info=delay_swp_info, seq_shape=delay_shape, seq_swp_info=seq_swp_info, t_rf_list=t_rf_list, t_clk_rf_list=t_clk_rf_list, t_clk_rf_first=(cons_swp_order[0] == 't_clk_rf'), dut_info=dict( pwr_domain=pwr_domain, sup_values=sup_values, pin_values=pin_values, reset_list=list(reset_table.items()), diff_list=diff_list, ), ) # get working directory vstr_table = {k: voltage_fmt.format(v).replace('.', 'p') for k, v in sup_values.items()} voltage_string = '_'.join((f'{k}_{vstr_table[k]}' for k in sorted(vstr_table.keys()))) work_dir = lib_root_dir / sim_envs[0] / voltage_string # construct result dictionary lib_data = {k: cell_specs[k] for k in ['props', 'pwr_pins', 'gnd_pins']} lib_data['name'] = impl_cell lib_data['stdcell_pwr_pins'] = stdcell_pwr_pins lib_data['input_pins'] = in_pin_list lib_data['output_pins'] = out_pin_list lib_data['inout_pins'] = io_pin_list return lib_data, mm_specs, work_dir