Python脚本自动化解析Verilog RTL模块依赖与可视化层次关系

发布时间:2026/6/20 20:15:06
Python脚本自动化解析Verilog RTL模块依赖与可视化层次关系 1. 为什么需要解析Verilog模块依赖关系当你接手一个大型数字IC设计项目时面对动辄上百个Verilog模块文件最头疼的问题就是理不清模块之间的调用关系。我去年参与一个SoC项目时就深有体会 - 项目代码库里有300多个RTL文件光是搞清楚顶层模块调用了哪些子模块就花了两天时间。传统的手工梳理方法效率极低需要逐个打开.v文件查找module实例化语句遇到跨多级调用时容易遗漏中间模块无法直观展示层次结构关系每次设计变更都需要重新人工检查这时候就需要自动化工具来帮忙了。用Python脚本解析Verilog RTL的模块依赖关系可以快速生成模块调用树一目了然看清设计层次自动生成文件列表方便验证平台调用发现潜在问题比如循环引用、悬空模块辅助文档生成作为设计文档的架构图基础2. 核心实现思路解析2.1 正则表达式匹配模块实例化解析Verilog代码的关键在于识别模块实例化语句。典型的实例化语法如下module_top u_module_top ( .clk(clk), .rst(rst) );我们可以用正则表达式捕获这种模式verilog_module_pattern r(\w)\s\w\s*\([\s\S]*?\)\;这个正则表达式的含义是(\w)匹配模块名如module_top\s\w\s*匹配实例名如u_module_top\([\s\S]*?\)\;匹配括号内的端口连接2.2 递归遍历模块层次解析的核心算法是递归遍历从顶层模块开始解析找到所有直接实例化的子模块对每个子模块重复步骤1-2用depth变量记录当前递归深度def getAllModule(in_file, depth1): sub_list getSubModule(in_file) for module in sub_list: print(--*depth module) # 根据深度缩进 getAllModule(module, depth1) # 递归调用2.3 处理特殊情况的技巧实际项目中会遇到各种特殊情况需要处理关键字冲突避免匹配到Verilog关键字如always、begin文件路径处理不同操作系统路径分隔符兼容/vs\重复模块用集合(Set)自动去重悬空模块检查.v文件是否存在3. 完整代码实现与解析下面是我优化后的完整脚本增加了更多实用功能#!/usr/bin/env python3 # verilog_module_parser.py - 解析Verilog模块层次关系 import os import re import sys from collections import defaultdict class VerilogParser: def __init__(self): self.module_deps defaultdict(list) self.all_modules set() def parse_file(self, filepath): 解析单个Verilog文件中的模块实例化 with open(filepath, r) as f: content f.read() # 移除注释避免干扰 content re.sub(r//.*?$|/\*.*?\*/, , content, flagsre.DOTALL|re.MULTILINE) # 匹配模块实例化 pattern r\b([a-zA-Z_]\w*)\s[a-zA-Z_]\w*\s*\([^;]*\); matches re.findall(pattern, content) # 过滤Verilog关键字 keywords {begin, end, module, always, if, else} return [m for m in matches if m not in keywords] def build_dependency(self, top_module, base_path.): 递归构建模块依赖关系 if top_module in self.module_deps: return filepath os.path.join(base_path, f{top_module}.v) if not os.path.exists(filepath): print(fWarning: {filepath} not found) return self.all_modules.add(top_module) submodules self.parse_file(filepath) self.module_deps[top_module] submodules for module in submodules: self.build_dependency(module, base_path) def print_hierarchy(self, module, depth0, fileNone): 打印模块层次树 indent * depth line f{indent}└── {module} print(line) if file: file.write(line \n) for sub in self.module_deps.get(module, []): self.print_hierarchy(sub, depth1, file) def generate_dot(self, output_file): 生成Graphviz DOT格式的可视化文件 with open(output_file, w) as f: f.write(digraph G {\n) f.write( rankdirTB;\n) for module, subs in self.module_deps.items(): for sub in subs: f.write(f {module} - {sub};\n) f.write(}\n) if __name__ __main__: if len(sys.argv) 2: print(Usage: python verilog_module_parser.py TOP_MODULE [BASE_PATH]) sys.exit(1) parser VerilogParser() top_module sys.argv[1] base_path sys.argv[2] if len(sys.argv) 2 else . parser.build_dependency(top_module, base_path) # 打印文本层次结构 print(f\nModule hierarchy for {top_module}:) parser.print_hierarchy(top_module) # 生成DOT文件用于可视化 dot_file f{top_module}_hierarchy.dot parser.generate_dot(dot_file) print(f\nDOT file generated: {dot_file}) print(Use dot -Tpng -o hierarchy.png hierarchy.dot to generate image)4. 高级功能扩展4.1 生成可视化图形单纯的文本树状图不够直观我们可以生成Graphviz DOT格式文件使用dot命令转换为PNG/SVG图片dot -Tpng -o hierarchy.png hierarchy.dot4.2 支持SystemVerilog特性现代设计常用SystemVerilog需要扩展支持接口(interface)解析程序包(package)引用宏定义(ifdef)条件编译4.3 集成到CI流程将模块依赖检查加入持续集成检查循环依赖验证模块完整性生成文档自动更新5. 实际项目中的应用技巧在真实项目中应用时有几个实用建议多维度输出除了文本树状图还可以生成CSV格式的模块清单Markdown格式的设计文档HTML交互式浏览界面性能优化对于超大型设计添加缓存机制避免重复解析支持增量更新多线程并行解析错误处理记录解析失败的模块支持黑名单排除特定模块提供详细日志模式我在一个GPU项目中应用这套脚本后模块理解时间从3天缩短到2小时。特别是当设计频繁变更时一键重新生成依赖关系图的功能简直救命。