| #!/usr/bin/env python3 | |
| """ | |
| Gather data from given lib file. This data is then used to populate JSON file | |
| that has delay numbers for some parameters related to F2A and A2F pins. | |
| """ | |
| import argparse | |
| from collections import defaultdict | |
| # ============================================================================= | |
| def main(): | |
| """ | |
| Gather lib information from the given library file | |
| """ | |
| parser = argparse.ArgumentParser( | |
| description='Gather lib information from the given library file.' | |
| ) | |
| parser.add_argument( | |
| "--lib", | |
| "-l", | |
| "-L", | |
| type=str, | |
| required=True, | |
| help='Specify input lib file' | |
| ) | |
| args = parser.parse_args() | |
| lib_fp = open(args.lib, newline='') | |
| for line in lib_fp: | |
| if line.find("bus ( gfpga_pad_IO_A2F") != -1: | |
| a2f_process_lib_data(lib_fp) | |
| elif line.find("bus ( gfpga_pad_IO_F2A") != -1: | |
| f2a_process_lib_data(lib_fp) | |
| # ============================================================================= | |
| def f2a_process_lib_data(lib_fp): | |
| """ | |
| Process F2A pin lib_data | |
| """ | |
| f2a_data_max = defaultdict(set) | |
| f2a_data_min = defaultdict(set) | |
| max_transition = set() | |
| capacitance = set() | |
| for f2a_line in lib_fp: | |
| pin_pos = f2a_line.find("pin(\"") | |
| if pin_pos != -1: | |
| for pin_line in lib_fp: | |
| if pin_line.find("rising_edge") != -1: | |
| f2a_data_max, f2a_data_min = f2a_timing_type( | |
| lib_fp, pin_line, "rising_edge", f2a_data_max, | |
| f2a_data_min | |
| ) | |
| elif pin_line.find("max_transition") != -1: | |
| val_list = pin_line.split(' : ') | |
| max_transition.add( | |
| float(val_list[1].split(' ;')[0].strip()) | |
| ) | |
| elif pin_line.find("capacitance") != -1: | |
| val_list = pin_line.split(' : ') | |
| capacitance.add(float(val_list[1].split(' ;')[0].strip())) | |
| elif pin_line.find("end of bus") != -1: | |
| break | |
| print( | |
| 'F2A {} least_val: {}, highest_val: {}'.format( | |
| "max_transition", next(iter(sorted(max_transition))), | |
| sorted(max_transition).pop() | |
| ) | |
| ) | |
| print( | |
| 'F2A {} least_val: {}, highest_val: {}'.format( | |
| "capacitance", next(iter(sorted(capacitance))), | |
| sorted(capacitance).pop() | |
| ) | |
| ) | |
| print( | |
| 'F2A {} least_val: {}, highest_val: {}'.format( | |
| "rising_edge_cell_rise_val", | |
| next(iter(sorted(f2a_data_min['rising_edge_cell_rise']))), | |
| sorted(f2a_data_max['rising_edge_cell_rise']).pop() | |
| ) | |
| ) | |
| print( | |
| 'F2A {} least_val: {}, highest_val: {}'.format( | |
| "rising_edge_cell_fall_val", | |
| next(iter(sorted(f2a_data_min['rising_edge_cell_fall']))), | |
| sorted(f2a_data_max['rising_edge_cell_fall']).pop() | |
| ) | |
| ) | |
| print( | |
| 'F2A {} least_val: {}, highest_val: {}'.format( | |
| "rising_edge_rise_tran_val", | |
| next(iter(sorted(f2a_data_min['rising_edge_rise_tran']))), | |
| sorted(f2a_data_max['rising_edge_rise_tran']).pop() | |
| ) | |
| ) | |
| print( | |
| 'F2A {} least_val: {}, highest_val: {}'.format( | |
| "rising_edge_fall_tran_val", | |
| next(iter(sorted(f2a_data_min['rising_edge_fall_tran']))), | |
| sorted(f2a_data_max['rising_edge_fall_tran']).pop() | |
| ) | |
| ) | |
| break | |
| # ============================================================================= | |
| def a2f_process_lib_data(lib_fp): | |
| """ | |
| Process A2F pin lib_data | |
| """ | |
| a2f_data_max = defaultdict(set) | |
| a2f_data_min = defaultdict(set) | |
| max_transition = set() | |
| capacitance = set() | |
| for a2f_line in lib_fp: | |
| pin_pos = a2f_line.find("pin(\"") | |
| if pin_pos != -1: | |
| for pin_line in lib_fp: | |
| if pin_line.find("setup_rising") != -1: | |
| a2f_data_max, a2f_data_min = a2f_timing_type( | |
| lib_fp, pin_line, "setup_rising", a2f_data_max, | |
| a2f_data_min | |
| ) | |
| elif pin_line.find("hold_rising") != -1: | |
| a2f_data_max, a2f_data_min = a2f_timing_type( | |
| lib_fp, pin_line, "hold_rising", a2f_data_max, | |
| a2f_data_min | |
| ) | |
| elif pin_line.find("max_transition") != -1: | |
| val_list = pin_line.split(' : ') | |
| max_transition.add( | |
| float(val_list[1].split(' ;')[0].strip()) | |
| ) | |
| elif pin_line.find("capacitance") != -1: | |
| val_list = pin_line.split(' : ') | |
| capacitance.add(float(val_list[1].split(' ;')[0].strip())) | |
| elif pin_line.find("end of bus gfpga_pad_IO_A2F") != -1: | |
| break | |
| print( | |
| 'A2F {} least_val: {}, highest_val: {}'.format( | |
| "max_transition", next(iter(sorted(max_transition))), | |
| sorted(max_transition).pop() | |
| ) | |
| ) | |
| print( | |
| 'A2F {} least_val: {}, highest_val: {}'.format( | |
| "capacitance", next(iter(sorted(capacitance))), | |
| sorted(capacitance).pop() | |
| ) | |
| ) | |
| print( | |
| 'A2F {} least_val: {}, highest_val: {}'.format( | |
| "setup_rising_rise_constraint_val", | |
| next( | |
| iter( | |
| sorted( | |
| a2f_data_min['setup_rising_rise_constraint'] | |
| ) | |
| ) | |
| ), | |
| sorted(a2f_data_max['setup_rising_rise_constraint']).pop() | |
| ) | |
| ) | |
| print( | |
| 'A2F {} least_val: {}, highest_val: {}'.format( | |
| "setup_rising_fall_constraint_val", | |
| next( | |
| iter( | |
| sorted( | |
| a2f_data_min['setup_rising_fall_constraint'] | |
| ) | |
| ) | |
| ), | |
| sorted(a2f_data_max['setup_rising_fall_constraint']).pop() | |
| ) | |
| ) | |
| print( | |
| 'A2F {} least_val: {}, highest_val: {}'.format( | |
| "hold_rising_rise_constraint_val", | |
| next( | |
| iter( | |
| sorted( | |
| a2f_data_min['hold_rising_rise_constraint'] | |
| ) | |
| ) | |
| ), | |
| sorted(a2f_data_max['hold_rising_rise_constraint']).pop() | |
| ) | |
| ) | |
| print( | |
| 'A2F {} least_val: {}, highest_val: {}'.format( | |
| "hold_rising_fall_constraint_val", | |
| next( | |
| iter( | |
| sorted( | |
| a2f_data_min['hold_rising_fall_constraint'] | |
| ) | |
| ) | |
| ), | |
| sorted(a2f_data_max['hold_rising_fall_constraint']).pop() | |
| ) | |
| ) | |
| break | |
| # ============================================================================= | |
| def a2f_timing_type(lib_fp, pin_line, type_str, a2f_data_max, a2f_data_min): | |
| """ | |
| Collect A2F pin data | |
| """ | |
| type_pos = pin_line.find(type_str) | |
| if type_pos != -1: | |
| for type_line in lib_fp: | |
| rise_pos = type_line.find("rise_constraint") | |
| if rise_pos != -1: | |
| for constraint_line in lib_fp: | |
| if constraint_line.find("}") != -1: | |
| break | |
| if constraint_line.find('values') != -1: | |
| val_set = set() | |
| val_set = populate_set(constraint_line, val_set) | |
| for val_line in lib_fp: | |
| if val_line.find(");") != -1: | |
| val_set = populate_set(val_line, val_set) | |
| break | |
| val_set = populate_set(val_line, val_set) | |
| if type_str == "setup_rising": | |
| a2f_data_max['setup_rising_rise_constraint'].add( | |
| sorted(val_set).pop() | |
| ) | |
| a2f_data_min['setup_rising_rise_constraint'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| else: | |
| a2f_data_max['hold_rising_rise_constraint'].add( | |
| sorted(val_set).pop() | |
| ) | |
| a2f_data_min['hold_rising_rise_constraint'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| break | |
| break | |
| for type_line in lib_fp: | |
| fall_pos = type_line.find("fall_constraint") | |
| if fall_pos != -1: | |
| for constraint_line in lib_fp: | |
| if constraint_line.find("}") != -1: | |
| break | |
| if constraint_line.find('values') != -1: | |
| val_set = set() | |
| val_set = populate_set(constraint_line, val_set) | |
| for val_line in lib_fp: | |
| if val_line.find(");") != -1: | |
| val_set = populate_set(val_line, val_set) | |
| break | |
| val_set = populate_set(val_line, val_set) | |
| if type_str == "setup_rising": | |
| a2f_data_max['setup_rising_fall_constraint'].add( | |
| sorted(val_set).pop() | |
| ) | |
| a2f_data_min['setup_rising_fall_constraint'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| else: | |
| a2f_data_max['hold_rising_fall_constraint'].add( | |
| sorted(val_set).pop() | |
| ) | |
| a2f_data_min['hold_rising_fall_constraint'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| break | |
| break | |
| return a2f_data_max, a2f_data_min | |
| # ============================================================================= | |
| def f2a_timing_type(lib_fp, pin_line, type_str, f2a_data_max, f2a_data_min): | |
| """ | |
| Collect F2A pin data | |
| """ | |
| type_pos = pin_line.find(type_str) | |
| if type_pos != -1: | |
| for type_line in lib_fp: | |
| rise_pos = type_line.find("cell_rise") | |
| if rise_pos != -1: | |
| for constraint_line in lib_fp: | |
| if constraint_line.find("}") != -1: | |
| break | |
| if constraint_line.find('values') != -1: | |
| val_set = set() | |
| val_set = populate_set(constraint_line, val_set) | |
| for val_line in lib_fp: | |
| if val_line.find(");") != -1: | |
| val_set = populate_set(val_line, val_set) | |
| break | |
| val_set = populate_set(val_line, val_set) | |
| f2a_data_max['rising_edge_cell_rise'].add( | |
| sorted(val_set).pop() | |
| ) | |
| f2a_data_min['rising_edge_cell_rise'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| break | |
| break | |
| for type_line in lib_fp: | |
| fall_pos = type_line.find("rise_transition") | |
| if fall_pos != -1: | |
| for constraint_line in lib_fp: | |
| if constraint_line.find("}") != -1: | |
| break | |
| if constraint_line.find('values') != -1: | |
| val_set = set() | |
| val_set = populate_set(constraint_line, val_set) | |
| for val_line in lib_fp: | |
| if val_line.find(");") != -1: | |
| val_set = populate_set(val_line, val_set) | |
| break | |
| val_set = populate_set(val_line, val_set) | |
| f2a_data_max['rising_edge_rise_tran'].add( | |
| sorted(val_set).pop() | |
| ) | |
| f2a_data_min['rising_edge_rise_tran'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| break | |
| break | |
| for type_line in lib_fp: | |
| fall_pos = type_line.find("cell_fall") | |
| if fall_pos != -1: | |
| for constraint_line in lib_fp: | |
| if constraint_line.find("}") != -1: | |
| break | |
| if constraint_line.find('values') != -1: | |
| val_set = set() | |
| val_set = populate_set(constraint_line, val_set) | |
| for val_line in lib_fp: | |
| if val_line.find(");") != -1: | |
| val_set = populate_set(val_line, val_set) | |
| break | |
| val_set = populate_set(val_line, val_set) | |
| f2a_data_max['rising_edge_cell_fall'].add( | |
| sorted(val_set).pop() | |
| ) | |
| f2a_data_min['rising_edge_cell_fall'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| break | |
| break | |
| for type_line in lib_fp: | |
| fall_pos = type_line.find("fall_transition") | |
| if fall_pos != -1: | |
| for constraint_line in lib_fp: | |
| if constraint_line.find("}") != -1: | |
| break | |
| if constraint_line.find('values') != -1: | |
| val_set = set() | |
| val_set = populate_set(constraint_line, val_set) | |
| for val_line in lib_fp: | |
| if val_line.find(");") != -1: | |
| val_set = populate_set(val_line, val_set) | |
| break | |
| val_set = populate_set(val_line, val_set) | |
| f2a_data_max['rising_edge_fall_tran'].add( | |
| sorted(val_set).pop() | |
| ) | |
| f2a_data_min['rising_edge_fall_tran'].add( | |
| next(iter(sorted(val_set))) | |
| ) | |
| break | |
| break | |
| return f2a_data_max, f2a_data_min | |
| # ============================================================================= | |
| def populate_set(line, val_set): | |
| """ | |
| Collects values and put it in a set | |
| """ | |
| pos = line.find("\"") | |
| pos1 = line.rfind("\"") | |
| sub = line[pos + 1:pos1] | |
| val_list = sub.split(',') | |
| for val in val_list: | |
| val_set.add(float(val.strip())) | |
| return val_set | |
| # ============================================================================= | |
| if __name__ == '__main__': | |
| main() |