vtags 是一款在gvim下實現相似verdi的信號追蹤、顯示拓撲等功能的插件。vtags插件徹底使用python實現,目前實現功能包括信號追蹤、宏定義追蹤、顯示模塊拓撲、快速打開文件、保存和打開gvim快照、添加斷點等功能。php
支持功能和快捷鍵:html
快捷鍵python |
功能linux |
givim |
進入子模塊windows |
guapi |
回到上層模塊bash |
<Space><Left>app |
追信號源,或宏定義less |
<Space><Right> |
追信號目的 |
<Space><Down> |
回退 |
<Space><Up> |
向前 |
<Space> + v |
顯示策略,和展開收回策略條目 |
<Space> + c |
添加記錄點 |
<Space> + b |
添加基本模塊 |
<Space> + d |
刪除記錄點或基本模塊 |
<Space> +h |
固定當前窗口 |
<Space> |
快速訪問 |
<Space> + s |
儲存快照 |
gvim/vim |
加載快照 |
詳細信息看《二:開始使用及支持功能和快捷鍵》
注意:
(1)在code目錄下經過vtags生成vtags.db後,第一次打開verilog code時須要編譯生成的database,因此第一打開code比較慢,以後打開code就會很是迅速。
1. 下載插件代碼,解壓並複製到自選的安裝路徑下。下面以安裝目錄爲「~/vtags-1.20/爲例」
代碼下載地址:(1)http://www.vim.org/scripts/script.php?script_id=5494
(2)http://bbs.eetop.cn/thread-620729-1-1.html
2. 在linux配置文件中添加別名。
~/.cshrc 中添加:alias vtags 'python ~/vtags-1.20/vtags.py'
或 ~/.bashrc 中添加:alias=vtags 'python ~/vtags-1.20/vtags.py'
source ~/.cshrc 或 source ~/.bashre 使設置生效。
3. 在vim配置文件中加入插件。
~/.vimrc 中添加: source ~/vtags-1.20/vtags_vim_api.vim
4. 本步驟可選,能夠在vtags-1.20/vim_glb_config.py中設置插件的一些全局設置,
你也能夠使用vtags時生成的局部配置文件vim_local_config.py中進行設置。
5. cd 到code目錄使用命令:vtags, 在code目錄下生成base文件 vtags.db, 用gvim打開代碼就能夠使用上面定義快捷鍵中功能。
注: 要求python版本2.7,詳情請看《用戶使用指南》。
""" https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== # left sidebar window width frame_window_width = 20 # right bottom report window height report_window_height = 8 # max work window vtags auto opened, not include use self opened window and holded window max_open_work_window_number = 1 # when use <Space><left>/<Space><right> the max number of history trace valid max_roll_trace_depth = 1000 # when <Space>c add check point, the max number of check point valid max_his_check_point_num = 10 # when gen the vtags database, in all verilog modules when some module called more then threshold times, # set this module to be base module, then show topo will not list it's inst one by one base_module_threshold = 200 # supported verilog postfix, we only add postfix in below to data base support_verilog_postfix = ['v'] # open debug module or not, open debug module will print a lot debug log at vtags.db debug_mode = False # when trace source, match bigger than TraceSourceOptimizingThreshold, open opt func, mainly for signal like clk,rst ... trace_source_optimizing_threshold = 20 # frame fold level space, use to set pre space num, if current level is 3 , # and fold level space is ' ', then current line pre space is ' '*3 = ' ' frame_fold_level_space = ' ' # weather show report or not show_report = True # weather show sidebar or not show_sidebar = True """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== __version__ = "1.20" __project_url__ = "https://my.oschina.net/u/2520885" import os import sys import re import pickle #print help help = '' try: help = sys.argv[1] except: pass if help in ['-h','-help']: print("(1) generate vtags at code dir, use command \"vtags\" ;" ) print("(2) config vtags vim at vtags gen dir \"/vtags.db/vim_local_config.py\"," ) print(" config items and detail look vim_local_config.py notes;" ) print("(3) support action in vim window:" ) print(" 1) gi : if cursor on module call, go in submodule;" ) print(" 2) gu : if cur module called before, go upper module;" ) print(" 3) <Space><Left> : trace cursor word signal source;" ) print(" 4) <Space><Right> : trace cursor word signal dest;" ) print(" 5) <Space><Down> : roll back;" ) print(" 6) <Space><Up> : go forward;" ) print(" 7) <Space>v : show current module topo " ) print(" or fold/unfold sidebar items;" ) print(" 8) <Space>c : add current cursor as checkpoint, can go back directly;" ) print(" 9) <Space>b : add current cursor module as basemodule, not show in topo;" ) print(" 10) <Space> : in sidebar or report win, just go cursor line link;" ) print(" 11) <Space>h : hold cursor win, will not auto close it;" ) print(" 12) <Space>d : in sidebar, delete valid items(base_module, checkpoint...);" ) print(" 13) <Space>s : save current vim snapshort," ) print(" use \"gvim/vim\" without input file to reload snapshort;" ) exit() def cur_file_dir(): path = sys.path[0] if os.path.isdir(path): return path elif os.path.isfile(path): return os.path.dirname(path) vtags_install_path = cur_file_dir() sys.path.insert(0,vtags_install_path) sed_vtags_install_path = re.sub('/','\/',vtags_install_path) os.system('sed -ig \'s/vtags_install_path =.*/vtags_install_path = "%s"/g\' %s/vtags_vim_api.vim' %(sed_vtags_install_path, vtags_install_path) ) os.system('sed -ig \'s/let is_vtags_installed =.*/let is_vtags_installed = 1/g\' %s/vtags_vim_api.vim' %(vtags_install_path) ) vtags_folder_path = os.getcwd() + '/vtags.db' os.system('mkdir -p %s'%(vtags_folder_path)) if os.path.isfile(vtags_folder_path + '/vtag_gen_log.txt'): os.system('rm -rf '+vtags_folder_path+'/vtag_gen_log.txt') import Lib.GLB as GLB G = GLB.G GLB.vtags_run_log_path[0] = vtags_folder_path + '/vtags_run.log' import Lib.Code as Code import Lib.View as View from Lib.Base import * # filelist: # use "//" as note sign # support dir_path and file path mix def get_all_verilog_files_from_filelist(filelist_path): verilog_file_paths = [] # get ~ path home_path = os.popen('echo ~').readlines()[0].rstrip('\n').rstrip('/') for l in open(filelist_path,'r').readlines(): l = l.strip('\n') l = re.sub('//.*','',l) l = re.sub('^~', home_path, l) if re.match('\s*$',l): continue path = l if os.path.isdir(path): c_files_path = os.popen('find ' + dir_path + ' -type f 2>/dev/null').readlines() c_files_path = [ d_l.rstrip('\n') for d_l in c_files_path ] for c_f in c_files_path: if get_file_path_postfix(c_f) not in G['SupportVerilogPostfix']: continue verilog_file_paths.append(c_f) if os.path.isfile(path): if get_file_path_postfix(path) not in G['SupportVerilogPostfix']: continue verilog_file_paths.append(path) return verilog_file_paths # get all verilog files inf and merge # modules_inf = { module_name: module_inf } # defines_inf = { macro_name : [ define_inf ] } # files_inf = { file_name : file_inf } # module_inf = { 'module_name' : module_name # ,'file_path' : f # ,'line_range_in_file' : (module_start_line_num, module_end_line_num) # ,'sub_modules' : sub_modules } # define_inf = { "name" : xxx # ,"path" : f # ,"pos" : (line_num, colum_num) # name first char pos # ,'code_line' : `define xxx .... } # file_inf = { 'glb_defines' : [ define_inf ] # ,'module_infs' : [ module_inf ] # ,'module_calls' : [ call_sub_inf ] # ,'file_edit_inf' : { 'create_time': ..., 'last_modify_time': ...} # call_sub_inf = { 'inst_name' : inst_name # ,'module_name' : modu_name # ,'match_range' : match_range } def get_verilog_files_code_inf(paths): # step 1/2 get all module/define inf all_file_module_inf = {} all_file_define_inf = {} all_module_name = set() print('step 1/2:') for i,f in enumerate(paths): show_progress_bar( i, len(paths)) PrintDebug(f) # gen cur module and define inf cur_file_module_inf = get_single_verilog_file_module_inf(f) cur_file_define_inf = get_single_verilog_file_define_inf(f) # add to result all_file_module_inf[f] = cur_file_module_inf all_file_define_inf[f] = cur_file_define_inf all_module_name = all_module_name | set([ mi['module_name'] for mi in cur_file_module_inf]) print('') # step 2/2 get all file sub call inf all_file_subcall_inf = {} patten = get_submodule_match_patten(all_module_name) print('step 2/2:') for i,f in enumerate(paths): PrintDebug(f) show_progress_bar( i, len(paths)) all_file_subcall_inf[f] = get_single_verilog_file_subcall_inf(f, patten, all_module_name) print('') # merge to all_file_inf all_file_inf = {} for i,f in enumerate(paths): add_single_verilog_file_submodule_inf_to_module_inf( all_file_module_inf[f], all_file_subcall_inf[f] ) all_file_inf[f] = { 'glb_defines' : all_file_define_inf[f] ,'module_infs' : all_file_module_inf[f] ,'module_calls' : all_file_subcall_inf[f] ,'file_edit_inf' : { 'create_time': os.path.getctime(f), 'last_modify_time': os.path.getmtime(f)} } modules_inf , global_defines_inf = gen_modules_and_defines_inf(all_file_inf) return { 'files_inf' : all_file_inf ,'modules_inf' : modules_inf ,'defines_inf' : global_defines_inf } #------------------------function for get module inf-------------------- filelist_path = '' verilog_file_paths = [] if filelist_path: verilog_file_paths = get_all_verilog_files_from_filelist(filelist_path) else: c_dir_path = os.getcwd() c_dir_files_path = os.popen('find ' + c_dir_path + ' -type f 2>/dev/null').readlines() c_dir_files_path = [ d_l.rstrip('\n') for d_l in c_dir_files_path ] for c_f in c_dir_files_path: if get_file_path_postfix(c_f) not in G['SupportVerilogPostfix']: continue verilog_file_paths.append(c_f) # get all code inf verilog_code_inf = get_verilog_files_code_inf(verilog_file_paths) modules_inf = verilog_code_inf['modules_inf'] files_inf = verilog_code_inf['files_inf' ] defines_inf = verilog_code_inf['defines_inf'] # set base module base_modules = set() base_threshold = G['BaseModuleInf']['BaseModuleThreshold'] module_inst_num = {} for m in modules_inf: for sm in modules_inf[m]['sub_modules']: module_name = sm['module_name'] module_inst_num.setdefault(module_name,0) module_inst_num[module_name] += 1 for m in module_inst_num: if module_inst_num[m] >= base_threshold: base_modules.add(m) # change vim HDLTags path fp = open(vtags_folder_path + '/files_inf.py','w') fp.write('FileInf = %s \n'%(files_inf.__str__())) fp.write('HDLTagsActive = True \n') fp.close() if not os.path.isfile(vtags_folder_path + '/vim_local_config.py'): os.system('cp %s/vim_glb_config.py %s/vim_local_config.py'%(vtags_install_path, vtags_folder_path)) if not os.path.isfile(vtags_folder_path+'/base_modules.pkl'): output = open(vtags_folder_path+'/base_modules.pkl','wb') pickle.dump(base_modules, output) output.close() """ " https://my.oschina.net/u/2520885 """ "=============================================================================== " Copyright (C) 2016 by Jun Cao " Permission is hereby granted, free of charge, to any person obtaining a copy " of this software and associated documentation files (the "Software"), to deal " in the Software without restriction, including without limitation the rights " to use, copy, modify, merge, publish, distribute, sublicense, and/or sell " copies of the Software, and to permit persons to whom the Software is " furnished to do so, subject to the following conditions: " The above copyright notice and this permission notice shall be included in " all copies or substantial portions of the Software. " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR " IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, " FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE " AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN " THE SOFTWARE. "=============================================================================== function! VimPythonExtend() python << EOF import os import sys vtags_install_path = "/mnt/hgfs/VMShare/my_tools/vtags-1.20" if os.path.isdir(vtags_install_path): sys.path.insert(0,vtags_install_path) from Lib.API import * EOF endfunction let is_vtags_installed = 1 if is_vtags_installed == 1 "vi_HDLTags_begin----------------------------------- call VimPythonExtend() map gi :py try_go_into_submodule() <CR> map gu :py try_go_upper_module() <CR> map <Space><Left> :py try_trace_signal_sources() <CR> map <Space><Right> :py try_trace_signal_destinations() <CR> map <Space><Down> :py try_roll_back() <CR> map <Space><Up> :py try_go_forward() <CR> map <Space>v :py try_show_frame() <CR> map <Space>c :py try_add_check_point() <CR> map <Space>b :py try_add_base_module() <CR> map <Space> :py try_space_operation() <CR> map <Space>h :py try_hold_current_win() <CR> map <Space>d :py try_del_operation() <CR> map <Space>s :py try_save_env_snapshort() <CR> "vi_HDLTags_end------------------------------------- endif """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== import os import sys # import vim, when gen vtags it will no vim,so use try try: import vim except: pass # import normal lib import re import Lib.Code as Code import Lib.View as View PrintReport = View.PrintReport import Lib.GLB as GLB G = GLB.G from Lib.Base import * # init gen module_inf, and glb define if G['HDLTagsActive']: G['ModuleInf'], G['CodeDefineInf'] = gen_modules_and_defines_inf(G['FileInf']) # open snapshort wins if G['HDLTagsActive'] and G['EnvSnapshortWinsInf']: OldOpenWinTrace = [p for p in G['WorkWin_Inf']['OpenWinTrace']] G['WorkWin_Inf']['OpenWinTrace'].insert(0,vim.current.buffer.name) for w_inf in G['EnvSnapshortWinsInf']: c_path = w_inf['path'] c_cursor = w_inf['cursor'] if os.path.isfile(c_path): View.Open(c_path) if c_path not in OldOpenWinTrace: if G['WorkWin_Inf']['OpenWinTrace'] and G['WorkWin_Inf']['OpenWinTrace'][-1] == c_path: del G['WorkWin_Inf']['OpenWinTrace'][-1] else: PrintDebug('Warning: reload file not exit ! file: %s'%(c_path)) for w_inf in G['EnvSnapshortWinsInf']: c_size = w_inf['size'] c_path = w_inf['path'] if os.path.isfile(c_path): View.Open(c_path) vim.current.window.width = c_size[0] vim.current.window.height = c_size[1] # because base module may be changed so refresh topo and show base if G['Frame_Inf']['Frame_Path'] in [ w.buffer.name for w in vim.windows]: View.refresh_topo() View.show_base_module() PrintReport('reload snapshort finish !') elif G['HDLTagsActive']: # treat the first win as work win , if cur win is hdl code, and add first trace point first_cursor_inf = View.get_cur_cursor_inf() if first_cursor_inf['hdl_type'] == 'verilog': G['WorkWin_Inf']['OpenWinTrace'].append(first_cursor_inf['file_path']) View.add_trace_point() PrintDebug('Point: initial new env finish !') # shortcut key: gi def go_into_submodule(): cursor_inf = View.get_cur_cursor_inf() cur_module_inf = cursor_inf['cur_module_inf'] if not cur_module_inf: PrintReport('Warning: cur cursor not in a valid module, no submodule call !') return call_module_name = cur_module_inf['module_name'] sub_call_inf = Code.get_module_call_sub_module_io_inf(cursor_inf['line'], cursor_inf['pos'], cursor_inf['file_path']) if not sub_call_inf: PrintReport('Warning: cur cursor not on recgnized subcall !') return sub_module_name = sub_call_inf['sub_module_name'] sub_module_inf = get_module_inf(sub_module_name) if not sub_module_inf: PrintReport('Warning: sub module %s no module inf in database !'%(sub_module_name)) return sub_signal_name = sub_call_inf['sub_io_name'] sub_match_pos = [] if sub_signal_name: sub_match_pos = sub_call_inf['sub_match_pos'] else: sub_signal_name = sub_module_name sub_match_pos = sub_module_inf['module_pos'] call_sub_inf = sub_call_inf['call_sub_inf'] # GLB call sub inf(atom) sub_module_path = sub_module_inf['file_path'] set_module_last_call_inf(sub_module_name, call_module_name, call_sub_inf['inst_name']) View.add_trace_point() View.go_win( sub_module_path, sub_match_pos, sub_signal_name) def try_go_into_submodule(): if not G['HDLTagsActive']: return if G['Debug']: go_into_submodule() else: try: go_into_submodule() except: pass # shortcut key: gu def go_upper_module(): cursor_inf = View.get_cur_cursor_inf() cur_module_inf = cursor_inf['cur_module_inf'] if not cur_module_inf: PrintReport('Warning: cur line not in a valid verilog module, or current module not in database !') return cur_last_call_inf = get_module_last_call_inf(cur_module_inf['module_name']) if not cur_last_call_inf: PrintReport('Warning: cur module %s not called by upper module before !'%(cur_module_inf['module_name'])) return upper_module_name = cur_last_call_inf['upper_module_name'] upper_call_sub_inf = cur_last_call_inf['upper_call_inf'] upper_match_pos = upper_call_sub_inf['match_pos'] upper_inst_name = upper_call_sub_inf['inst_name'] View.add_trace_point() View.go_win( upper_module_name, upper_match_pos, upper_inst_name) def try_go_upper_module(): if not G['HDLTagsActive']: return if G['Debug']: go_upper_module() else: try: go_upper_module() except: pass # shortcut key: <Space><Left> def trace_signal_sources(): if G['IgnoreNextSpaceOp']: G['IgnoreNextSpaceOp'] = False PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !') return cursor_inf = View.get_cur_cursor_inf() trace_signal_name = cursor_inf['word'] if not trace_signal_name: PrintReport("Warning: Current cursor not on signal name, can not trace source !") return # case0: if cur cursor on a macro, go macro define if Code.trace_glb_define_signal('source', cursor_inf): return # case1: if cur cursor on io signal, need cross to upper module if Code.trace_io_signal('source', cursor_inf): return # case2: if cur cursor on module call io line go to submodule io if Code.trace_module_call_io_signal('source', cursor_inf): return # case3: trace signal same as pre trace signal, just show next result if (G['TraceInf']['LastTraceSource']['Path'] == cursor_inf['file_path']) and (G['TraceInf']['LastTraceSource']['SignalName'] == trace_signal_name) : View.show_next_trace_result('source') return # case4: trace a new normal(not io, sub call io) signal if Code.trace_normal_signal('source', cursor_inf): return def try_trace_signal_sources(): if not G['HDLTagsActive']: return if G['Debug']: trace_signal_sources() else: try: trace_signal_sources() except: pass # shortcut key: <Space><Right> def trace_signal_destinations(): if G['IgnoreNextSpaceOp']: G['IgnoreNextSpaceOp'] = False PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !') return cursor_inf = View.get_cur_cursor_inf() trace_signal_name = cursor_inf['word'] if not trace_signal_name: PrintReport("Warning: Current cursor not on signal name, can not trace dest!") return # case0: if cur cursor on io signal, need cross to upper module if Code.trace_io_signal('dest', cursor_inf): return # case1: if cur cursor on module call io line go to submodule io if Code.trace_module_call_io_signal('dest', cursor_inf): return # case2: trace signal same as pre trace signal, just show next result if (G['TraceInf']['LastTraceDest']['Path'] == cursor_inf['file_path']) and (G['TraceInf']['LastTraceDest']['SignalName'] == trace_signal_name) : View.show_next_trace_result('dest') return # case3: if cur cursor on a macro, go macro define if Code.trace_glb_define_signal('dest', cursor_inf): return # case4: trace a new normal(not io, sub call io) signal Code.trace_normal_signal('dest', cursor_inf) def try_trace_signal_destinations(): if not G['HDLTagsActive']: return if G['Debug']: trace_signal_destinations() else: try: trace_signal_destinations() except: pass # shortcut key: <Space><Down> def roll_back(): if G['IgnoreNextSpaceOp']: G['IgnoreNextSpaceOp'] = False PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !') return cur_nonius = G['OpTraceInf']['Nonius'] - 1 TracePoints = G['OpTraceInf']['TracePoints'] # if reach to the oldest trace point just return if cur_nonius < 0: PrintReport("Warning: roll backed to the oldest trace point now !") return # go to the trace point cur_point = TracePoints[cur_nonius] G['OpTraceInf']['Nonius'] = cur_nonius View.go_win( cur_point['path'], cur_point['pos'], cur_point['key']) return def try_roll_back(): if not G['HDLTagsActive']: return if G['Debug']: roll_back() else: try: roll_back() except: pass # shortcut key: <Space><Up> def go_forward(): if G['IgnoreNextSpaceOp']: G['IgnoreNextSpaceOp'] = False PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !') return cur_nonius = G['OpTraceInf']['Nonius'] + 1 TracePoints = G['OpTraceInf']['TracePoints'] if cur_nonius >= len(TracePoints): PrintReport("Warning: go forward to the newest trace point now !") return cur_point = TracePoints[cur_nonius] G['OpTraceInf']['Nonius'] = cur_nonius View.go_win( cur_point['path'], cur_point['pos'], cur_point['key']) return def try_go_forward(): if not G['HDLTagsActive']: return if G['Debug']: go_forward() else: try: go_forward() except: pass # shortcut key: <space> def space_operation(): if G['IgnoreNextSpaceOp']: G['IgnoreNextSpaceOp'] = False PrintDebug('Care: not do this trace source op ,bucause <space> is come from unknow reason !') return cursor_inf = View.get_cur_cursor_inf() # if cur in Frame or Report, show file link files if cursor_inf['file_path'] in [ G['Frame_Inf']['Frame_Path'], G['Report_Inf']['Report_Path'] ]: cur_frame_link = G['VimBufferLineFileLink'][cursor_inf['file_path']][cursor_inf['line_num']] View.add_trace_point() if cur_frame_link and cur_frame_link['path']: View.go_win( cur_frame_link['path'], cur_frame_link['pos'], cur_frame_link['key']) View.add_trace_point() else: PrintReport('Warning: No file link in current line ! ') else: PrintReport('Warning: No space operation in current file ! ') def try_space_operation(): if not G['HDLTagsActive']: return if G['Debug']: space_operation() else: try: space_operation() except: pass # shortcut key: <s-t> def show_frame(): G["IgnoreNextSpaceOp"] = G['FixExtraSpace'] if cur_in_frame(): cursor_line = vim.current.window.cursor[0] - 1 View.frame_line_fold_operation(cursor_line) else: View.show_topo() View.show_check_point(False) View.show_base_module(False) return def try_show_frame(): if not G['HDLTagsActive']: return if G['Debug']: show_frame() else: try: show_frame() except: pass return # shortcut key: <Space>h def hold_current_win(): cur_path = vim.current.buffer.name # just del current win frome work win, then will not auto close current win for i,path in enumerate(G['WorkWin_Inf']['OpenWinTrace']): if cur_path == path: del G['WorkWin_Inf']['OpenWinTrace'][i] break def try_hold_current_win(): if not G['HDLTagsActive']: return if G['Debug']: hold_current_win() else: try: hold_current_win() except: pass # shortcut key: <Space>c def add_check_point(): G["IgnoreNextSpaceOp"] = G['FixExtraSpace'] cursor_inf = View.get_cur_cursor_inf() level = G['CheckPointInf']['TopFoldLevel'] + 1 key = G['Frame_Inf']['FoldLevelSpace']*level + cursor_inf['word'] link = { 'type' : 'check_point' ,'key' : cursor_inf['word'] ,'pos' : cursor_inf['pos'] ,'path' : cursor_inf['file_path'] ,'fold_inf' : { 'fold_status': 'fix', 'level': level } } G['CheckPointInf']['CheckPoints'].insert(0, {'key': key, 'link': link }) if len(G['CheckPointInf']['CheckPoints']) > G['CheckPointInf']['MaxNum']: del G['CheckPointInf']['CheckPoints'][-1] View.show_check_point() def try_add_check_point(): if not G['HDLTagsActive']: return if G['Debug']: add_check_point() else: try: add_check_point() except: pass # shortcut key: <Space>b def add_base_module(): G["IgnoreNextSpaceOp"] = G['FixExtraSpace'] cursor_inf = View.get_cur_cursor_inf() cursor_module = cursor_inf['word'] if not cursor_module: PrintReport('Warning: cursor not on a valid word ! ') return if not get_module_inf(cursor_module): PrintReport('Warning: cursor words: %s not a recgnized module name ! will no file link ! '%(cursor_module)) if cursor_module in G['BaseModuleInf']['BaseModules']: PrintReport('Care: module %s is already base module ! '%(cursor_module)) return G['BaseModuleInf']['BaseModules'].add(cursor_module) update_base_module_pickle() View.show_base_module() View.refresh_topo() def try_add_base_module(): if not G['HDLTagsActive']: return if G['Debug']: add_base_module() else: try: add_base_module() except: pass #------------------------------ # shortcut key: <Space>d def del_operation(): if not cur_in_frame(): PrintReport('Warning: Cur file no del function ! ') return cur_path = vim.current.buffer.name cur_line_num = vim.current.window.cursor[0] - 1 cur_file_link = G['VimBufferLineFileLink'][cur_path][cur_line_num] if not cur_file_link: PrintReport('Warning: Cur line no del function ! ') return # delete a check point, if link has path means a valid link if (cur_file_link['type'] == 'check_point') and (cur_file_link['fold_inf']['level'] > G['CheckPointInf']['TopFoldLevel']): G["IgnoreNextSpaceOp"] = G['FixExtraSpace'] check_point_begin_line_num = get_frame_range_inf()['check_point_range'][0] del_index = cur_line_num - check_point_begin_line_num - 1 del G['CheckPointInf']['CheckPoints'][ del_index ] View.show_check_point() return # del a base module if (cur_file_link['type'] == 'base_module') and (cur_file_link['fold_inf']['level'] > G['BaseModuleInf']['TopFoldLevel']): G["IgnoreNextSpaceOp"] = G['FixExtraSpace'] G['BaseModuleInf']['BaseModules'].remove(cur_file_link['key']) update_base_module_pickle() View.show_base_module() View.refresh_topo() return PrintReport('Warning: Cur line no del function ! ') def try_del_operation(): if not G['HDLTagsActive']: return if G['Debug']: del_operation() else: try: del_operation() except: pass #---------------------------------------- # shortcut key: <Space>s def try_save_env_snapshort(): if not G['HDLTagsActive']: return if G['Debug']: if G['SaveEnvSnapshort_F'](): PrintReport('save env snapshort success !') else: try: if G['SaveEnvSnapshort_F'](): PrintReport('save env snapshort success !') except: pass """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== import sys try: import vim except: pass import os import re import pickle import GLB G = GLB.G # function to print debug PrintDebug = G['PrintDebug_F'] def get_valid_code( str ): str = re.sub('(^\s*)|(\s*$)', '' ,str) str = re.sub('//.*', '' ,str) str = re.sub('^`.*', '' ,str) # bug ^\s*`.* return str def get_valid_code_leave_head_space( str ): str = re.sub('\s*$', '' ,str) str = re.sub('//.*', '' ,str) str = re.sub('^`.*', '' ,str) return str def cur_in_frame(): return vim.current.buffer.name == G['Frame_Inf']['Frame_Path'] def cur_in_report(): return vim.current.buffer.name == G['Report_Inf']['Report_Path'] def get_path_for_name(path_or_name): if path_or_name == 'Frame': return G["Frame_Inf"]["Frame_Path"] if path_or_name == 'Report': return G["Report_Inf"]["Report_Path"] may_module_inf = get_module_inf(path_or_name) if may_module_inf: return may_module_inf['file_path'] return path_or_name def get_file_name_from_path(path): return re.sub('.*/','',path) def get_full_word(line, y): pre_part = ( re.match('^(?P<pre>\w*)',(line[:y])[::-1]).group('pre') )[::-1] post_part = re.match('^(?P<post>\w*)', line[y:]).group('post') return pre_part + post_part def get_file_path_postfix(file_path): if type(file_path) != str: return split_by_dot = file_path.split('.') if len(split_by_dot) < 2 : # which means file_path has no postfix return '' # post_fix = split_by_dot[-1].lower() # postfix don't care case post_fix = split_by_dot[-1] # postfix care case return post_fix def get_file_hdl_type(file_path): postfix = get_file_path_postfix(file_path) if postfix in G['SupportVHDLPostfix']: return 'vhdl' elif postfix in G['SupportVerilogPostfix']: return 'verilog' else: return '' #------------------------------------------------------------ def get_vhdl_full_line(codes, start_pos, direction): pass def get_verilog_pre_full_line(codes, start_pos): pre_full_line = '' start_x, start_y = start_pos start_line = codes[start_x][:start_y+1] start_line = start_line.strip('\n') start_line = re.sub('//.*','',start_line) colon_y = start_line.rfind(';') if colon_y != -1: pre_full_line = start_line[colon_y+1:] else: pre_full_line = start_line for i in range(start_x-1,-1,-1): t_line = codes[i].strip('\n') t_line = re.sub('//.*', '', t_line) t_colon_y = t_line.rfind(';') if t_colon_y != -1: pre_full_line = t_line[t_colon_y+1:] + ' ' + pre_full_line break else: pre_full_line = t_line + ' ' +pre_full_line return pre_full_line def get_verilog_post_full_line(codes, start_pos): post_full_line = '' start_x, start_y = start_pos start_line = codes[start_x][start_y:] start_line = start_line.strip('\n') start_line = re.sub('//.*','',start_line) colon_y = start_line.find(';') if colon_y != -1: pre_full_line = start_line[:colon_y+1] else: pre_full_line = start_line for i in range(start_x+1,len(codes)): t_line = codes[i].strip('\n') t_line = re.sub('//.*', '', t_line) t_colon_y = t_line.find(';') if t_colon_y != -1: pre_full_line = pre_full_line + ' ' + t_line[: t_colon_y+1] break else: pre_full_line = pre_full_line + ' ' + t_line return pre_full_line def get_verilog_full_line(codes, start_pos, direction): if direction == -1: # 0 <- x return get_verilog_pre_full_line(codes, start_pos) elif direction == 1: # x -> n return get_verilog_post_full_line(codes, start_pos) elif direction == 0: # 0 <- x -> n return get_verilog_pre_full_line(codes, start_pos) + get_verilog_post_full_line(codes, start_pos)[1:] # [1:] because start char at both part else: return '' def get_full_line( codes, hdl_type, start_pos, direction = 0): if hdl_type == 'vhdl': return get_vhdl_full_line(codes, start_pos, direction) elif hdl_type == 'verilog': return get_verilog_full_line(codes, start_pos, direction) else: return '' # -------------------------------------------------------- # ok def recgnize_io_signal_line(line, line_num): # pre check if is not io if line.find('input') == -1 and line.find('output') == -1: return False line = line.strip('\n') line = re.sub('//.*','',line) # del notes # raw re match re_match = re.match('\s*(input|output)\W',line) if not re_match: re_match = re.match('(?P<prefix>.*\(\s*)(?P<real_io>(input|output)\W.*)',line) if re_match: prefix = re_match.group('prefix') real_io_line = re_match.group('real_io') line = ' '*(len(prefix)) + real_io_line else: return False # match used egrep io line decode function egrep_io_line = str(line_num)+':'+line io_inf = decode_egreped_verilog_io_line(egrep_io_line)['io_infs'] return io_inf # "name" : name # , "io_type" : io_type # , "left" : left_index # , "right" : right_index # , "size" : size # , 'line_num' : line_num # , 'name_pos' : (line_num, colm_num) # , 'code_line' : code_line # , 'signal_type' : signal_type } #----------------------------------------------------------- # ok def search_verilog_code_use_grep(key, path, row_range = ()): search_result = [] if not path: path = vim.current.buffer.name match_lines = os.popen('egrep -n -h \'(^|\W)%s(\W|$)\' %s'%(key, path)).readlines() for l in match_lines: l = l.strip('\n') split0 = l.split(':') line_num = int(split0[0]) - 1 code_line = ':'.join(split0[1:]) if row_range and ( line_num not in range(row_range[0], row_range[1]+1 ) ): continue # del note see if has key s0 = re.search('(?P<pre>^|\W)%s(\W|$)'%(key), re.sub('//.*','',code_line) ) if s0: colum_num = s0.span()[0] + len(s0.group('pre')) match_pos = (line_num, colum_num) line = code_line search_result.append( (match_pos, line) ) return search_result #---------------------------------------------------------- def get_fram_topo_sub_inf(topo_module, cur_level): sub_level = cur_level + 1 topo_prefix = G['Frame_Inf']['FoldLevelSpace'] * sub_level topo_datas = [] topo_links = [] sub_func_modules, sub_base_modules = get_sub_func_base_module(topo_module) # first deal sub func module, show "inst(module)" sub_func_modules_inst_names = list(sub_func_modules) sub_func_modules_inst_names.sort() for c_sub_inst_name in sub_func_modules_inst_names: c_call_sub_inf = sub_func_modules[c_sub_inst_name] c_sub_module_name = c_call_sub_inf['module_name'] # gen show data c_str = '%s%s(%s)'%(topo_prefix, c_sub_inst_name, c_sub_module_name) topo_datas.append(c_str) # gen link c_topo_link = { 'type' : 'topo' ,'topo_inst_name' : '' ,'key' : '' ,'pos' : '' ,'path' : '' ,'fold_inf' : {'fold_status':'off', 'level': sub_level} } c_sub_module_inf = get_module_inf(c_sub_module_name) if c_sub_module_inf: c_topo_link['topo_inst_name'] = c_sub_inst_name c_topo_link['key' ] = c_sub_module_name c_topo_link['pos' ] = c_sub_module_inf['module_pos'] c_topo_link['path' ] = c_sub_module_inf['file_path'] # show cur module, then all submodule, last call set to cur module set_module_last_call_inf(c_sub_module_name, topo_module, c_call_sub_inf['inst_name']) topo_links.append(c_topo_link) sub_base_modules_names = list(sub_base_modules) sub_base_modules_names.sort() if len(sub_base_modules_names) > 0: # deal base , show "module(n)" # add one to sep func and base topo_datas.append(topo_prefix+'------') c_topo_link = { 'type' : 'topo' ,'topo_inst_name' : '' ,'key' : '' ,'pos' : () ,'path' : '' ,'fold_inf' : {'fold_status':'on', 'level': sub_level} } topo_links.append(c_topo_link) for c_sub_module_name in sub_base_modules_names: # deal data c_sub_inst_n = len(sub_base_modules[c_sub_module_name]) c_str = '%s%s(%d)'%(topo_prefix,c_sub_module_name,c_sub_inst_n) topo_datas.append(c_str) # deal link c_topo_link = { 'type' : 'topo' ,'topo_inst_name' : '' ,'key' : '' ,'pos' : '' ,'path' : '' ,'fold_inf' : {'fold_status':'off', 'level': sub_level} } c_sub_module_inf = get_module_inf(c_sub_module_name) if c_sub_module_inf: c_topo_link['key' ] = c_sub_module_name c_topo_link['pos' ] = c_sub_module_inf['module_pos'] c_topo_link['path'] = c_sub_module_inf['file_path'] topo_links.append(c_topo_link) return topo_datas, topo_links def get_fram_check_point_inf(): datas = [] links = [] for cp in G['CheckPointInf']['CheckPoints']: datas.append(cp['key']) links.append(cp['link']) return datas, links def get_fram_base_module_inf(): datas = [] links = [] base_module_level = G['BaseModuleInf']['TopFoldLevel'] + 1 base_module_space = G['Frame_Inf']['FoldLevelSpace'] * base_module_level base_modules = list(G['BaseModuleInf']['BaseModules']) base_modules.sort() for bm in base_modules: key = base_module_space + bm link = { 'type' : 'base_module' ,'key' : bm ,'pos' : '' ,'path' : '' ,'fold_inf' : { 'fold_status': 'fix', 'level': base_module_level } } bm_module_inf = get_module_inf(bm) if bm_module_inf: link['pos'] = bm_module_inf['module_pos'] link['path'] = bm_module_inf['file_path'] datas.append(key) links.append(link) return datas, links ########################################################### #---------------------------------------------------------- def decode_egreped_verilog_io_line(o_io_line): # exp: # 365:output alu_frf_part_p0_w; # 366:output [127:0] alu_frf_data_p0_w; # 357:output [THR_WIDTH-1:0] alu_dst_cond_tid_w # 368:output reg alu_frf_part_p0_w; # 369:output wire [127:0] alu_frf_data_p0_w; # 370:output reg [THR_WIDTH-1:0] alu_dst_cond_tid_w # 388:input [width-1 : 0] A,B; # split by ":" | 388:input [width-1 : 0] A,B; # split0 | 0 ^ 1 ^ 2 split0 = o_io_line.split(':') line_num = int(split0[0]) - 1 # -1 because egrep form 1, our line from 0 code_line = ':'.join(split0[1:]) # valid code line is code_line del note, and change all \s+ to ' ' valid_code_line = re.sub('(//.*)|(^\s+)|(\s+$)','',code_line) valid_code_line = re.sub('\s+',' ',valid_code_line) valid_code_line = re.sub('\W*$', '',valid_code_line)# del end ";" or "," # io type is the first word in valid_code_line match_io_type = re.match('(?P<io_type>\w+)\s*(?P<other>.*)',valid_code_line) assert(match_io_type) io_type = match_io_type.group('io_type') other = match_io_type.group('other').strip(' ') # other: [width-1 : 0] A,B | wire [127:0] alu_frf_data_p0_w | alu_frf_part_p0_w # get name, name is the last word or words sep by ',' ; reverse it and reverse back # exp: A | A,B | A,B,C match_name = re.match('\s*(?P<r_names_str>\w+(\s*,\s*\w+)*)\s*(?P<r_other>.*)',other[::-1]) assert(match_name),'%s | %s'%(other,code_line) other = (match_name.group('r_other')[::-1]).strip(' ') names_str = match_name.group('r_names_str')[::-1] names = re.sub('\s+','',names_str).split(',') names_pos = [] if len(names) == 1: colum = re.search('\W%s(\W|$)'%(names[0]),code_line).span()[0] + 1 names_pos = [ ( line_num, colum ) ] else: for n in names: colum = re.search('\W%s(\W|$)'%(n),code_line).span()[0] + 1 names_pos.append( (line_num, colum) ) # signal_type is the first word of other, maybe empty # case0 : empty # case1 : reg # case2 : reg [THR_WIDTH-1:0] # case3 : [127:0] signal_type = 'wire' if other: match_signal_type = re.match('\s*(?P<signal_type>\w*)\s*(?P<other>.*)',other) assert(match_signal_type) m_signal_type = match_signal_type.group('signal_type') if m_signal_type: signal_type = m_signal_type other = match_signal_type.group('other').strip(' ') # other is empty or [a : b] left_index = '' right_index = '' size = 1 if other: assert(other[0] == '[' and other[-1] == ']'),'%s'%(other) indexs = other[1:-1].split(':') if len(indexs) == 2: left_index = indexs[0].strip(' ') right_index = indexs[1].strip(' ') try: left_index = int(left_index) right_index = int(left_index) size = right_index - left_index + 1 except: size = other # may a line has mulity names io_infs = {} for i, name in enumerate(names): io_infs[name] = { "name" : name , "io_type" : io_type , "left" : left_index , "right" : right_index , "size" : size , 'line_num' : line_num , 'name_pos' : names_pos[i] , 'code_line' : code_line , 'signal_type' : signal_type } return {'io_infs':io_infs, 'name_list':names} #------------------------------------------------ # for code in verilog modules, from pos to find next pair ")" # case 0: # if pos is "(" | ( A...B ) # pos | ^ # rest | parm_line= A...B, end_pos = B 's pos # case 1: # if pos not "("| ( A...B ) # pos | ^ # rest | parm_line= A...B, end_pos = B 's pos def get_str_to_next_right_bracket(module_lines, pos): assert(0),'not used not realized ' def get_str_to_pre_left_bracket(module_lines, pos): assert(0),'not used not realized ' #------------------------------------------- # for situation: # case0 : module_name inst_name (.a(A), .b(B), .c(C)) | # | ^ | input pos # | ^0 ^1 | module_range[0] # case1 : module_name #( .a(A), .b(B), .c(C) ) inst_name ( ... ) # | ^ | input pos # | ^ | module_range[0] # case2 : module_name #( A, B, C ) inst_name ( .x(X), .y(Y) ) # | ^ | input pos # | ^ | module_range[0] # case3 : module_name ... inst_name[a:b] ... # case4 : module_name ... inst_name[a:b] (A,B,C) def get_verilog_sub_module_inf_from_dot_line( pos, module_lines, module_start_line_num): dot_line = get_valid_code(module_lines[pos[0]]) assert(dot_line[pos[1]] == '.') module_name = '' inst_name = '' match_range = [] match_pos = () # first deal pre dot line pre_line_end = False dot_pre_line = dot_line[:pos[1]+1] # module_name inst_name (. pre_next_line_num = pos[0] - 1 search_case0 = '' search_case12 = '' while not pre_line_end: semicolon_y = dot_pre_line.find(';') if semicolon_y != -1: pre_line_end = True dot_pre_line = dot_pre_line[semicolon_y + 1:] search_case0 = re.search('(^|\W)(?P<m_name>\w+)\s+(?P<i_name>\w+(\s*\[[^\[\]]*\])?)\s*\(\s*\.$',dot_pre_line) if search_case0: module_name = search_case0.group('m_name') inst_name = search_case0.group('i_name') break search_case12 = re.search('(^|\W)(?P<m_name>\w+)\s*#\s*\(', dot_pre_line) if search_case12: module_name = search_case12.group('m_name') match_case2_inst_name = re.match('\.\s*\(\s*(?P<r_i_name>(\s*\][^\[\]]*\[\s*)?\w+)',dot_pre_line[::-1]) # inst_name ( . if match_case2_inst_name: inst_name = match_case2_inst_name.group('r_i_name')[::-1] break if pre_next_line_num >= 0: dot_pre_line = get_valid_code(module_lines[pre_next_line_num]) + ' ' + dot_pre_line pre_next_line_num -= 1 else: pre_line_end = True # if not match anyone then unrecgize if not (search_case0 or search_case12): PrintDebug('Error: 0 cur dot match cannot recgnize ! line: %s , pos: %s'%(dot_line, pos.__str__())) return False # if no inst name need decode dot back line if not inst_name: # case1: module_name #( .a(A), .b(B), .c(C) ) inst_name ( ... ) back_line_end = False dot_back_line = dot_line[pos[1]:] # .a(A), .b(B), .c(C)) back_next_line_num = pos[0] + 1 search_case1_inst_name = '' while not back_line_end: semicolon_y = dot_back_line.find(';') if semicolon_y != -1: back_line_end = True dot_back_line = dot_back_line[:semicolon_y] # inst_name ( .x search_case1_inst_name = re.search('\)\s*(?P<i_name>\w+(\s*\[[^\[\]]*\])?)\s*\(',dot_back_line) if search_case1_inst_name: inst_name = search_case1_inst_name.group('i_name') break if back_next_line_num < len(module_lines): dot_back_line = dot_back_line + ' ' +get_valid_code(module_lines[back_next_line_num]) back_next_line_num += 1 else: back_line_end = True if not inst_name: PrintDebug('Error: 1 cur dot match cannot recgnize inst name ! line: %s , pos: %s'%(dot_line, pos.__str__())) return False match_range = [ pre_next_line_num + 1 + module_start_line_num, -1 ] module_y = module_lines[pre_next_line_num + 1].find(module_name) assert(module_y != -1) match_pos = ( pre_next_line_num + 1 + module_start_line_num, module_y ) return { 'inst_name' : inst_name ,'module_name' : module_name ,'match_range' : match_range ,'match_pos' : match_pos } # case 0: dff # (...) my_dff(a, b, c); in only one line def get_verilog_sub_module_inf_from_pound_line( pos, module_lines, module_start_line_num): pound_line = get_valid_code(module_lines[pos[0]]) match_sub = re.match('\s*(?P<module_name>\w+)\s+#\s*\(.*\)\s*(?P<inst_name>\w+)\s*\(.*\)\s*;\s*', pound_line) if match_sub: return { 'inst_name' : match_sub.group('inst_name') ,'module_name' : match_sub.group('module_name') ,'match_range' : [ pos[0] + module_start_line_num, pos[0] + module_start_line_num ] ,'match_pos' : ( pos[0] + module_start_line_num, module_lines[pos[0]].find(match_sub.group('module_name')) ) } return False # for current valid module lines # find each pair : (".xxx(...)" ";") # get the each pair result :{ 'inst_name' : inst_name # ,'module_name' : modu_name # ,'match_range' : match_range # ,'match_pos' : match_pos} # finial result is : [ pair_result0, pair_result1, ... ] def get_verilog_sub_module_inf(module_lines, module_start_line_num, gen_vtags_log_path = ''): sub_module_inf = [] has_call_sub_not_end = False find_next = True for i ,l in enumerate(module_lines): if find_next: assert(not has_call_sub_not_end),'already start new search, should not has unfinish subcall' cur_sub_module_inf = {} cur_match_right_part = '' if l.find('.') != -1: l = get_valid_code(l) s0 = re.search('(^|\W)\.\w+\s*\(', l) if not s0: continue # no matter recgnize or not , must wait next ";", continue search find_next = False # get dot pos dot_colm = '' if l[0] is '.': dot_colm = 0 else: dot_colm = s0.span()[0] + 1 assert(dot_colm != '') cur_match_right_part = l[s0.span()[1]:] # get cur sub module inf cur_sub_module_inf = get_verilog_sub_module_inf_from_dot_line( (i, dot_colm), module_lines, module_start_line_num) elif l.find('#') != -1: l = get_valid_code(l) s1 = re.search('#\s*\(', l) if not s1: continue # no matter recgnize or not , must wait next ";", continue search find_next = False # get dot pos pound_colm = '' dot_colm = s1.span()[0] cur_match_right_part = l[s1.span()[1]:] # get cur sub module inf cur_sub_module_inf = get_verilog_sub_module_inf_from_pound_line( (i, pound_colm), module_lines, module_start_line_num) else: continue # find result in two way if cur_sub_module_inf: assert(not has_call_sub_not_end) sub_module_inf.append(cur_sub_module_inf) has_call_sub_not_end = True else: PrintDebug( 'Error : not recgnize %d: %s '%(i+module_start_line_num, l ), gen_vtags_log_path ) # no matter find or not , current back line has valid ";", continue find new match if cur_match_right_part.find(';') != -1: find_next = True # if end at current line, set the call range [1] if has_call_sub_not_end and cur_match_right_part.find(';') != -1: sub_module_inf[-1]['match_range'][1] = i + module_start_line_num # start line and end line the same has_call_sub_not_end = False continue if (not find_next) and l.find(';') != -1: if get_valid_code(l).find(';') != -1: # if current not find next, and match a valid ";", need continue search find_next = True # if has unended sub call, and find a valid ";", set last call sub range[1] if has_call_sub_not_end: sub_module_inf[-1]['match_range'][1] = i + module_start_line_num # end line is the first ; line has_call_sub_not_end = False # if has_call_sub_not_end and (not find_next) and l.find(';') != -1: if has_call_sub_not_end and l.find(';') != -1: if get_valid_code(l).find(';') != -1: sub_module_inf[-1]['match_range'][1] = i + module_start_line_num # end line is the first ; line has_call_sub_not_end = False if has_call_sub_not_end: PrintDebug('Error : call sub not end at end module , try module end as callsub end ! : %s'%(sub_module_inf[-1].__str__()), gen_vtags_log_path) sub_module_inf[-1]['match_range'][1] = len(module_lines) - 1 + module_start_line_num # end line is the first ; line return sub_module_inf #------------------------------------------- # modules_inf = { module_name: module_inf } # defines_inf = { macro_name : [ define_inf ] } # files_inf = { file_name : file_inf } # module_inf = { 'module_name' : module_name # ,'file_path' : f # ,'line_range_in_file' : (module_start_line_num, module_end_line_num) # ,'module_pos' : module_pos # ,'sub_modules' : sub_modules } # define_inf = { "name" : xxx # ,"path" : f # ,"pos" : (line_num, colum_num) # name first char pos # ,'code_line' : `define xxx .... } # file_inf = { 'glb_defines' : [ define_inf ] # ,'module_infs' : [ module_inf ] # ,'module_calls' : [ call_sub_inf ] # ,'file_edit_inf' : { 'create_time': ..., 'last_modify_time': ...} # call_sub_inf = { 'inst_name' : inst_name # ,'module_name' : module_name # ,'match_range' : match_range # ,'match_pos' : match_pos } def gen_modules_and_defines_inf(files_inf): modules_inf = {} global_defines_inf = {} for c_file_path in files_inf: c_file_inf = files_inf[c_file_path] # merge defines c_file_glb_defines = c_file_inf['glb_defines'] for d in c_file_glb_defines: d_name = d['name'] global_defines_inf.setdefault(d_name,[]) global_defines_inf[d_name].append(d) # merge modules_inf c_file_module_infs = c_file_inf['module_infs'] for m in c_file_module_infs: mn = m['module_name'] if mn in modules_inf: PrintDebug('Error: module %s has multip defines ! in %s '%(mn, [ modules_inf[mn]['file_path'], m['file_path'] ].__str__() )) else: modules_inf.setdefault(mn, None) modules_inf[mn] = m return modules_inf, global_defines_inf def updata_file_pickle_inf(path): PrintDebug('Care: updata database, file: %s'%(path)) if get_file_path_postfix(path) not in G['SupportVerilogPostfix']: PrintDebug('Warning: updata_file_pickle_inf: file not verilog file ! file: %s'%(path)) return False if not os.path.isfile(path): PrintDebug('Error: updata_file_pickle_inf: file not exit ! file: %s'%(path)) return new_file_modules_inf = get_single_verilog_file_code_inf(path) glb_defines = new_file_modules_inf['glb_defines'] #[ define_inf ] module_infs = new_file_modules_inf['module_infs'] #[ module_inf ] # updata files_inf if path not in G['FileInf']: # if add new inf just add G['FileInf'][path] = new_file_modules_inf # add glb_defines for gd in glb_defines: gd_name = gd['name'] G['CodeDefineInf'].setdefault(gd_name,[]) G['CodeDefineInf'][gd_name].append( gd ) # add module infs for m_inf in module_infs: m_name = m_inf['module_name'] if m_name in G['ModuleInf']: PrintDebug('Error: module %s define twice ! used last at %s, %s'%(m_name, G['ModuleInf'][m_name]['file_path'], path)) G['ModuleInf'][m_name] = m_inf else: # need refresh old and add new, so just gen new inf G['FileInf'][path] = new_file_modules_inf G['ModuleInf'], G['CodeDefineInf'] = gen_modules_and_defines_inf(G['FileInf']) # update pickles if not os.path.isdir(G['VTagsPath']): os.system('mkdir -p '+G['VTagsPath']) fp = open(G['VTagsPath'] + '/files_inf.py','w') fp.write('FileInf = %s \n'%(G['FileInf'].__str__())) fp.write('HDLTagsActive = True \n') fp.close() def get_module_inf(module_name): if module_name not in G['ModuleInf']: PrintDebug('Warning:get_module_inf: "%s" not konwn module !'%(module_name) ) return False module_inf = G['ModuleInf'][module_name] module_path = module_inf['file_path'] cur_inf_time = G['FileInf'][module_path]['file_edit_inf']['last_modify_time'] last_modify_time = os.path.getmtime(module_path) # cur module file not modify, then inf valid and return if cur_inf_time == last_modify_time: return module_inf # if cur module file modify , update Module_inf and return new updata_file_pickle_inf(module_path) return get_module_inf(module_name) #---------------------------------------------------- def get_line_inf_from_cur_file_inf(line_num, file_inf): line_module_inf = {} line_call_sub_inf = {} module_infs = file_inf['module_infs' ] #[ module_inf ] module_calls = file_inf['module_calls'] #[ call_sub_inf ] # first get current line module inf for m_inf in module_infs: c_module_range = m_inf['line_range_in_file'] if c_module_range[1] < line_num: continue if line_num < c_module_range[0]: break line_module_inf = m_inf # second get current line call sub inf for c_inf in module_calls: c_call_range = c_inf['match_range'] if c_call_range[1] < line_num: continue if line_num < c_call_range[0]: break line_call_sub_inf = c_inf return { 'line_module_inf' : line_module_inf ,'line_call_sub_inf' : line_call_sub_inf } def get_file_line_inf(line_num, path = ''): if not path: path = vim.current.buffer.name if get_file_path_postfix(path) not in G['SupportVerilogPostfix']: PrintDebug('Warning: get_file_line_inf: file not verilog file ! file: %s'%(path)) return False if path not in G['FileInf']: updata_file_pickle_inf(path) if path not in G['FileInf']: PrintDebug('Warning: get_file_line_inf: %s has no file database !'%(path) ) return False cur_inf_time = G['FileInf'][path]['file_edit_inf']['last_modify_time'] last_modify_time = os.path.getmtime(path) # cur module file not modify, then inf valid and return if cur_inf_time == last_modify_time: return get_line_inf_from_cur_file_inf( line_num, G['FileInf'][path] ) # if cur module file modify , update Module_inf and return new updata_file_pickle_inf(path) return get_file_line_inf(line_num, path) #---------------------------------------------- # { module_name:'', 'call_inf':atom} def get_module_last_call_inf(module_name): if module_name not in G['ModuleLastCallInf']: return False upper_module_name = G['ModuleLastCallInf'][module_name]['upper_module_name'] upper_inst_name = G['ModuleLastCallInf'][module_name]['upper_inst_name'] if upper_module_name not in G['ModuleInf']: return False if upper_inst_name not in G['ModuleInf'][upper_module_name]['sub_calls']: return False upper_call_inf = G['ModuleInf'][upper_module_name]['sub_calls'][upper_inst_name] return {'upper_module_name': upper_module_name, 'upper_call_inf': upper_call_inf} def set_module_last_call_inf(sub_module_name, upper_module_name, upper_inst_name): G['ModuleLastCallInf'][sub_module_name] = { 'upper_module_name': upper_module_name, 'upper_inst_name': upper_inst_name } #---------------------------------------------- # for a module's submodule, sep function module and base module def get_sub_func_base_module(module_name): func_modules = {} # inst:module base_modules = {} # module : [inst0,inst1...] sub_modules = [] if module_name in G['ModuleInf']: sub_modules = G['ModuleInf'][module_name]['sub_modules'] for sm in sub_modules: inst_name = sm['inst_name'] module_name = sm['module_name'] if module_name in G['BaseModuleInf']['BaseModules']: base_modules.setdefault(module_name,[]) base_modules[module_name].append(inst_name) else: if inst_name in func_modules: # has to same inst name, may be use `ifdefine sep new_inst_name = inst_name+'_'+str(sm['match_range'][0]) func_modules[new_inst_name] = sm continue func_modules[inst_name] = sm return func_modules, base_modules #---------------------------------------------- # update function base information, no need added each times def update_base_module_pickle(): pkl_output = open(G['VTagsPath'] + '/base_modules.pkl','wb') pickle.dump(G['BaseModuleInf']['BaseModules'], pkl_output) pkl_output.close() #---------------------------------------------- # topo/checkpoint/basemodule line range ,in frame file def get_frame_range_inf(): fram_file_link = G["VimBufferLineFileLink"][G['Frame_Inf']['Frame_Path']] # get topo range , default 0,0 has_topo = False has_check_point = False has_base_module = False topo_range = [0, 0] check_point_range = [0, 0] base_module_range = [0, 0] for i,link in enumerate(fram_file_link): if link and (link['type'] == 'topo'): if not has_topo: topo_range[0] = i has_topo = True topo_range[1] = i if link and (link['type'] == 'check_point'): if not has_check_point: check_point_range[0] = i has_check_point = True check_point_range[1] = i if link and (link['type'] == 'base_module'): if not has_base_module: base_module_range[0] = i has_base_module = True base_module_range[1] = i # if no topo ,next topo start at [0,0] if not has_topo: topo_range = [0, 0] # check point initial start at topo end + 2 if not has_check_point: check_point_range[0] = topo_range[1] + 2 check_point_range[1] = topo_range[1] + 2 # base module initial at check point end + 2 if not has_base_module: base_module_range[0] = check_point_range[1] + 2 base_module_range[1] = check_point_range[1] + 2 return { 'topo_range' : tuple(topo_range) ,'check_point_range' : tuple(check_point_range) ,'base_module_range' : tuple(base_module_range) ,'has_topo' : has_topo ,'has_check_point' : has_check_point ,'has_base_module' : has_base_module } #---------------------------------------------------- def get_submodule_match_patten(all_module_name): patten_char_set_list = [] len_2_modules = {} for m_n in all_module_name: l = len(m_n) len_2_modules.setdefault(l,[]) len_2_modules[l].append(m_n) l_pattens = [] for l in len_2_modules: l_m = len_2_modules[l] l_patten = '(['+ (']['.join(map(''.join, map(set,zip(*l_m))))) + '])' l_pattens.append(l_patten) patten = '(' + '|'.join(l_pattens) + ')' return patten #---------------------------------------------------- def get_single_verilog_file_module_inf(f): all_module_start_end_lines = os.popen('egrep -n -h \'^\s*(module|endmodule)\>\' %s'%(f)).readlines() cur_file_module_inf = [] has_module_not_end = False i = 0 while i < len(all_module_start_end_lines): cur_start_end_line = all_module_start_end_lines[i] cur_start_end_line_num = int(cur_start_end_line.split(':')[0]) - 1 cur_start_end_line_code = ':'.join( cur_start_end_line.split(':')[1:] ) match_module_start = re.match('\s*module\s+(?P<name>(|`)\w+)', cur_start_end_line_code) # some module use macro as name so (|`) if match_module_start: module_name = match_module_start.group('name') module_start_line_num = cur_start_end_line_num module_pos = ( module_start_line_num, cur_start_end_line_code.find(module_name) ) # if pre module not end, set new module start pre line as pre module end line if has_module_not_end: PrintDebug('Error: module:"%s" in file:"%s", no "endmodule" !'%(cur_file_module_inf[-1]['module_name'],f) ) cur_file_module_inf[-1]['line_range_in_file'][1] = module_start_line_num - 1 cur_file_module_inf.append( { 'module_name' : module_name ,'file_path' : f ,'line_range_in_file' : [module_start_line_num, -1] ,'sub_modules' : None # [] ,'module_pos' : module_pos } ) has_module_not_end = True i += 1 continue match_module_end = re.match('\s*endmodule(\W|$)', cur_start_end_line_code) if match_module_end: if not has_module_not_end: PrintDebug( 'Error: line: %s "endmodule" has no correlation module define ! file: %s '%(match_module_end,f) ) continue module_end_line_num = cur_start_end_line_num cur_file_module_inf[-1]['line_range_in_file'][1] = module_end_line_num has_module_not_end = False i += 1 continue i += 1 if has_module_not_end: PrintDebug( 'Error: module:"%s" in file:"%s", no "endmodule" !'%(cur_file_module_inf[-1]['module_name'],f) ) return cur_file_module_inf # for current file line match all patten: `define xxx .... # patten_result = { # "name" : xxx # ,"path" : f # ,"pos" : (line_num, colum_num) # name first char pos # ,'code_line' : `define xxx .... # } # finial return [ patten_result0, patten_result1 ] def get_single_verilog_file_define_inf(f): global_define_inf = [] global_define_lines = os.popen('egrep -n -h \'^\s*`define\W\' %s'%(f)).readlines() for l in global_define_lines: split0 = l.split(':') line_num = int(split0[0]) - 1 code_line = ':'.join(split0[1:]) match_name = re.match('\s*`define\s*(?P<name>\w+)',code_line) name = '' colum_num = -1 if match_name: name = match_name.group('name') colum_num = code_line.find(name) if colum_num != -1: global_define_inf.append( { "name" : name ,"path" : f ,"pos" : (line_num, colum_num) ,'code_line' : code_line } ) return global_define_inf def get_single_line_sub_call_inf(egrep_line, all_module_names): sp = egrep_line.split(':') l_num = int(sp[0]) - 1 l_code = re.sub('//.*', '', ':'.join(sp[1:])) if l_code.find(';') == -1: return False # match_name = re.match('\s*(?P<m_n>(|`)\w+)\s*(?P<other>.*;)\s*$',l_code) match_name = re.match('\s*(?P<m_n>(|`)\w+)\s*(?P<other>.*;)',l_code) assert(match_name),'%s,%s'%(egrep_line, l_code) module_name = match_name.group('m_n') if module_name not in all_module_names: return False other = match_name.group('other') inst_name_patten = '\w+((\s*\[[^\[\]]*\])|)' search_i_n = re.search('(^(?P<i_n0>%s))|(#.*\)\s*(?P<i_n1>%s)\s*\()'%(inst_name_patten,inst_name_patten),other) if not search_i_n: PrintDebug( 'Warning: match module name %s, but no inst name !' ) return False inst_name = search_i_n.group('i_n0') if not inst_name: inst_name = search_i_n.group('i_n1') assert(inst_name) return { 'module_name': module_name ,'inst_name' : inst_name ,'match_range': [l_num, l_num] ,'match_pos' : [l_num, l_code.find(module_name)] } def get_mult_line_sub_call_inf(egrep_line, f_lines, all_module_names): sp = egrep_line.split(':') l_num = int(sp[0]) - 1 code_line = re.sub('//.*', '', ':'.join(sp[1:])) # get module name module_name = '' module_pos = (-1,-1) match_name = re.match('^\s*(?P<m_n>(|`)\w+)\s*(?P<other>.*)',code_line) assert(match_name) module_name = match_name.group('m_n') if module_name not in all_module_names: return False module_pos = (l_num, code_line.find(module_name)) # get inst name inst_name = '' inst_name_patten = '\w+((\s*\[[^\[\]]*\])|)' other = match_name.group('other') i = l_num + 1 max_i = len(f_lines) line_end = False while not other and i < max_i and not line_end: next_code_line_with_semi = re.sub('((^\s+)|(^\s*`.*)|(//.*))','',f_lines[i].strip('\n')) next_code_line_no_semi = re.sub(';.*','',next_code_line_with_semi) other = next_code_line_no_semi if len(next_code_line_no_semi) != len(next_code_line_with_semi): line_end = True i += 1 match_inst_name_no_parm = re.match('^(?P<i_n>%s)'%(inst_name_patten),other) if match_inst_name_no_parm: inst_name = match_inst_name_no_parm.group('i_n') elif other[0] != '#': PrintDebug('Warning: un recgnize 0 module match ! %s ||| %s'%(egrep_line, other)) return False # del has parm inst_name search_inst_name_has_parm = re.search('#\s*\(.*\)\s*(?P<i_n>%s)\s*\('%(inst_name_patten),other) if search_inst_name_has_parm: inst_name = search_inst_name_has_parm.group('i_n') while i < max_i and not line_end: next_code_line_with_semi = re.sub('((^\s+)|(^\s*`.*)|(//.*))','',f_lines[i].strip('\n')) next_code_line_no_semi = re.sub(';.*','',next_code_line_with_semi) other = other +' '+next_code_line_no_semi if len(next_code_line_no_semi) != len(next_code_line_with_semi): line_end = True i += 1 search_inst_name_has_parm = re.search('#\s*\(.*\)\s*(?P<i_n>%s)\s*\('%(inst_name_patten),other) if search_inst_name_has_parm: inst_name = search_inst_name_has_parm.group('i_n') break if not inst_name: PrintDebug('Warning: un recgnize 1 module match ! %s ||| %d ||| %s '%(egrep_line, i, str(line_end) ) ) return False # get cur call end line end_line_num = max_i while i < max_i and not line_end: next_code_line = re.sub('(^`.*)|(//.*)','',f_lines[i]) if next_code_line.find(';') != -1: line_end = True break i += 1 if not line_end: PrintDebug('Warning: cur sub call no end ";" ! %s'%(egrep_line)) else: end_line_num = i # return result return { 'module_name': module_name ,'inst_name' : inst_name ,'match_range': [l_num, end_line_num] ,'match_pos' : module_pos } def get_single_verilog_file_subcall_inf(f, patten, all_module_names): egrep_match_lines = os.popen('egrep -n -h \'^\s*(%s)\>\' %s'%(patten,f)).readlines() # start get sub call inf if not egrep_match_lines: return [] file_sub_call_infs = [] c0_cnt = 0 c1_cnt = 0 f_lines = open(f,'r').readlines() for egrep_l in egrep_match_lines: # case0: signal line call c0_rst = get_single_line_sub_call_inf(egrep_l, all_module_names) if c0_rst: c0_cnt += 1 file_sub_call_infs.append(c0_rst) continue # case1: mult line call c1_rst = get_mult_line_sub_call_inf(egrep_l, f_lines, all_module_names) if c1_rst: c1_cnt += 1 file_sub_call_infs.append(c1_rst) continue PrintDebug('subcall: one_line/mult_line = %d/%d'%( c0_cnt,c1_cnt) ) return file_sub_call_infs def add_single_verilog_file_submodule_inf_to_module_inf( file_module_inf, file_subcall_inf ): s_inf_i = 0 for m_inf in file_module_inf: m_inf['sub_modules'] = [] m_inf['sub_calls'] = {} m_range = m_inf['line_range_in_file'] while s_inf_i < len(file_subcall_inf): s_range = file_subcall_inf[s_inf_i]['match_range'] # cur subcall in cur module if m_range[0] <= s_range[0] and s_range[1] <= m_range[1]: m_inf['sub_modules'].append(file_subcall_inf[s_inf_i]) m_inf['sub_calls'][file_subcall_inf[s_inf_i]['inst_name']] = file_subcall_inf[s_inf_i] s_inf_i += 1 continue elif s_range[0] < m_range[0]: PrintDebug('Error: subcall %s not in valid module !'%(file_subcall_inf[s_inf_i].__str__())) s_inf_i += 1 elif s_range[1] > m_range[1]: if s_range[0] < m_range[0]: PrintDebug('Error: subcall %s cross two module !'%(file_subcall_inf[s_inf_i].__str__())) break else: assert(0) return def get_single_verilog_file_code_inf(f): # gen cur module and define inf new_file_module_inf = get_single_verilog_file_module_inf(f) new_file_define_inf = get_single_verilog_file_define_inf(f) # gen new all_module_names, del old current file add new new_module_names = set([ mi['module_name'] for mi in new_file_module_inf ]) old_file_module_inf = G['FileInf'][f]['module_infs'] old_module_names = set([ mi['module_name'] for mi in old_file_module_inf ]) all_module_name = ( set(G['ModuleInf']) - old_module_names ) | new_module_names # get file sub call inf patten = get_submodule_match_patten(all_module_name) new_file_subcall_inf = get_single_verilog_file_subcall_inf(f, patten, all_module_name) # merge to file_inf add_single_verilog_file_submodule_inf_to_module_inf( new_file_module_inf, new_file_subcall_inf ) new_file_inf = { 'glb_defines' : new_file_define_inf ,'module_infs' : new_file_module_inf ,'module_calls' : new_file_subcall_inf ,'file_edit_inf' : { 'create_time': os.path.getctime(f), 'last_modify_time': os.path.getmtime(f)} } return new_file_inf def show_progress_bar( i, i_max, show_char = '#', show_width = 20): i += 1 # count from 1 i_max_len = len(str(i_max)) i_len = len(str(i)) i_str = ' '*(i_max_len-i_len)+str(i) i_max_str = str(i_max) prefix = '%s/%s: '%(i_str,i_max_str) pass_str = show_char*((i*show_width)/i_max) empty_str = ' '*(show_width - len(pass_str)) progress_bar = '[%s%s]'%(pass_str,empty_str) tool_len = len(prefix) + show_width sys.stdout.write(' '*tool_len + '\r') sys.stdout.flush() sys.stdout.write(prefix + progress_bar) """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== import sys import re import os try: import vim except: pass import GLB G = GLB.G from Base import* import View PrintReport = View.PrintReport ######################################################## def get_sub_io_signal_name_from_sub_call_line(call_line, y): word = get_full_word(call_line, y) # if | .xxx(xxxx) # y | ^ # | ^ ^ // call_sub_assign_signal_str # cur_word is sub_io_signal_name if re.match('\w+\.', call_line[:y+1][::-1]): call_sub_assign_signal_str = re.sub('(^\w*)|(\.\w+\(.*)', '', call_line[y:]) call_sub_signals = set( re.findall('\w+',call_sub_assign_signal_str) ) sub_call_io = word return { 'call_sub_signals': call_sub_signals ,'sub_call_io' : word ,'sub_call_io_num' : None } # if | .xxx(xxxx) # y | ^ # | ^ ^ // call_sub_assign_signal_str s0 = re.search('\(\s*(?P<sub_call_io>\w+)\.',call_line[:y+1][::-1]) if s0: sub_call_io = s0.group('sub_call_io')[::-1] call_sub_assign_and_right = call_line[y-s0.span()[0]:] assert(call_sub_assign_and_right[0] == '(') call_sub_assign_signal_str = re.sub('\.\w+\s*\(.*', '', call_line[y:]) call_sub_signals = set( re.findall('\w+',call_sub_assign_signal_str) ) return { 'call_sub_signals': call_sub_signals ,'sub_call_io' : sub_call_io ,'sub_call_io_num' : None } # if module_name #(parm) inst_name( a, b, c) # if module_name inst_name( a, b, c) # y # call_sub_signals set(b) # sub_call_io_num 1 # sub_call_io '' if word: s1 = re.search('\)\s*\w+\s*\(',call_line[:y+1]) if not s1: s1 = re.match('\s*\w+\s*\w+\s*\(',call_line[:y+1]) full_match_s1 = True if s1: pre_sub_call_signal_str = call_line[s1.span()[1]:y+1] pre_sub_call_signals = pre_sub_call_signal_str.split(',') assert(pre_sub_call_signals) for sc in pre_sub_call_signals: if not re.match('\s*(\w+)|(\w+\s*\[[^\[\]]+\])\s*$',sc): full_match_s1 = False if full_match_s1: return { 'call_sub_signals': set([word]) ,'sub_call_io' : '' ,'sub_call_io_num' : len(pre_sub_call_signals) - 1 } return None # if has io_name return cur io inf # else return all io inf of current module #io_inf = # "name" : name # , "io_type" : io_type # , "left" : left_index # , "right" : right_index # , "size" : size # , 'line_num' : line_num # , 'name_pos' : (line_num, colm_num) # , 'code_line' : code_line # , 'signal_type' : signal_type } def get_io_inf(module_name, io_name = ''): module_inf = get_module_inf(module_name) if not module_inf: return False module_path = module_inf['file_path'] module_range = module_inf['line_range_in_file'] if io_name: # get cur io inf io_inf = {} io_lines = os.popen('sed -n \'%d,%dp\' %s | egrep -n -h \'^\s*(input|output)\>.*\<%s\>\''%(module_range[0]+1, module_range[1]+1, module_path, io_name)).readlines() if len(io_lines) == 0: PrintDebug('Error: module: %s \'s io: %s define not found !'%(module_name,io_name)) return False if len(io_lines) > 1: l_i = 0 while l_i < len(io_lines): if not re.search('\W%s(\W|)'%(io_name), re.sub('//.*','',io_lines[l_i])): del io_lines[l_i] continue l_i += 1 continue if len(io_lines) > 1: PrintDebug('Error: module: %s \'s io: %s define multiple times !'%(module_name,io_name)) line = io_lines[0] assert(line.find(io_name) != -1) io_inf = decode_egreped_verilog_io_line(line)['io_infs'] if io_name in io_inf: # because use "sed ... | grep ..." so the line number is not the real number need add sed started line num io_inf[io_name]['line_num'] = io_inf[io_name]['line_num'] + module_range[0] io_inf[io_name]['name_pos'] = ( io_inf[io_name]['line_num'], io_inf[io_name]['name_pos'][1] ) return io_inf[io_name] else: PrintDebug('Warning: get_io_inf, io_name is parm name ,not a io !') return False else: # get module all io inf all_io_inf = [] cur_module_code_range = module_inf['line_range_in_file'] all_io_lines = os.popen('sed -n \'%d,%dp\' %s | egrep -n -h \'^\s*(input|output)\>\''%(cur_module_code_range[0]+1, cur_module_code_range[1]+1, module_path)).readlines() for line in all_io_lines: line = line.rstrip('\n') egrep_io_infs = decode_egreped_verilog_io_line(line) io_inf = egrep_io_infs['io_infs'] name_list = egrep_io_infs['name_list'] if not io_inf: PrintDebug('Error: module: %s, line: %s, can not decode by decode_egreped_verilog_io_line() ! file: %s'(module_name, line, module_path)) continue for io_name in name_list: assert(io_name in io_inf) c_io_inf = io_inf[io_name] c_io_inf['line_num'] = c_io_inf['line_num'] + cur_module_code_range[0] c_io_inf['name_pos'] = (c_io_inf['line_num'], c_io_inf['name_pos'][1]) all_io_inf.append( c_io_inf ) return all_io_inf def get_module_call_sub_module_io_inf(call_line, io_pos, call_file_path): call_line_num = io_pos[0] # if database has no this file return if call_file_path not in G['FileInf']: PrintDebug("Warning: get_module_call_sub_module_io_inf : cur file has not in hdltags database, file: %s !"%(call_file_path)) return False file_line_inf = get_file_line_inf(call_line_num, call_file_path) line_call_sub_inf = {} line_module_inf = {} if file_line_inf: line_call_sub_inf = file_line_inf['line_call_sub_inf'] line_module_inf = file_line_inf['line_module_inf'] # if cursor line not no sub call , return if not line_call_sub_inf: PrintDebug("Warning: get_module_call_sub_module_io_inf: cur line %d not on sub call ! "%(call_line_num)) return False sub_call_signal_inf = get_sub_io_signal_name_from_sub_call_line(call_line, io_pos[1]) # may be parm # call module name assert(line_module_inf),'is in sub call, must be valid mudule' call_module_name = line_module_inf['module_name'] # valid cursor on sub call sub_module_name = line_call_sub_inf['module_name'] sub_module_path = '' sub_module_inf = get_module_inf(sub_module_name) if sub_module_inf: sub_module_path = sub_module_inf['file_path'] # sub_match_pos means cursor call io signal in sub module io pos sub_io_inf = {} call_sub_signals = set() if sub_call_signal_inf: call_sub_signals = sub_call_signal_inf['call_sub_signals'] sub_call_io = sub_call_signal_inf['sub_call_io'] sub_call_io_num = sub_call_signal_inf['sub_call_io_num'] if sub_call_io: sub_io_inf = get_io_inf(sub_module_name, sub_call_io) elif sub_call_io_num != None: all_io_inf = get_io_inf(sub_module_name) assert(sub_call_io_num < len(all_io_inf)) sub_io_inf = all_io_inf[sub_call_io_num] sub_match_pos = () sub_io_type = '' sub_io_line = '' sub_io_name = '' if sub_io_inf: sub_io_name = sub_io_inf['name'] sub_match_pos = sub_io_inf['name_pos'] sub_io_type = sub_io_inf['io_type'] sub_io_line = sub_io_inf['code_line'] return { 'sub_io_name' : sub_io_name ,'sub_module_name' : sub_module_name ,'sub_module_path' : sub_module_path ,'sub_match_pos' : sub_match_pos ,'sub_io_type' : sub_io_type ,'sub_io_line' : sub_io_line ,'sub_io_inf' : sub_io_inf ,'call_sub_signals' : call_sub_signals ,'call_sub_inf' : line_call_sub_inf ,'call_module_name' : call_module_name } #########################function for trace############################## # ok def get_upper_module_call_io_inf(cur_module_name , cur_io_name): cur_module_last_call_inf = get_module_last_call_inf(cur_module_name) if not cur_module_last_call_inf: PrintDebug("Warning: get_upper_module_call_io_inf: module %s, not called before, no upper module !"%(cur_module_name)) return False upper_module_name = cur_module_last_call_inf['upper_module_name'] upper_call_inf = cur_module_last_call_inf['upper_call_inf'] upper_module_inf = get_module_inf(upper_module_name) assert(upper_module_inf),'upper module %s call %s before, upper should has inf in database !'%(upper_module_name, cur_module_name) upper_module_path = upper_module_inf['file_path'] # get upper call, match this signal pos upper_call_lines = open(upper_module_path,'r').readlines() upper_call_pos = upper_call_inf['match_pos'] # initial to call inst line upper_matched = False for i in range( upper_call_inf['match_range'][0] , upper_call_inf['match_range'][1] + 1 ): f0 = upper_call_lines[i].find(cur_io_name) if f0 == -1: continue s0 = re.search('(?P<pre>^|\W)%s(\W|$)'%(cur_io_name) , re.sub('//.*','',upper_call_lines[i])) if s0: colum_num = s0.span()[0] + len(s0.group('pre')) upper_call_pos = (i, colum_num) upper_matched = True break assert(upper_matched),'upper called so should be match, cur_io_name:%s, %s '%(upper_call_inf['match_range'].__str__(), cur_io_name) upper_call_line = upper_call_lines[upper_call_pos[0]] return { 'module_name' : upper_module_name ,'call_pos' : upper_call_pos ,'call_line' : upper_call_line ,'module_path' : upper_module_path } def get_cur_appear_is_source_or_dest(key, code_lines, appear_pos): a_x, a_y = appear_pos appear_code_line = re.sub('(//.*)|(^\s*`.*)', '', code_lines[a_x] ) # case 0 cur pos in note return not source and dest if len(appear_code_line) - 1 < a_y: return 'None' # case 1 is io if (appear_code_line.find('input') != -1) or (appear_code_line.find('output') != -1): match_io_type = re.match('\s*(?P<io_type>(input|output))\W',appear_code_line) # may input a,b,c match_io_name = re.match('\s*[;,]?\s*(?P<r_names>\w+(\s*,\s*\w+)*)',appear_code_line[::-1]) # may input a,b,c if match_io_type and match_io_name: io_type = match_io_type.group('io_type') io_names = match_io_name.group('r_names')[::-1] io_names = set(re.split('\s*,\s*',io_names)) if (io_type == 'input') and (key in io_names): return 'Source' if (io_type == 'output') and (key in io_names): return 'Dest' elif match_io_type: PrintDebug('Error: recgnize_signal_assign_line: unrecgnize io line: '+appear_code_line) return 'None' # case 2 cur pos in case/casez/for/if (...key...) then it's dest match_case2 = False c2 = re.search( '(^|\W)(case|casez|for|if|while)\s*\(' , appear_code_line) if c2: appear_code_right_line = appear_code_line[c2.span()[1]:] unmatch_bracket_count = 1 end_match_patten = '^' end_y = len(appear_code_right_line) - 1 all_brackets = re.findall('\(|\)', appear_code_right_line) for b in all_brackets: if b == '(': unmatch_bracket_count += 1 else: unmatch_bracket_count -= 1 end_match_patten = end_match_patten + '[^()]*\\'+b if unmatch_bracket_count == 0: end_y = re.search(end_match_patten, appear_code_right_line).span()[1] - 1 break end_y = c2.span()[1] + end_y if end_y >= a_y: return 'Dest' else: # if key not in (...), then use ) right str as real appear_code_line match_case2 = True appear_code_line = appear_code_line[end_y + 1:] # case 3 cur line has = at left or right assign_patten = '([^=>!]=[^=<>])' # ... =|<= ... key : is dest if re.search(assign_patten, appear_code_line[:a_y + 1]): return 'Dest' # key ... =|<= ... : is source if re.search(assign_patten, appear_code_line[a_y:]): return 'Source' # case 4 if not match case2(if match no pre line) post full line sep by ";" has =|<=, it's dest if not match_case2: pre_full_line = get_verilog_pre_full_line(code_lines, appear_pos) if re.search(assign_patten, pre_full_line): return 'Dest' # case 5 post full line sep by ";" has =|<=, it's source post_full_line = get_verilog_post_full_line(code_lines, appear_pos) if re.search(assign_patten, post_full_line[:a_y + 1]): return 'Source' # case 6 unrecgnize treat as maybe dest/source return 'Maybe' # ok def clear_last_trace_inf( trace_type ): if trace_type in ['source','both']: G['TraceInf']['LastTraceSource']['Maybe'] = [] G['TraceInf']['LastTraceSource']['Sure'] = [] G['TraceInf']['LastTraceSource']['ShowIndex'] = 0 G['TraceInf']['LastTraceSource']['SignalName'] = '' G['TraceInf']['LastTraceSource']['Path'] = '' if trace_type in ['dest','both']: G['TraceInf']['LastTraceDest']['Maybe'] = [] G['TraceInf']['LastTraceDest']['Sure'] = [] G['TraceInf']['LastTraceDest']['ShowIndex'] = 0 G['TraceInf']['LastTraceDest']['SignalName'] = '' G['TraceInf']['LastTraceDest']['Path'] = '' # #-------------------trace_io_signal--------------------------- # del get_cur_module_inf def real_trace_io_signal(trace_type, cursor_inf, io_signal_inf): assert(trace_type in ['dest', 'source']),'only trace dest/source' # verilog if (trace_type is 'dest') and (io_signal_inf['io_type'] != 'output'): PrintDebug('Warning: real_trace_io_signal: not output signal, not dest') return False # not output signal, not dest if (trace_type is 'source') and (io_signal_inf['io_type'] != 'input'): PrintDebug('Warning: real_trace_io_signal: not input signal, not source') return False # not input signal, not source # trace a input signal clear_last_trace_inf( trace_type ) # clear pre trace dest/source result cur_module_inf = cursor_inf['cur_module_inf'] if not cur_module_inf: PrintDebug('Warning: cur file not in database, will not go upper ! file: %s'(cursor_inf['file_path'])) return True cur_module_name = cur_module_inf['module_name'] upper_module_call_inf = get_upper_module_call_io_inf(cur_module_name , io_signal_inf['name']) if not upper_module_call_inf: PrintReport('Warning: no upper module call this module before !') return True # this dest/source but not found upper module # has upper module go to upper module call location upper_module_name = upper_module_call_inf['module_name'] upper_call_pos = upper_module_call_inf['call_pos'] upper_call_line = upper_module_call_inf['call_line'] upper_module_path = upper_module_call_inf['module_path'] show_str = '%s %d : %s'%(upper_module_name, upper_call_pos[0]+1, upper_call_line) file_link = {'key':io_signal_inf['name'], 'pos': upper_call_pos, 'path': upper_module_path} trace_result = {'show': show_str, 'file_link': file_link} if trace_type is 'dest': G['TraceInf']['LastTraceDest']['Sure'].append(trace_result) G['TraceInf']['LastTraceDest']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceDest']['Path'] = cursor_inf['file_path'] else : G['TraceInf']['LastTraceSource']['Sure'].append(trace_result) G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceSource']['Path'] = cursor_inf['file_path'] # show dest/source to report win, and go first trace PrintReport(spec_case = trace_type) View.show_next_trace_result(trace_type) return True # ok def trace_io_signal(trace_type, cursor_inf): trace_signal_name = cursor_inf['word'] io_signal_infs = recgnize_io_signal_line(cursor_inf['line'], cursor_inf['line_num']) if not io_signal_infs: PrintDebug('Warning: trace_io_signal: not io signal') return False # not io signal # if trace_signal_name != io_signal_inf['name']: if trace_signal_name not in io_signal_infs: PrintDebug('Warning: trace_io_signal: is io signal but not traced signal') return False # is io signal but not traced signal if trace_type in ['source','dest']: return real_trace_io_signal(trace_type, cursor_inf, io_signal_infs[trace_signal_name]) assert(0),'unkonw tarce type %s' %(trace_type) #------------------------------------------------------------- # ok def real_trace_module_call_io_signal(trace_type, sub_call_inf, cursor_inf): assert(trace_type in ['source', 'dest']) if trace_type == 'source' and sub_call_inf['sub_io_type'] != 'output': return False # submodule not source, just pass elif trace_type == 'dest' and sub_call_inf['sub_io_type'] != 'input': return False # submodule not source, just pass # has sub module and in submodule signal is out, then it's source sub_module_name = sub_call_inf['sub_module_name'] sub_module_path = sub_call_inf['sub_module_path'] sub_module_match_pos = sub_call_inf['sub_match_pos'] sub_module_match_line = sub_call_inf['sub_io_line'] sub_module_signal_name = sub_call_inf['sub_io_name'] show_str = '%s %d : %s'%(sub_module_name, sub_module_match_pos[0]+1, sub_module_match_line) file_link = {'key':sub_module_signal_name, 'pos': sub_module_match_pos, 'path': sub_module_path} trace_result = {'show': show_str, 'file_link': file_link} if trace_type == 'source': G['TraceInf']['LastTraceSource']['Sure'].append(trace_result) G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceSource']['Path'] = cursor_inf['file_path'] else: # dest G['TraceInf']['LastTraceDest']['Sure'].append(trace_result) G['TraceInf']['LastTraceDest']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceDest']['Path'] = cursor_inf['file_path'] # go to sub module code now, so cur module is the sub module last call cur_module_name = sub_call_inf['call_module_name'] call_sub_inf = sub_call_inf['call_sub_inf'] set_module_last_call_inf(sub_module_name, cur_module_name, call_sub_inf['inst_name']) # show source to report win, and go first trace PrintReport(spec_case = trace_type) View.show_next_trace_result(trace_type) return True # ok # del is_module_call_range def trace_module_call_io_signal(trace_type, cursor_inf): sub_call_inf = get_module_call_sub_module_io_inf(cursor_inf['line'], cursor_inf['pos'], cursor_inf['file_path']) if not sub_call_inf: PrintDebug('Warning: trace_module_call_io_signal: not in module call io') return False # not in module call io if sub_call_inf['sub_module_name'] == cursor_inf['word']: PrintReport('Warning: trace key is a submodule call, module name , no source !') return True if not sub_call_inf['sub_io_name']: PrintDebug('Warning: trace_module_call_io_signal: is module call ,but unrecgnize io name !') return False clear_last_trace_inf( trace_type ) return real_trace_module_call_io_signal(trace_type, sub_call_inf, cursor_inf) # #--------------------------------------------------------------------- def real_trace_normal_signal(trace_type, signal_appear_pos_line, cursor_inf): assert(trace_type in ['source', 'dest']) clear_last_trace_inf(trace_type) if trace_type == 'source': G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceSource']['Path'] = cursor_inf['file_path'] else: G['TraceInf']['LastTraceDest']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceDest']['Path'] = cursor_inf['file_path'] trace_signal_name = cursor_inf['word'] cur_module_inf = cursor_inf['cur_module_inf'] # already qualify cur_module_name = cur_module_inf['module_name'] cur_module_path = cur_module_inf['file_path'] # add optimizing for signal such like clk, used by many times, but only io, or sub call is source input_is_only_source = False if trace_type == 'source' and len(signal_appear_pos_line) > G['TraceInf']['TraceSourceOptimizingThreshold']: for appear_pos, appear_line in signal_appear_pos_line: signal_appear_line = cursor_inf['codes'][appear_pos[0]] if signal_appear_line.find('input') == -1: continue dest_or_source = get_cur_appear_is_source_or_dest(trace_signal_name, [signal_appear_line], (0,appear_pos[1]) ) if dest_or_source != source: continue input_is_only_source = True show_str = '%s %d : %s'%(cur_module_name, appear_pos[0]+1, appear_line) file_link = {'key':trace_signal_name, 'pos': appear_pos, 'path': cur_module_path} trace_result = {'show': show_str, 'file_link': file_link} G['TraceInf']['LastTraceSource']['Sure'].append(trace_result) break # if found a input as source, should be the only source, clear appear pos to jump, normal search if input_is_only_source: signal_appear_pos_line = [] # appear_pos (line number, column), deal each match to find source for appear_pos, appear_line in signal_appear_pos_line: appear_dest_or_source = False appear_is_dest = False appear_is_source = False # module call assign range sub_call_inf = get_module_call_sub_module_io_inf(appear_line, appear_pos, cur_module_path) if sub_call_inf: if trace_signal_name in sub_call_inf['call_sub_signals']: # cur is subcall but not io name not match trace name go next if not sub_call_inf['sub_io_type']: appear_dest_or_source = True elif sub_call_inf['sub_io_type'] == 'output': appear_is_source = True elif sub_call_inf['sub_io_type'] == 'input': appear_is_dest = True else: PrintDebug('Warning: subcall match on sub io name, not on assign name ! %s,%s'%(appear_pos.__str__(), appear_line)) continue else: # not module call then check if a assign signal dest_or_source = get_cur_appear_is_source_or_dest(trace_signal_name, cursor_inf['codes'], appear_pos) if dest_or_source == 'Dest': appear_is_dest = True elif dest_or_source == 'Source': appear_is_source = True elif dest_or_source == 'Maybe': appear_dest_or_source = True else: PrintDebug('Warning: match not source or dest ! %s : %s'%(appear_pos.__str__(), appear_line)) # finial add to source/dest show_str = '%s %d : %s'%(cur_module_name, appear_pos[0]+1, appear_line) file_link = {'key':trace_signal_name, 'pos': appear_pos, 'path': cur_module_path} trace_result = {'show': show_str, 'file_link': file_link} if trace_type == 'source': if appear_dest_or_source: G['TraceInf']['LastTraceSource']['Maybe'].append(trace_result) elif appear_is_source: G['TraceInf']['LastTraceSource']['Sure'].append(trace_result) else: # trace dest if appear_dest_or_source: G['TraceInf']['LastTraceDest']['Maybe'].append(trace_result) elif appear_is_dest: G['TraceInf']['LastTraceDest']['Sure'].append(trace_result) continue # finish get all dest/source if trace_type == 'source': finded_source_num = len(G['TraceInf']['LastTraceSource']['Sure']) finded_maybe_source_num = len(G['TraceInf']['LastTraceSource']['Maybe']) # not find signal source if not (finded_source_num + finded_maybe_source_num): PrintReport("Warning: Not find signal source !") return True else: # dest finded_dest_num = len(G['TraceInf']['LastTraceDest']['Sure']) finded_maybe_dest_num = len(G['TraceInf']['LastTraceDest']['Maybe']) # not find signal dest if not (finded_dest_num + finded_maybe_dest_num): PrintReport("Warning: Not find signal dest !") return True # show source to report win, and go first trace PrintReport(spec_case = trace_type) View.show_next_trace_result(trace_type) return True def trace_normal_signal(trace_type, cursor_inf): cur_module_inf = cursor_inf['cur_module_inf'] if not cur_module_inf: PrintDebug('Warning: cur file has no module inf, may be no database or cur line not in module, file: %s '%(cursor_inf['file_path'])) return False # just use grep get all signal appear in current file to speed up signal search signal_appear_pos_line = search_verilog_code_use_grep( cursor_inf['word'], cursor_inf['file_path'], cur_module_inf['line_range_in_file'] ) return real_trace_normal_signal(trace_type, signal_appear_pos_line, cursor_inf) #---------------------------------------------------- def trace_glb_define_signal(trace_type, cursor_inf): assert(trace_type in ['dest', 'source']) cur_line = cursor_inf['line'] cur_word = cursor_inf['word'] if cur_line.find('`') == -1: return False s0 = re.search('(?P<prefix>^|\W)%s(\W|$)'%(cur_word),cur_line) if not s0: return False if s0.group('prefix') != '`': return False if cur_word not in G['CodeDefineInf']: PrintReport('Warning: cur macro: \"%s\", not has find in database !'%(cur_word)) return True cur_define_infs = G['CodeDefineInf'][cur_word] clear_last_trace_inf(trace_type) for inf in cur_define_infs: # {name path pos code_line} file_name = re.sub('.*/','',inf['path']) show_str = '%s %d : %s'%(file_name, inf['pos'][0]+1, inf['code_line']) file_link = {'key':cur_word, 'pos': inf['pos'], 'path': inf['path']} trace_result = {'show': show_str, 'file_link': file_link} if trace_type == 'source': G['TraceInf']['LastTraceSource']['SignalName'] = cursor_inf['word'] G['TraceInf']['LastTraceSource']['Path'] = cursor_inf['file_path'] G['TraceInf']['LastTraceSource']['Sure'].append(trace_result) else: # dest PrintReport('Warning: cur not support trace macro dest !') return True # show source to report win, and go first trace PrintReport(spec_case = trace_type) View.show_next_trace_result(trace_type) return True """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== import sys sys.path.append('../') import vim_glb_config as glb_config import os import re import pickle vim_start_open_file = '' try: import vim vim_start_open_file = vim.current.buffer.name except: vim_start_open_file = '|vim_not_open|' pass # cur call path cur_path = os.getcwd() # find most resent vtags path hdl_tags_path = '' while cur_path and cur_path[0] == '/': if os.path.isdir(cur_path + '/vtags.db'): hdl_tags_path = cur_path + '/vtags.db' break cur_path = re.sub('/[^/]*$','',cur_path) # get local config config = glb_config try: if hdl_tags_path: sys.path.append(hdl_tags_path) import vim_local_config as local_config config = local_config except: pass # get next empty frame, report,log report index, first try del Frame, Report def del_old_logs(): ls_a_f = [ f.strip('\n') for f in os.popen('ls -a ' + hdl_tags_path).readlines() ] used_log_index = set() for f in ls_a_f: match_swp = re.match('\.(Frame\.HF|Report\.HF|run\.log)(?P<idx>\d+)\.swp',f) if match_swp: used_log_index.add(int(match_swp.group('idx'))) ls_f = [ f.strip('\n') for f in os.popen('ls ' + hdl_tags_path).readlines() ] for f in ls_f: match_idx = re.match('(Frame\.HF|Report\.HF|run\.log)(?P<idx>\d+)', f) if not match_idx: continue cur_index = int(match_idx.group('idx')) if cur_index in used_log_index: continue os.system('rm %s/%s'%(hdl_tags_path,f) ) return empty_log_index = 0 if hdl_tags_path: del_old_logs() while os.path.isfile(hdl_tags_path + '/run.log' + str(empty_log_index)) or \ os.path.isfile(hdl_tags_path + '/Frame.HF' + str(empty_log_index)) or \ os.path.isfile(hdl_tags_path + '/Report.HF' + str(empty_log_index)): empty_log_index += 1 # if in generate vtags situation, print log to vtags.db/vtags_run.log vtags_run_log_path = [''] # run log path run_log_path = hdl_tags_path + '/run.log'+str(empty_log_index) def PrintDebug( str, out_path = ''): if vtags_run_log_path[0]: output = open( vtags_run_log_path[0], 'a') output.write(str+'\n') output.close() return if not config.debug_mode: return if out_path: output = open( out_path, 'a') output.write(str+'\n') output.close() return if hdl_tags_path: output = open( run_log_path ,'a') output.write(str+'\n') output.close() def get_file_path_postfix(file_path): split_by_dot = file_path.split('.') if len(split_by_dot) < 2: # which means file_path has no postfix return '' post_fix = split_by_dot[-1] # postfix care case return post_fix HDLTagsActive = True # if cur open a valid file, and file not verilog file not act vtags if vim_start_open_file \ and (get_file_path_postfix(vim_start_open_file) not in config.support_verilog_postfix): HDLTagsActive = False # get file inf FileInf = {} try: if hdl_tags_path and HDLTagsActive: import files_inf HDLTagsActive = files_inf.HDLTagsActive FileInf = files_inf.FileInf else: HDLTagsActive = False except: HDLTagsActive = False BaseModules = set() if HDLTagsActive: # get base module inf try: pkl_input = open(hdl_tags_path + '/base_modules.pkl','rb') BaseModules = pickle.load(pkl_input) pkl_input.close() except: pass # function ------------------------------------------------- def save_env_snapshort(): snapshort = {} # 0: save cur dir path, used to quality opne snapshort snapshort['snapshort_dir_path'] = os.getcwd() # 1: save Frame snapshort['frame_file_lines'] = [] if os.path.isfile(G['Frame_Inf']['Frame_Path']): snapshort['frame_file_lines'] = open(G['Frame_Inf']['Frame_Path'],'r').readlines() # 2: save Report snapshort['report_file_lines'] = [] if os.path.isfile(G['Report_Inf']['Report_Path']): snapshort['report_file_lines'] = open(G['Report_Inf']['Report_Path'],'r').readlines() # 3: save G snapshort['G'] = {} snapshort['G']['OpTraceInf'] = {} snapshort['G']['OpTraceInf']['TracePoints'] = G['OpTraceInf']['TracePoints'] snapshort['G']['OpTraceInf']['Nonius' ] = G['OpTraceInf']['Nonius' ] snapshort['G']['WorkWin_Inf'] = {} snapshort['G']['WorkWin_Inf']['OpenWinTrace'] = G['WorkWin_Inf']['OpenWinTrace'] snapshort['G']['VimBufferLineFileLink' ] = G["VimBufferLineFileLink" ] snapshort['G']["TraceInf" ] = G['TraceInf'] snapshort['G']['CheckPointInf'] = {} snapshort['G']['CheckPointInf']['CheckPoints'] = G['CheckPointInf']['CheckPoints'] snapshort['G']['TopoInf'] = {} snapshort['G']['TopoInf']['CurModule'] = G['TopoInf']['CurModule'] snapshort['G']['ModuleLastCallInf'] = G['ModuleLastCallInf'] snapshort['G']['Frame_Inf'] = {} snapshort['G']['Frame_Inf']['Frame_Path'] = G['Frame_Inf']['Frame_Path'] snapshort['G']['Report_Inf'] = {} snapshort['G']['Report_Inf']['Report_Path'] = G['Report_Inf']['Report_Path'] # 4: save act windows inf act_win_inf = [] for w in vim.windows: c_file_path = w.buffer.name if c_file_path == vim.current.buffer.name: continue c_cursor = w.cursor c_size = (w.width, w.height) act_win_inf.append({'path': c_file_path, 'cursor': c_cursor, 'size': c_size }) # last is current window cur_file_path = vim.current.buffer.name cur_cursor = vim.current.window.cursor cur_size = (vim.current.window.width, vim.current.window.height) act_win_inf.append({'path': cur_file_path, 'cursor': cur_cursor, 'size': cur_size }) snapshort['act_win_inf'] = act_win_inf pkl_output = open(hdl_tags_path + '/env_snapshort.pkl','wb') pickle.dump(snapshort, pkl_output) pkl_output.close() return True def reload_env_snapshort(snapshort): # 1: reload G snapshort_G = snapshort['G'] G['OpTraceInf']['TracePoints'] = snapshort_G['OpTraceInf']['TracePoints'] G['OpTraceInf']['Nonius' ] = snapshort_G['OpTraceInf']['Nonius' ] G['WorkWin_Inf']['OpenWinTrace'] = snapshort_G['WorkWin_Inf']['OpenWinTrace'] G['VimBufferLineFileLink' ] = snapshort_G["VimBufferLineFileLink" ] G["TraceInf" ] = snapshort_G['TraceInf'] G['CheckPointInf']['CheckPoints'] = snapshort_G['CheckPointInf']['CheckPoints'] G['TopoInf']['CurModule'] = snapshort_G['TopoInf']['CurModule'] G['ModuleLastCallInf'] = snapshort_G['ModuleLastCallInf'] G['Frame_Inf']['Frame_Path'] = snapshort_G['Frame_Inf']['Frame_Path'] G['Report_Inf']['Report_Path'] = snapshort_G['Report_Inf']['Report_Path'] # 2: reload Frame os.system('touch ' + G['Frame_Inf']['Frame_Path']) assert(os.path.isfile(G['Frame_Inf']['Frame_Path'])) frame_fp = open(G['Frame_Inf']['Frame_Path'],'w') for l in snapshort['frame_file_lines']: frame_fp.write(l) frame_fp.close() # 3: reload Report os.system('touch ' + G['Report_Inf']['Report_Path']) assert(os.path.isfile(G['Report_Inf']['Report_Path'])) report_fp = open(G['Report_Inf']['Report_Path'],'w') for l in snapshort['report_file_lines']: report_fp.write(l) report_fp.close() # 4: reload act windows inf need re open at API.py G['EnvSnapshortWinsInf'] = snapshort['act_win_inf'] return # structure ----------------------------------------------------- # frame file_link = { # 'type' : '', topo | check_point | base_module # 'key' : '', topo module name | add check point word | base module name # 'pos' : '', module def pos | add pos | module pos # 'path' : '', module def file path | add file path | module def file path # 'fold_inf' : {}, 'fold_status': on/off/fix # , 'level' : n # # } Frame_Inf = { "Frame_Win_x" : config.frame_window_width # frame window width ,"Frame_Path" : '' ,"FoldLevelSpace" : config.frame_fold_level_space } Frame_Inf['Frame_Path'] = hdl_tags_path + '/' + "Frame.HF" + str(empty_log_index) # report file_link = { # 'key' : '' , signal_name # 'pos' : '' , match_pos # 'path' : '' , match_path # } Report_Inf = { "Report_Win_y" : config.report_window_height # report window height ,"Report_Path" : hdl_tags_path + '/' + "Report.HF" } Report_Inf['Report_Path'] = hdl_tags_path + '/' + "Report.HF" + str(empty_log_index) WorkWin_Inf ={ "MaxNum" : config.max_open_work_window_number ,"OpenWinTrace" : [] } # all vim buffer line file link { path:[...]} VimBufferLineFileLink = {} TraceInf = { 'LastTraceSource' : {'Maybe':[], 'Sure':[], 'ShowIndex': 0, 'SignalName':'', 'Path':'' } # Maybe[{'show':'', 'file_link':{ 'key':'','pos':(l,c),'path':'' } }] ,'LastTraceDest' : {'Maybe':[], 'Sure':[], 'ShowIndex': 0, 'SignalName':'', 'Path':'' } ,'TraceSourceOptimizingThreshold' : config.trace_source_optimizing_threshold } # operation trace OpTraceInf = { 'TracePoints' : [] # {'path':'', "pos":(line, colum), 'key':''} ,'TraceDepth' : config.max_roll_trace_depth ,'Nonius' : -1 # roll nonius } TopoInf = { 'CurModule' : '' ,'TopFoldLevel' : 0 } CheckPointInf = { "MaxNum" : config.max_his_check_point_num ,"CheckPoints" : [] #{}--- key: '', link: {} ,"TopFoldLevel" : 0 } BaseModuleInf = { "BaseModuleThreshold" : config.base_module_threshold # when module inst BaseModuleThreshold times, then default set it to base module ,"BaseModules" : BaseModules # module name set() ,"TopFoldLevel" : 0 } G = { 'HDLTagsActive' : HDLTagsActive ,'SupportVHDLPostfix' : set([]) ,'SupportVerilogPostfix' : set(config.support_verilog_postfix) ,'ModuleInf' : {} ,'ModuleLastCallInf' : {} # {module_name:{ upper_module_name:'', 'upper_inst_name':inst_name} } ,'FileInf' : FileInf ,'CodeDefineInf' : {} # {name: [ {name path pos code_line} ]} ,'OpTraceInf' : OpTraceInf ,"Debug" : config.debug_mode # debug mode ,"ShowReport" : config.show_report ,"ShowFrame" : config.show_sidebar ,"PrintDebug_F" : PrintDebug # function to print debug ,"Frame_Inf" : Frame_Inf # Frame window inf ,"Report_Inf" : Report_Inf # report window inf ,"WorkWin_Inf" : WorkWin_Inf # win config ,"VimBufferLineFileLink" : VimBufferLineFileLink ,"TraceInf" : TraceInf ,"CheckPointInf" : CheckPointInf ,"BaseModuleInf" : BaseModuleInf ,'TopoInf' : TopoInf ,"FixExtraSpace" : True # some situation come extra space, need do nonthing ,"IgnoreNextSpaceOp" : False # just flod has a else space, not do space op ,"EnvSnapshortWinsInf" : [] ,"SaveEnvSnapshort_F" : save_env_snapshort ,"VTagsPath" : hdl_tags_path } # has save history sence then just repaly it start_with_empty_file = False if not vim_start_open_file : start_with_empty_file = True EnvSnapshort = {} if HDLTagsActive and start_with_empty_file and os.path.isfile(hdl_tags_path + '/env_snapshort.pkl'): pkl_input = open(hdl_tags_path + '/env_snapshort.pkl','rb') c_snapshort = pickle.load(pkl_input) if c_snapshort['snapshort_dir_path'] == os.getcwd(): os.system('echo \'do you want reload vim snapshort ? (y/n): \'') yes_or_no = raw_input() if yes_or_no.lower() in ['y','yes']: EnvSnapshort = c_snapshort pkl_input.close() if EnvSnapshort: reload_env_snapshort(EnvSnapshort) """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== import sys import re try: import vim except: pass import os import re from Base import * from Win import * import GLB G = GLB.G #-------------------------------------- SnapshotStack = [] def snapshort_push(): cur_cursor = vim.current.window.cursor cur_pos = (cur_cursor[0]-1, cur_cursor[1]) # minus 1 because cursor start from 1, and lines start from 0 cur_line_num = cur_pos[0] cur_line = vim.current.buffer[cur_line_num] cur_word = get_full_word(cur_line, cur_pos[1]) cur_file_path = vim.current.buffer.name cur_snapshort = {"path": cur_file_path, "pos":cur_pos, "key":cur_word} SnapshotStack.append(cur_snapshort) def snapshort_pop(): pop_snapshort = SnapshotStack[-1] del SnapshotStack[-1] go_win( pop_snapshort['path'], pop_snapshort['pos'], pop_snapshort['key']) #-------------------------------------- def Show(path): # just show frame win , and not go to that window path = get_path_for_name(path) Act_Win = Cur_Act_Win() if path not in Act_Win: snapshort_push() Open(path) snapshort_pop() return #-------------------------------------- def add_trace_point(): cur_cursor = vim.current.window.cursor cur_file_path = vim.current.buffer.name if cur_file_path in [ G['Frame_Inf']['Frame_Path'], G['Report_Inf']['Report_Path'] ]: PrintDebug('Warning: Frame and Report not add trace point !') return cur_pos = (cur_cursor[0]-1, cur_cursor[1]) # minus 1 because cursor start from 1, and lines start from 0 cur_line_num = cur_pos[0] cur_line = vim.current.buffer[cur_line_num] cur_word = get_full_word(cur_line, cur_pos[1]) cur_trace_point = {"path": cur_file_path, "pos":cur_pos, "key":cur_word} cur_nonius = G['OpTraceInf']['Nonius'] TracePoints = G['OpTraceInf']['TracePoints'] # when roll back, and add from middle of queue, just clear old trace point after cur insert index # | 0 | 1 | 2 | 3 | 4 | # ^ if len 5, nonius <= 3 then del 4 if cur_nonius <= (len(TracePoints) - 2): del TracePoints[cur_nonius + 1 : ] # add a new point to TracePoints # if cur add is equ to pre not add if not TracePoints: TracePoints.append(cur_trace_point) else: pre_point = TracePoints[-1] if cur_trace_point != pre_point: TracePoints.append(cur_trace_point) # if length bigger than TraceDepth del TraceDepth = G['OpTraceInf']['TraceDepth'] while (len(TracePoints) > TraceDepth): del TracePoints[0] # if add new point ,nonius assign to len(TracePoints) # | 0 | 1 | 2 | 3 | 4 | # ^ because roll back will first sub 1 G['OpTraceInf']['Nonius'] = len(TracePoints) def get_cur_cursor_inf(): cur_cursor = vim.current.window.cursor cur_line_num = cur_cursor[0] - 1 # minus 1 because cursor start from 1, and lines start from 0 cur_colm_num = cur_cursor[1] cur_line = vim.current.buffer[cur_line_num] cur_word = get_full_word(cur_line, cur_cursor[1]) cur_codes = vim.current.buffer cur_file_path = vim.current.buffer.name cur_hdl_type = get_file_hdl_type(cur_file_path) cur_call_sub_inf = {} cur_module_inf = {} cur_line_inf = get_file_line_inf(cur_line_num, cur_file_path) if cur_line_inf: cur_call_sub_inf = cur_line_inf['line_call_sub_inf'] cur_module_inf = cur_line_inf['line_module_inf'] cur_module_name = '' if cur_module_inf: cur_module_name = cur_module_inf['module_name'] else: PrintDebug('Warning: get_cur_cursor_inf: current cursor %s not in module, file: %s ! '%(cur_cursor.__str__(), cur_file_path )) return { 'cursor' : cur_cursor ,'pos' : (cur_line_num, cur_colm_num) ,'line_num' : cur_line_num ,'colm_num' : cur_colm_num ,'line' : cur_line ,'word' : cur_word ,'file_path' : cur_file_path ,'hdl_type' : cur_hdl_type ,'cur_call_sub_inf' : cur_call_sub_inf ,'cur_module_inf' : cur_module_inf ,'codes' : cur_codes } # ok # report file_link = { # 'key' : '' , signal_name # 'pos' : '' , match_pos # 'path' : '' , match_path # } #----for python edition 2.7 + # def PrintReport(*show, file_link = {}, spec_case = '', mode = 'a'): # # normal show a string # show_str = ' '.join([ i.__str__() for i in show ]) #----for python edition 2.6 def PrintReport(show = '', file_link = {}, spec_case = '', mode = 'a'): if not G['ShowReport']: return has_self_snap_short = False if not cur_in_report(): snapshort_push() Open('Report') has_self_snap_short = True show_str = show if show_str: edit_vim_buffer('Report', [show_str], file_links = [file_link], mode = mode) # show trace source result if spec_case == 'source': edit_vim_buffer('Report', "---------------------------source--------------------------------") t_data = [] t_file_link = [] for Sure in G['TraceInf']['LastTraceSource']['Sure']: t_data.append( Sure['show'] ) t_file_link.append( Sure['file_link'] ) edit_vim_buffer('Report', t_data, t_file_link) edit_vim_buffer('Report', "------------------------maybe source-----------------------------") t_data = [] t_file_link = [] for Maybe in G['TraceInf']['LastTraceSource']['Maybe']: t_data.append( Maybe['show'] ) t_file_link.append( Maybe['file_link'] ) edit_vim_buffer('Report', t_data, t_file_link) edit_vim_buffer('Report', "----------------------------END----------------------------------") edit_vim_buffer('Report', "") # show trace dest result if spec_case == 'dest': edit_vim_buffer('Report', "---------------------------dest--------------------------------") t_data = [] t_file_link = [] for Sure in G['TraceInf']['LastTraceDest']['Sure']: t_data.append( Sure['show'] ) t_file_link.append( Sure['file_link'] ) edit_vim_buffer('Report', t_data, t_file_link) edit_vim_buffer('Report', "------------------------maybe dest-----------------------------") t_data = [] t_file_link = [] for Maybe in G['TraceInf']['LastTraceDest']['Maybe']: t_data.append( Maybe['show'] ) t_file_link.append( Maybe['file_link'] ) edit_vim_buffer('Report', t_data, t_file_link) edit_vim_buffer('Report', "----------------------------END----------------------------------") edit_vim_buffer('Report', "") # go report to the last line, and return assert(cur_in_report()) # if mode == 'a': vim.current.window.cursor = (len(vim.current.buffer) - 1 , 0) vim.command('w!') if has_self_snap_short: snapshort_pop() # ok def show_next_trace_result( trace_type ): if trace_type == 'source': cur_show_index = G['TraceInf']['LastTraceSource']["ShowIndex"] sure_source_len = len(G['TraceInf']['LastTraceSource']['Sure']) maybe_source_len = len(G['TraceInf']['LastTraceSource']['Maybe']) if (sure_source_len + maybe_source_len) == 0: PrintReport('not find source !') return cur_file_link = {} if cur_show_index < sure_source_len: cur_file_link = G['TraceInf']['LastTraceSource']['Sure'][cur_show_index]['file_link'] else: cur_file_link = G['TraceInf']['LastTraceSource']['Maybe'][cur_show_index - sure_source_len]['file_link'] G['TraceInf']['LastTraceSource']["ShowIndex"] = (cur_show_index + 1) % (sure_source_len + maybe_source_len) add_trace_point() go_win( cur_file_link['path'], cur_file_link['pos'], cur_file_link['key'] ) elif trace_type == 'dest': cur_show_index = G['TraceInf']['LastTraceDest']["ShowIndex"] sure_dest_len = len(G['TraceInf']['LastTraceDest']['Sure']) maybe_dest_len = len(G['TraceInf']['LastTraceDest']['Maybe']) if (sure_dest_len + maybe_dest_len) == 0: PrintReport('not find dest !') return cur_file_link = {} if cur_show_index < sure_dest_len: cur_file_link = G['TraceInf']['LastTraceDest']['Sure'][cur_show_index]['file_link'] else: cur_file_link = G['TraceInf']['LastTraceDest']['Maybe'][cur_show_index - sure_dest_len]['file_link'] G['TraceInf']['LastTraceDest']["ShowIndex"] = (cur_show_index + 1) % (sure_dest_len + maybe_dest_len) add_trace_point() go_win( cur_file_link['path'], cur_file_link['pos'], cur_file_link['key']) else: assert(0) #-------------------------------------------------------------------------- def gen_top_topo_data_link(topo_module): topo_datas = [] topo_links = [] topo_module_inf = get_module_inf(topo_module) if not topo_module_inf: PrintDebug('Error: get topo module name %s, should has module inf !'%(topo_module)) return topo_datas, topo_links TopTopoLevel = G['TopoInf']['TopFoldLevel'] TopTopoPrefix = G['Frame_Inf']['FoldLevelSpace'] * TopTopoLevel # add first topo line topo_datas.append(TopTopoPrefix + 'ModuleTopo:') topo_link = { 'type' : 'topo' ,'topo_inst_name' : '' ,'key' : '' ,'pos' : '' ,'path' : '' ,'fold_inf' : {'fold_status':'on', 'level': TopTopoLevel - 1 } } topo_links.append(topo_link) # add cur module name topo_datas.append(TopTopoPrefix + topo_module + ':') topo_link = { 'type' : 'topo' ,'topo_inst_name' : '' ,'key' : topo_module ,'pos' : topo_module_inf['module_pos'] ,'path' : topo_module_inf['file_path'] ,'fold_inf' : {'fold_status':'on', 'level': TopTopoLevel} } topo_links.append(topo_link) # gen current module sub function module, and base module topo inf sub_module_data, sub_module_link = get_fram_topo_sub_inf(topo_module, 0) topo_datas = topo_datas + sub_module_data topo_links = topo_links + sub_module_link return topo_datas, topo_links def edit_frame(data = [], file_links = [], mode = 'a', n = 0, del_range = ()): has_self_snap_short = False if not cur_in_frame(): snapshort_push() Open('Frame') has_self_snap_short = True edit_vim_buffer( path_or_name = 'Frame', data = data, file_links = file_links, mode = mode, n = n, del_range = del_range) # go frame w! and go back assert(cur_in_frame()) vim.command('w!') if has_self_snap_short: snapshort_pop() #--------------------------------------- def show_base_module(fold = True): frame_data = [] frame_link = [] # if frame not show ,show it Show("Frame") # add initial line level = G['BaseModuleInf']['TopFoldLevel'] key = G['Frame_Inf']['FoldLevelSpace']*level + 'BaseModules:' link = { 'type' : 'base_module' ,'key' : '' ,'pos' : '' ,'path' : '' ,'fold_inf' : { 'fold_status': 'on', 'level': level } } frame_data.append(key) frame_link.append(link) # add check points range_inf = get_frame_range_inf() has_base_module = range_inf['has_base_module'] base_module_range = range_inf['base_module_range'] cp_data = [] cp_link = [] if fold: cp_data, cp_link = get_fram_base_module_inf() else: frame_link[-1]['fold_inf']['fold_status'] = 'off' frame_data = frame_data + cp_data frame_link = frame_link + cp_link # del old cp, add new cp if has_base_module: # del edit_frame(mode = 'del', del_range = base_module_range) edit_frame(data = frame_data, file_links = frame_link, mode = 'i', n = base_module_range[0]) return True #------------------------------------- def show_check_point(fold = True): frame_data = [] frame_link = [] # if frame not show ,show it Show("Frame") # add initial line level = G['CheckPointInf']['TopFoldLevel'] key = G['Frame_Inf']['FoldLevelSpace']*level + 'CheckPoints:' link = { 'type' : 'check_point' ,'key' : '' ,'pos' : '' ,'path' : '' ,'fold_inf' : { 'fold_status': 'on', 'level': level } } frame_data.append(key) frame_link.append(link) # add check points range_inf = get_frame_range_inf() has_check_point = range_inf['has_check_point'] check_point_range = range_inf['check_point_range'] cp_data = [] cp_link = [] if fold: cp_data, cp_link = get_fram_check_point_inf() else: frame_link[-1]['fold_inf']['fold_status'] = 'off' frame_data = frame_data + cp_data frame_link = frame_link + cp_link # del old cp, add new cp if has_check_point: # del edit_frame(mode = 'del', del_range = check_point_range) edit_frame(data = frame_data, file_links = frame_link, mode = 'i', n = check_point_range[0]) return True #--------------------------------------- def show_topo(topo_module_name = ''): if not topo_module_name: cursor_inf = get_cur_cursor_inf() if cursor_inf['hdl_type'] != 'verilog': # if not in support file type(verilog,vhdl) just return PrintReport("Warning: Current only support verilog !") return False # get current module inf cur_module_inf = cursor_inf['cur_module_inf'] # current not at module lines, just return if not cur_module_inf: PrintReport("Warning: Current cursor not in valid module !") return False topo_module_name = cur_module_inf['module_name'] else: if topo_module_name not in G['ModuleInf']: PrintReport("Warning: show topo module %s not have database !"%(topo_module_name)) return False # if frame not show ,show it Show("Frame") # current module must has module inf G['TopoInf']['CurModule'] = topo_module_name # note cur topo name for refresh range_inf = get_frame_range_inf() has_topo = range_inf['has_topo'] topo_range = range_inf['topo_range'] topo_data, topo_link = gen_top_topo_data_link(topo_module_name) # del old topo, add new topo if has_topo: # del edit_frame(mode = 'del', del_range = topo_range) edit_frame(data = topo_data, file_links = topo_link, mode = 'i', n = topo_range[0]) return True def iteration_fold_no_module(inst_module_pairs, base_modules): c_frame_range_inf = get_frame_range_inf() if not c_frame_range_inf['has_topo']: return frame_path = G['Frame_Inf']['Frame_Path'] c_topo_range = c_frame_range_inf['topo_range'] c_topo_links = G['VimBufferLineFileLink'][frame_path][c_topo_range[0] : c_topo_range[1]] for i,lk in enumerate(c_topo_links): if not( lk and (lk['fold_inf']['fold_status'] == 'off') and lk['key'] ): continue if lk['topo_inst_name']: c_inst_module_pair = (lk['topo_inst_name'], lk['key']) if c_inst_module_pair in inst_module_pairs: fold_frame_line(lk, i+c_topo_range[0], lk['fold_inf']['level'], 'topo') iteration_fold_no_module(inst_module_pairs, base_modules) return else: if lk['key'] in base_modules: fold_frame_line(lk, i+c_topo_range[0], lk['fold_inf']['level'], 'topo') iteration_fold_no_module(inst_module_pairs, base_modules) return return def refresh_topo(): # get all folded module or inst pair old_frame_range_inf = get_frame_range_inf() if not old_frame_range_inf['has_topo']: return frame_path = G['Frame_Inf']['Frame_Path'] old_topo_range = old_frame_range_inf['topo_range'] old_topo_links = G['VimBufferLineFileLink'][frame_path][old_topo_range[0] + 2 : old_topo_range[1] + 1] old_fold_inst_module_pairs = set() old_fold_base_modules = set() for lk in old_topo_links: if not( lk and (lk['fold_inf']['fold_status'] == 'on') and lk['key'] ): continue if lk['topo_inst_name']: old_fold_inst_module_pairs.add( (lk['topo_inst_name'], lk['key']) ) else: if lk['key'] in G['BaseModuleInf']['BaseModules']: old_fold_base_modules.add(lk['key']) # start new topo new_topo_module_name = G['TopoInf']['CurModule'] show_topo(new_topo_module_name) # iteration opened old folded topo iteration_fold_no_module(old_fold_inst_module_pairs, old_fold_base_modules) #--------------------------------------- def unfold_frame_line(frame_links, frame_line, cur_frame_level, cur_frame_type): assert(frame_links[frame_line]['fold_inf']['fold_status'] == 'on') G['VimBufferLineFileLink'][ G['Frame_Inf']['Frame_Path'] ][frame_line]['fold_inf']['fold_status'] = 'off' unfold_end_line_num = frame_line for i in range(frame_line+1, len(frame_links)): # if cur not have file link, then cur is unflod end if not frame_links[i]: unfold_end_line_num = i - 1 break # if has file link ,but not topo inf then unflod end if frame_links[i]['type'] != cur_frame_type: unfold_end_line_num = i - 1 break # if is topo , but level <= cur level then unflod end if frame_links[i]['fold_inf']['level'] <= cur_frame_level: unfold_end_line_num = i - 1 break # if cur module has no sub module then just return if unfold_end_line_num == frame_line: return True # else edit the frame buffer and file link, del the unflod lines if unfold_end_line_num > frame_line: edit_frame(mode = 'del', del_range = (frame_line + 1, unfold_end_line_num)) return True # else some trouble assert(0),'shold not happen !' def fold_frame_line(cur_line_link, frame_line, cur_frame_level, cur_frame_type): assert(cur_line_link['fold_inf']['fold_status'] == 'off') G['VimBufferLineFileLink'][ G['Frame_Inf']['Frame_Path'] ][frame_line]['fold_inf']['fold_status'] = 'on' if cur_frame_type == 'topo': # if cur is ModuleTopo: line, show refresh topo if cur_frame_level == G['TopoInf']['TopFoldLevel'] - 1: topo_module_name = G['TopoInf']['CurModule'] show_topo(topo_module_name) return # cur_line_link['key'] is the cur topo line module name cur_module_name = cur_line_link['key'] if not cur_module_name: PrintReport('Warning: cur topo line has no module name !') return if cur_module_name not in G['ModuleInf']: PrintReport('Warning: cur module: \"%s\" has no database !'%(cur_module_name)) return # get cur module sub module inf sub_topo_data, sub_topo_link = get_fram_topo_sub_inf(cur_module_name, cur_frame_level) # add cur module topo inf to frame edit_frame(data = sub_topo_data, file_links = sub_topo_link, mode = 'i', n = frame_line + 1) elif cur_frame_type == 'check_point': show_check_point() elif cur_frame_type == 'base_module': show_base_module() else: PrintReport('Warning: no operation in this line !') return def frame_line_fold_operation(frame_line): frame_path = G['Frame_Inf']['Frame_Path'] frame_links = G['VimBufferLineFileLink'][frame_path] cur_line_link = frame_links[frame_line] if not cur_line_link : PrintReport('Warning: cur frame line no fold operation !') return cur_frame_type = cur_line_link['type'] cur_frame_level = cur_line_link['fold_inf']['level'] cur_fold_state = cur_line_link['fold_inf']['fold_status'] if cur_fold_state == 'off': fold_frame_line(cur_line_link, frame_line, cur_frame_level, cur_frame_type) elif cur_fold_state == 'on': unfold_frame_line(frame_links, frame_line, cur_frame_level, cur_frame_type) else: PrintReport('Warning: cur frame line no fold operation !') return """ https://my.oschina.net/u/2520885 """ #=============================================================================== # Copyright (C) 2016 by Jun Cao # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #=============================================================================== try: import vim except: pass import sys import re import os import GLB G = GLB.G from Base import * def Reset_Win_Size(): cur_act_wins = Cur_Act_Win() if G['Report_Inf']['Report_Path'] in cur_act_wins: Jump_To_Win(G['Report_Inf']['Report_Path']) vim.command('wincmd J') vim.current.window.height = G['Report_Inf']['Report_Win_y'] if G['Frame_Inf']['Frame_Path'] in cur_act_wins: Jump_To_Win(G['Frame_Inf']['Frame_Path']) vim.command('wincmd H') vim.current.window.width = G['Frame_Inf']['Frame_Win_x'] return def Refresh_OpenWinTrace(): cur_act_win_path = Cur_Act_Win() cur_act_work_win_path = cur_act_win_path - set([ G["Report_Inf"]["Report_Path"], G["Frame_Inf"]["Frame_Path"] ]) i = 0 while i < len(G['WorkWin_Inf']['OpenWinTrace']) : c_path = G['WorkWin_Inf']['OpenWinTrace'][i] if c_path not in cur_act_work_win_path: del G['WorkWin_Inf']['OpenWinTrace'][i] else: i += 1 return def Cur_Act_Win(): Act_Win = set() for w in vim.windows: Act_Win.add(w.buffer.name) return Act_Win def Open(name): path = get_path_for_name(name) Act_Win = Cur_Act_Win() if path in Act_Win: # win has open and just jump to than window Jump_To_Win(path) elif path == G['Frame_Inf']["Frame_Path"]: Open_Frame_Win() elif path == G['Report_Inf']["Report_Path"]: Open_Report_Win() else: Open_Work_Win(path) Reset_Win_Size() Jump_To_Win(path) assert(vim.current.buffer.name == path) def Jump_To_Win(path): cur_act_wins = Cur_Act_Win() assert(path in cur_act_wins) start_path = vim.current.buffer.name if start_path == path: return vim.command('wincmd w') cur_path = vim.current.buffer.name while cur_path != start_path: if cur_path == path: break vim.command("wincmd w") cur_path = vim.current.buffer.name assert(vim.current.buffer.name == path),'vim.current.buffer.name: %s, path: %s'%(vim.current.buffer.name, path) def Open_Frame_Win(): G['VimBufferLineFileLink'].setdefault(G["Frame_Inf"]["Frame_Path"],[{}]) vim.command("vertical topleft sp " + G["Frame_Inf"]["Frame_Path"]) def Open_Report_Win(): G['VimBufferLineFileLink'].setdefault(G["Report_Inf"]["Report_Path"],[{}]) vim.command("bot sp " + G["Report_Inf"]["Report_Path"]) if G["Frame_Inf"]["Frame_Path"] in Cur_Act_Win(): Jump_To_Win(G["Frame_Inf"]["Frame_Path"]) vim.command('wincmd H') Jump_To_Win(G["Report_Inf"]["Report_Path"]) def Open_Work_Win(path): # path must valid assert(os.path.isfile(path)) # refresh open work win trace Refresh_OpenWinTrace() # leave at most G['WorkWin_Inf']['MaxNum'] work win win_num_need_to_close = len(G['WorkWin_Inf']['OpenWinTrace']) - G['WorkWin_Inf']['MaxNum'] for i in range(win_num_need_to_close): win_path_need_close = G['WorkWin_Inf']['OpenWinTrace'][i] Jump_To_Win(win_path_need_close) vim.command('q') del G['WorkWin_Inf']['OpenWinTrace'][i] # if has work win cur_work_win_num = len(G['WorkWin_Inf']['OpenWinTrace']) if cur_work_win_num > 0: # case 0: has work win, and num less than max # just go last work win, and vsp a new win if cur_work_win_num < G['WorkWin_Inf']['MaxNum']: Jump_To_Win(G['WorkWin_Inf']['OpenWinTrace'][-1]) vim.command('vsp '+path) else: # case 1: opened all work win, just replace the oldest open work win Jump_To_Win(G['WorkWin_Inf']['OpenWinTrace'][0]) vim.command('e '+path) del G['WorkWin_Inf']['OpenWinTrace'][0] # replace [0], just del old else: # cur no work win cur_act_win_paths = Cur_Act_Win() cur_act_hold_wins = cur_act_win_paths - set([G["Report_Inf"]["Report_Path"], G["Frame_Inf"]["Frame_Path"]]) # if has hold win, go hold win, vsp if cur_act_hold_wins: Jump_To_Win(list(cur_act_hold_wins)[0]) vim.command('vsp '+path) elif G["Report_Inf"]["Report_Path"] in cur_act_win_paths: # if no hold win, has report , go report sp new Jump_To_Win(G["Report_Inf"]["Report_Path"]) vim.command('sp '+path) else: vim.command('vsp '+path) # finial add path to trace assert(vim.current.buffer.name == path) G['WorkWin_Inf']['OpenWinTrace'].append(path) def get_file_vim_buffer(path): for i,b in enumerate(vim.buffers): if b.name == path: return b # path buffer not open vim.command("bad "+path) assert(vim.buffers[ len(vim.buffers) - 1].name == path) return vim.buffers[ len(vim.buffers) - 1] # edit the vim buffer, with put data at some position # mode : a --after : append data after current buffer data # b --before : append data before current buffer data # w --write : clear old buffer data, and write data # i --insert : inster list to n # del -- delete : delete del_range lines # del_range : (start,end) del range, include end def edit_vim_buffer(path_or_name = '', data = [], file_links = [], mode = 'a', n = 0, del_range = ()): # weather to edit link buffer need_edit_buffer_file_link = False if data == [] and mode != 'del': PrintDebug('Warning: edit_vim_buffer: edit file with empty data= [], file:%s !'%(path_or_name)) return if type(data) is str: data = [data] path = get_path_for_name(path_or_name) # some time edit other buffer, may change cur window cursor or add empty line to cur buffer file, # so must edit current buffer assert(vim.current.buffer.name == path),'%s,%s'%(vim.current.buffer.name, path) if path in [G['Report_Inf']['Report_Path'], G['Frame_Inf']['Frame_Path']]: need_edit_buffer_file_link = True if file_links: assert(len(data) == len(file_links)) else: file_links = [ {} for i in range(len(data))] # PrintDebug('edit_vim_buffer path_or_name:'+path_or_name) # PrintDebug('edit_vim_buffer data:'+data.__str__()) # PrintDebug('edit_vim_buffer file_links:'+file_links.__str__()) # PrintDebug('edit_vim_buffer mode:'+mode.__str__()) # PrintDebug('edit_vim_buffer n:'+n.__str__()) # PrintDebug('edit_vim_buffer del_range:'+del_range.__str__()) t_buffer = get_file_vim_buffer(path) assert(t_buffer) if mode is 'w': del t_buffer[:] t_buffer.append(data) del t_buffer[:1] if need_edit_buffer_file_link: G["VimBufferLineFileLink"][path] = file_links elif mode is 'a': t_buffer.append(data) if need_edit_buffer_file_link: G["VimBufferLineFileLink"].setdefault(path,[]) G["VimBufferLineFileLink"][path] = G["VimBufferLineFileLink"][path] + file_links elif mode is 'b': t_buffer.append(data, 0) if need_edit_buffer_file_link: G["VimBufferLineFileLink"].setdefault(path,[]) G["VimBufferLineFileLink"][path] = file_links + G["VimBufferLineFileLink"][path] elif mode is 'i': while len(t_buffer) <= n+1: t_buffer.append('') if need_edit_buffer_file_link: G["VimBufferLineFileLink"][path].append({}) t_buffer.append(data, n) if need_edit_buffer_file_link: G["VimBufferLineFileLink"].setdefault(path,[]) G["VimBufferLineFileLink"][path] = G["VimBufferLineFileLink"][path][:n] + file_links + G["VimBufferLineFileLink"][path][n:] elif mode is 'del': assert(del_range != () ) if type(del_range) is int: del t_buffer[del_range] del G["VimBufferLineFileLink"][path][del_range] elif type(del_range) in [ tuple, list ]: del t_buffer[del_range[0]:del_range[1]+1] del G["VimBufferLineFileLink"][path][del_range[0]:del_range[1]+1] else: assert(0) def go_win( path_or_name = '', pos = (), search_word = ''): if not path_or_name: return # path_or_name = vim.current.buffer.name Open(path_or_name) if re.search('\w+',search_word): vim.current.window.cursor = (1,0) # search from top in case match to left vim warning vim.command('/\c\<'+search_word+'\>') if pos: cursor = (pos[0]+1, pos[1]) vim.current.window.cursor = cursor ############################################################################