def run(self, edit, args): settings = self.view.settings() isAutoConnect = settings.get('sv.autoconnect', False) isParamOneLine = settings.get('sv.param_oneline', True) isInstOneLine = settings.get('sv.inst_oneline', True) isColumnAlignment = settings.get('sv.param_port_alignment', True) indent_level = settings.get('sv.decl_indent') param_decl = '' pm = args['pm'] # print(pm) # Update Module information with parameter value for later signal declaration using correct type for p in args['pv']: for pmp in pm['param']: if pmp['name'] == p['name']: if p['value'].startswith('parameter') or p[ 'value'].startswith('localparam'): pmp['value'] = p['name'] param_decl += indent_level * '\t' + p['value'] + ';\n' m = re.search(r"(?P<name>\w+)\s*=", p['value']) p['value'] = m.group('name') else: pmp['value'] = p['value'] break # print('[VerilogDoModuleInstCommand] pm = '+ str(pm)) decl = '' ac = {} wc = {} # Add signal port declaration if isAutoConnect and pm['port']: (decl, ac, wc) = self.get_connect(self.view, settings, pm) #Find location where to insert signal declaration: default to just before module instantiation if decl or param_decl: r = self.get_region_decl(self.view, settings) self.view.insert(edit, r, '\n' + param_decl + decl) sublime.status_message('Adding ' + str(len(decl.splitlines())) + ' signals declaration') inst_name = settings.get('sv.instance_prefix', '') + pm['name'] + settings.get( 'sv.instance_suffix', '') # Check if instantiation can fit on one line only if isInstOneLine: len_inst = len(pm['name']) + 1 + len(inst_name) + 2 if len(args['pv']) > 0: len_inst += 2 for p in args['pv']: len_inst += len(p['name']) + len(p['value']) + 5 if len_inst + 3 > settings.get('sv.max_line_length', 120): isParamOneLine = False elif pm['port']: for p in pm['port']: len_inst += len(p['name']) + 5 if p['name'] in ac.keys(): len_inst += len(ac[p['name']]) else: len_inst += len(p['name']) if len_inst + 3 > settings.get('sv.max_line_length', 120): isInstOneLine = False # Instantiation inst = pm['name'] + " " # Parameters: bind only parameters for which a value different from default was set if len(args['pv']) > 0: if isParamOneLine or not isColumnAlignment: max_len = 0 else: max_len = max([len(x['name']) for x in args['pv']]) inst += "#(" if not isParamOneLine: inst += "\n" for i in range(len(args['pv'])): if not isParamOneLine: inst += "\t" inst += "." + args['pv'][i]['name'].ljust( max_len) + "(" + args['pv'][i]['value'] + ")" if i < len(args['pv']) - 1: inst += "," if not isParamOneLine: inst += "\n" elif i < len(args['pv']) - 1: inst += " " inst += ") " #Port binding inst += inst_name + " (" if not isInstOneLine: inst += "\n" if pm['port']: # Get max length of a port to align everything if isInstOneLine or not isColumnAlignment: max_len_p = 0 max_len_s = 0 else: max_len_p = max([len(x['name']) for x in pm['port']]) max_len_s = max_len_p # print('Autoconnect dict = ' + str([ac[x] for x in ac])) if len(ac) > 0: max_len_s = max([len(ac[x]) for x in ac]) if max_len_p > max_len_s: max_len_s = max_len_p for i in range(len(pm['port'])): portname = pm['port'][i]['name'] if not isInstOneLine: inst += "\t" inst += "." + portname.ljust(max_len_p) + "(" if isAutoConnect: if portname in ac.keys(): inst += ac[portname].ljust(max_len_s) else: inst += portname.ljust(max_len_s) inst += ")" if i < len(pm['port']) - 1: inst += "," if not isInstOneLine: if portname in wc.keys(): inst += " // TODO: Check connection ! " + wc[portname] inst += "\n" elif i < len(pm['port']) - 1: inst += " " inst += ");\n" self.view.insert(edit, self.view.sel()[0].a, inst) # Status report nb_decl = len(decl.splitlines()) s = '' if nb_decl: s += 'Adding ' + str(nb_decl) + ' signal(s) declaration(s)\n' if len(ac) > 0: s += 'Non-perfect name match for ' + str( len(ac)) + ' port(s) : ' + str(ac) + '\n' if len(wc) > 0: s += 'Found ' + str(len(wc)) + ' mismatch(es) for port(s): ' + str( [x for x in wc.keys()]) + '\n' if s != '': sublimeutil.print_to_panel(s, 'SystemVerilog')
def run(self, edit): if len(self.view.sel()) == 0: return r = self.view.sel()[0] scope = self.view.scope_name(r.a) if 'meta.module.inst' not in scope: return # Select whole module instantiation r = sublimeutil.expand_to_scope(self.view, 'meta.module.inst', r) if self.view.classify(r.a) & sublime.CLASS_LINE_START == 0: r.a = self.view.find_by_class(r.a, False, sublime.CLASS_LINE_START) # print(self.view.substr(r)) txt = verilogutil.clean_comment(self.view.substr(r)) # Parse module definition mname = re.findall(r'\w+', txt)[0] filelist = self.view.window().lookup_symbol_in_index(mname) if not filelist: return for f in filelist: fname = sublimeutil.normalize_fname(f[0]) mi = verilogutil.parse_module_file(fname, mname, no_inst=True) if mi: break if not mi: sublime.status_message( 'Unable to retrieve module information for ' + mname) return settings = self.view.settings() mpl = [x['name'] for x in mi['port']] mpal = [x['name'] for x in mi['param']] #Extract existing binding bl = re.findall(r'(?s)\.(\w+)\s*\(\s*(.*?)\s*\)\s*(,|\))', txt, flags=re.MULTILINE) # Handle case of binding by position (TODO: support parameter as well ...) if not bl: m = re.search( r'(?s)(#\s*\((?P<params>.*?)\)\s*)?\s*\w+\s*\((?P<ports>.*?)\)\s*;', txt, flags=re.MULTILINE) pl = m.group('ports') if pl: pa = pl.split(',') bt = '' for i, p in enumerate(pa): if i >= len(mpl): break bl.append((mpl[i], p.strip())) bt += '.{portName}({sigName}),\n'.format( portName=bl[-1][0], sigName=bl[-1][1]) # Replace connection by position by connection by name r_tmp = self.view.find(pl, r.a, sublime.LITERAL) if r.contains(r_tmp): self.view.replace(edit, r_tmp, bt) # Update region r = sublimeutil.expand_to_scope(self.view, 'meta.module.inst', r) ipl = [x[0] for x in bl] # Check for added port apl = [x for x in mpl if x not in ipl] if apl: (decl, ac, wc) = VerilogDoModuleInstCommand.get_connect( self, self.view, settings, mi) last_char = self.view.substr(sublime.Region(r.a, r.b - 2)).strip(' \t')[-1] b = '\n' if last_char != '\n' else '' for p in apl: b += "." + p + "(" if p in ac.keys(): b += ac[p] else: b += p b += ")," if p in wc.keys(): b += " // TODO: Check connection ! " + wc[p] b += "\n" # Add binding at the end of the instantiation self.view.insert(edit, r.b - 2, b) # Check for deleted port dpl = [x for x in ipl if x not in mpl and x not in mpal] for p in dpl: r_tmp = self.view.find(r'(?s)\.' + p + r'\s*\(.*?\)\s*(,|\)\s*;)', r.a) if r.contains(r_tmp): s = self.view.substr(r_tmp) if s[-1] == ';': s_tmp = s[:-1].strip()[:-1] r_tmp.b -= (len(s) - len(s_tmp)) self.view.erase(edit, r_tmp) r_tmp = self.view.full_line(r_tmp.a) # cleanup comment m = re.search(r'^\s*(\/\/.*)?$', self.view.substr(r_tmp)) if m: self.view.erase(edit, r_tmp) # Print status # print('[reconnect] Module Port list = ' + str(mpl)) # print('[reconnect] Instance Port list = ' + str(ipl)) # print('[reconnect] => Removed Port list = ' + str(dpl)) # print('[reconnect] => Added Port list = ' + str(apl)) s = '' if dpl: s += "Removed %d ports: %s\n" % (len(dpl), str(dpl)) if apl: s += "Added %d ports: %s\n" % (len(apl), str(apl)) decl_clean = '' ac_clean = {} for p in apl: if p in ac: ac_clean[p] = ac[p] m = re.search(r'^.*\b' + p + r'\b.*;', decl, re.MULTILINE) if m: decl_clean += m.group(0) + '\n' for p in ipl: if p in wc: wc.pop(p) nb_decl = len(decl_clean.splitlines()) if decl_clean: r_start = VerilogDoModuleInstCommand.get_region_decl( self, self.view, settings, r.a) self.view.insert(edit, r_start, '\n' + decl_clean) s += 'Adding ' + str(nb_decl) + ' signal(s) declaration(s)\n' if len(ac_clean) > 0: s += 'Non-perfect name match for ' + str( len(ac_clean)) + ' port(s) : ' + str(ac_clean) + '\n' if len(wc) > 0: s += 'Found ' + str( len(wc)) + ' mismatch(es) for port(s): ' + str( [x for x in wc.keys()]) + '\n' if s: sublimeutil.print_to_panel(s, 'SystemVerilog') # Realign self.view.run_command("verilog_align")