def parse_tech_lef(filename, find_via=False): techLEF_dict = {} metal_layer = 1 with open(filename) as f: start_parsing_layer_info = False start_parsing_via_info = False find_cutclass = False find_open_quote_cutclass = False find_layer_cut_info = False find_layer_routing_info = False find_via_dimesion = False storage = [] for line in f: if re.match(r'^LAYER\s+(\w+)', line): layer_name = re.match(r'^LAYER\s+(\w+)', line).group(1) start_parsing_layer_info = True # PART I: Parsing the information of the metal layer if start_parsing_layer_info: if re.match(r'^\s+TYPE\s+\w+\s*;', line): type_of_layer = re.match(r'^\s+TYPE\s+(\w+)\s*;', line).group(1) if type_of_layer == 'CUT': find_layer_cut_info = True # Set the Flag # initialize the dictionary if not 'Layer' in techLEF_dict: techLEF_dict['Layer'] = {} techLEF_dict['Layer'][layer_name] = { 'type': type_of_layer } continue if type_of_layer == 'ROUTING': find_layer_routing_info = True cur_ml = cl.LEF_Metal_Routing(layer=layer_name, layer_type=type_of_layer, layer_number=metal_layer) metal_layer += 1 continue # PART IA: Get the information of CUT layers if find_layer_cut_info: if re.match(r'^\s*PROPERTY\s+LEF58_CUTCLASS', line): find_cutclass = True if find_cutclass: if re.search(r'"', line) and not find_open_quote_cutclass: find_open_quote_cutclass = True elif re.search(r'"', line) and find_open_quote_cutclass: find_open_quote_cutclass = False if re.search(r';', line) and not find_open_quote_cutclass: find_cutclass = False if find_open_quote_cutclass: if re.match('^\s+CUTCLASS\s+\w+', line): cutclass = re.match(r'^\s+CUTCLASS\s+(\w+)', line) # Initialize the class to store the info cur_ml = cl.LEF_Metal_Cut( layer=layer_name, layer_type=type_of_layer) cur_ml.set_layerClassName(cutclass.group(1)) cur_ml.set_cutClass(True) if re.search(r'\s+WIDTH\s+([-+]?\d*\.\d+)', line): width = re.search( r'\s+WIDTH\s+([-+]?\d*\.\d+)', line) cur_ml.set_viaWidth(width.group(1)) if re.search(r'\s+LENGTH\s+([-+]?\d*\.\d+|\w+)', line): length = re.search( r'\s+LENGTH\s+([-+]?\d*\.\d+)', line) cur_ml.set_viaLength(length.group(1)) if re.search(r'\s+CUTS\s+([-+]?\d*\.\d+|\w+)', line): cuts = re.search(r'\s+CUTS\s*(\d+)', line) cur_ml.set_viaCuts(cuts.group(1)) if re.search(r';', line): storage.append(cur_ml) if re.match(r'^\s*WIDTH\s+([-+]?\d*\.\d+)', line): wid = re.search(r'^\s*WIDTH\s+([-+]?\d*\.\d+)\s*;', line) cur_ml = cl.LEF_Metal_Cut(layer=layer_name, layer_type=type_of_layer) cur_ml.set_viaWidth(wid.group(1)) storage.append(cur_ml) if start_parsing_layer_info and re.match( r'^\s*END\s+' + re.escape(layer_name), line): start_parsing_layer_info = False find_layer_cut_info = False # PART IB: Get the information of ROUTING layers if find_layer_routing_info: if re.match('^\s+DIRECTION\s+\w+', line): direction = re.match(r'^\s+DIRECTION\s+(\w+)\s+;', line) cur_ml.set_layerDirection(direction.group(1)) if re.match('^\s+WIDTH\s+([-+]?\d*\.\d+)\s+;', line): width = re.match(r'^\s+WIDTH\s+([-+]?\d*\.\d+)', line) cur_ml.set_layerWidth(width.group(1)) if re.match('^\s+PITCH\s+([-+]?\d*\.\d+)\s+;', line): pitch = re.match(r'^\s+PITCH\s+([-+]?\d*\.\d+|\w+)', line) cur_ml.set_layerPitch(pitch.group(1)) if re.match('^\s+SPACING\s+([-+]?\d*\.\d+)\s+;', line): spacing = re.match( r'^\s+SPACING\s+([-+]?\d*\.\d+|\w+)', line) cur_ml.set_layerSpacing(spacing.group(1)) if re.match('^\s+TYPE\s+\w+\s*;', line): check = re.match('^\s+TYPE\s+(\w+)\s*;', line).group(1) if check == 'MIMCAP' or check == 'PASSIVATION' or check == 'HIGHR' or check == 'TSV': start_parsing_layer_info = False find_layer_routing_info = False if start_parsing_layer_info and re.match( r'^\s*END\s+' + re.escape(layer_name), line): start_parsing_layer_info = False find_layer_routing_info = False storage.append(cur_ml) # PART II: Parsing the information of VIA section --> # of cuts if re.match(r'^\s*VIA\s+(\w+)', line): start_parsing_via_info = True via_name = re.match(r'^\s*VIA\s+(\w+)', line).group(1) cur_via = cl.LEF_VIA_Info(via_name=via_name) if start_parsing_via_info and re.match( r'^\s*END\s+' + re.escape(via_name) + '', line): start_parsing_via_info = False cur_via.set_viaCuts( compute_via_number_of_cuts(cur_via, techLEF_dict)) storage.append(cur_via) if start_parsing_via_info: if re.match(r'^\s+LAYER\s+(\w+)\s+;', line): layer = re.match(r'\s+LAYER\s+(\w+)\s+;', line).group(1) if techLEF_dict['Layer'][layer]['type'] == 'CUT': find_via_dimesion = True cur_via.set_viaCutLayer(layer) else: cur_via.set_viaLayerAssignemnt(layer, techLEF_dict) find_via_dimesion = False # If the CUT layer is detected if find_via_dimesion: if re.match(r'^\s+RECT\s+.+;$', line): pin_dimension = re.findall('([-+]?\d*\.\d+)+', line) cur_via.set_viaDimension(pin_dimension) if len(storage) != 0: convert_techLEF_dictionary(storage, techLEF_dict) storage.clear() # Function to get the list of via used in the calibration script if find_via: find_via_for_each_layer(techLEF_dict) else: return techLEF_dict
def def_parser(def_file, pins, nets, cell_coor_dict, load_cap_dict, cell_dimension, buildPath=True): print('# READING DEF') with open(def_file) as f: blocks = [] mapping_number = 1 # Parsing Components Section parsing_component = False comp_syn = False cur_comp = [] # NET BOOLEAN find_net = False find_data = False # PIN BOOLEAN find_pin = False pin_info = False # VIAS BOOLEAN find_vias = False via_info = False for line in f: """ HEADER SECTION""" # Finding the PER UNIT VALUE if re.search('UNITS DISTANCE MICRONS', line, flags=re.IGNORECASE): data = re.findall(r'\d+', line) glob.UNIT_DISTANCE = (int(data[0])) if re.match('^VERSION\s*(\d+\.?\d*)\s*[;]', line): def_version = re.match('^VERSION\s*(\d+\.?\d*)\s*[;]', line).group(1) if re.match('^DIVIDERCHAR\s*["](.+)["]\s*[;]', line): glob.DIVIDER = re.match('^DIVIDERCHAR\s*["](.+)["]\s*[;]', line).group(1) if re.match('^BUSBITCHARS\s*["](.+)["]\s*[;]', line): glob.BUS_CHAR = re.match('^BUSBITCHARS\s*["](.+)["]\s*[;]', line).group(1) if re.match('^DESIGN\s*\w+\s*[;]', line): glob.DESIGN = re.match('^DESIGN\s*(\w+)\s*[;]', line).group(1) """" END HEADER SECTION """ """FILLING THE FIRST PART OF THE RECT CLASS""" if re.match('^[\t ]*COMPONENTS \d+', line, flags=re.IGNORECASE): parsing_component = True continue if re.match('^[\t ]*END COMPONENTS', line, flags=re.IGNORECASE): parsing_component = False # Create dictionary that contains all the COMPONENTS info create_block_dict(blocks, load_cap_dict, cell_dimension, cell_coor_dict) continue if parsing_component: if re.match('^[\t ]*-[\t ]+\w+[\t ]+\w+', line): comp_name = re.search(r'[\t ]*-[\t ]+(\w+)[\t ]+(\w+)', line) cur_comp = cl.Component(name=comp_name.group(1), cell=comp_name.group(2), number=mapping_number) comp_syn = True mapping_number += 1 if re.search('PLACED|FIXED|COVER', line, flags=re.IGNORECASE) and comp_syn: comp_loc = re.search( r'[+] (PLACED|FIXED|COVER)\s+[(] ([-+]?\d+\.?\d*)\s+([-+]?\d+\.?\d*) [)] (\w+)', line) cur_comp.set_location(comp_loc.group(2), comp_loc.group(3)) cur_comp.set_orientation(comp_loc.group(4)) if re.search('PLACED|FIXED|COVER', line, flags=re.IGNORECASE) and comp_syn: Property = re.search( r'[+] (PROPERTY)\s+(\w+)\s+([-+]?\d+\.?\d*|\w+)', line) if Property != None: cur_comp.set_property( [Property.group(2), Property.group(3)]) if re.search( ';', line ) and comp_syn: #semicolon at the begining of the line comp_syn = False blocks.append(cur_comp) """ FIRST PART ENDS HERE """ """ PINS START """ if re.match('^[\t ]*PINS \d+', line, flags=re.IGNORECASE): find_pin = True continue if re.match('^[\t ]*END PINS*', line, flags=re.IGNORECASE): find_pin = False continue if find_pin: if re.match('^\s*-\s+(\w+)', line): pin_info = True pin_class = cl.Pin(number=mapping_number) pin_class.set_name( re.match('^\s*-\s+(\S+)\s*', line).group(1)) mapping_number += 1 if pin_info: if re.match('. .+', line): data = re.findall(r'(?![(|)|+|;])\S+', line) processPinData(pin_class, data) if re.search(';', line): pin_info = False add_pin_info_toDict(pin_class, pins) continue """ END PINS """ """ VIAS SECTION """ if find_vias: if re.search(r';', line): via_info = False # Set the cut layer of the via num_cuts = compute_via_number_of_cuts( cur_via, glob.TECH_LEF_DICT) cur_via.set_viaCuts(num_cuts) def_via.append_via_data_to_dict(cur_via, glob.TECH_LEF_DICT) if via_info: def_via.parse_def_via_section(line, cur_via, glob.TECH_LEF_DICT) if re.match(r'^\s*[-]\s+(\w+)', line): via_name = re.findall(r'\S+', line) via_name = (via_name[1]) cur_via = cl.LEF_VIA_Info(via_name=via_name) via_info = True if re.match('^VIAS\s+\d+\s+[;]', line): find_vias = True if re.match('^END VIAS*', line): find_vias = False """ END VIA SECTION """ """ NETS PART """ if re.match('^[\t ]*NETS \d+', line, flags=re.IGNORECASE): find_net = True print('# Process Nets information...') net_count = 0 continue if re.match('^[\t ]*END NETS*', line, flags=re.IGNORECASE): find_net = False print('# Finsihed processing Nets information') print('# Total Net Count: {}'.format(net_count)) continue if find_net == True: if re.match('^[\t ]*-[\t ]+\w+', line): mapped = False data = re.findall(r'\S+', line) # Create an Instance of a net cur_net = cl.NET(data[1]) cur_net.add_cell = blocks # ADDING THE MAPPING NUMBER OF THE NET TO THE PIN INFO if data[1] in pins: cur_net.number = pins[data[1]]['number'] mapped = True if not mapped: cur_net.number = mapping_number mapping_number += 1 find_data = True # End of the particular NET, process the wire data if re.search('^\s*;', line): #semicolon at the begining of the line find_data = False net_count += 1 if cur_net.wire_list == []: nets.append(cur_net) print( '# Warning: Net {} does not contain any interconnect information!' .format(cur_net.name)) continue # Use for SPEF writer, creating PATH from DEF if buildPath: build_path(cur_net, cell_coor_dict, pins) nets.append(cur_net) continue if find_data: parse_net(line, cur_net, cell_coor_dict) """ END NETS """ # if buildPath: # import multiprocessing as mp # print('# Building Path ...') # processes = [] # end = 0 # # cpu_count = mp.cpu_count() + 10 # for i in range (cpu_count): # start = end # # if i == cpu_count-1: # end = len(nets) # else: # end = (i+1) * int(len(nets)/cpu_count) # # p = mp.Process(target=fork_build_path, args=(start, end, nets, cell_coor_dict, pins,)) # processes.append(p) # p.start() # # for process in processes: # process.join() print('# Finish Rading DEF')