feat: 集成 waveform_trace 波形调试工具

新增功能:
- waveformTracer.ts: 调用 waveform_trace.exe 的工具实现
- toolExecutor.ts: 添加 waveform_trace 工具分发
- types/api.ts: 添加 WaveformTraceArgs 类型定义

工具源码 (tools/waveform_trace/src/):
- AST 解析 + BFS 信号追踪
- VCD 波形解析
- 修复通用 testbench 支持

配置文件:
- .gitignore: 排除 exe 和打包产物
- .vscodeignore: 发布时排除源码
- build.bat/build.sh: 打包脚本
This commit is contained in:
XiaoFeng
2026-01-05 18:18:57 +08:00
parent e48e822d07
commit ada4806493
173 changed files with 57092 additions and 4 deletions

View File

@ -0,0 +1,144 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# Author : Chia-Tung (Mark) Ho, NVIDIA
#
from __future__ import print_function
import sys
import os
from optparse import OptionParser
# 优先使用本地修改过的 pyverilog包含 toplogic_tree_traverse 方法)
_local_path = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, _local_path)
from pyverilog.vparser.parser import parse
from io import StringIO
import networkx as nx
# importing matplotlib.pyplot
import matplotlib.pyplot as plt
import re
# create graph from ast str
# directed graph from networkX
def create_graph_from_ast(ast, display=False, display_signal_only=False):
graph = nx.DiGraph()
ast.toplogic_tree_traverse(network_G=graph, rvalue=False, lvalue=False)
if not display and not display_signal_only:
return graph
# Print out nodes with attributes
nodes_to_display = []
edges_to_display = []
print("Nodes:")
for node, attrs in graph.nodes(data=True):
if display_signal_only and (not re.match("^Assign", node) and not re.match("^Always", node) and not re.match("^Module", node)):
nodes_to_display.append(node)
print(f"Node {node}: {attrs}")
# Print out edges with attributes
print("\nEdges:")
for src, dst, attrs in graph.edges(data=True):
if display_signal_only and src in nodes_to_display and dst in nodes_to_display:
edges_to_display.append((src, dst))
print(f"Edge {src} to {dst}: {attrs}")
# displaying graphs
plt.figure(figsize=(18, 16)) # Set the figure size
pos = nx.spring_layout(graph, k=1.0)
if display_signal_only:
subgraph = graph.subgraph(nodes_to_display)
# subgraph.add_edges_from(edges_to_display)
else:
subgraph = graph
nx.draw_networkx(subgraph, pos, with_labels=True) # Draw the graph without labels
# Add node labels
# node_labels = nx.get_node_attributes(graph, 'label')
# nx.draw_networkx_labels(graph, pos, labels=node_labels)
# edge labels
edge_labels = nx.get_edge_attributes(subgraph, 'lines')
nx.draw_networkx_edge_labels(
subgraph, pos,
edge_labels=edge_labels,
font_color='blue'
)
# plt.axis('off')
plt.show()
return graph
def get_ast_structure_str(ast):
normal_stdout = sys.stdout
# put the string output to a string buffer
result = StringIO()
sys.stdout = result
# traverse the ast
ast.show(buf=sys.stdout)
# Redirect std output to the normal mode
sys.stdout = normal_stdout
# Get the result out
ast_str = result.getvalue()
# print('ast str = ', ast_str, '\n ast end')
return ast_str
def generate_top_logic_graph(filelist: list[str]):
for f in filelist:
if not os.path.exists(f):
raise IOError("file not found: " + f)
ast, directives = parse(filelist,
preprocess_include=[],
preprocess_define=[])
# ast_str = get_ast_structure_str(ast)
return create_graph_from_ast(ast, display=False, display_signal_only=False)
def main():
INFO = "Verilog code parser"
VERSION = pyverilog.__version__
USAGE = "Usage: python example_parser.py file ..."
def showVersion():
print(INFO)
print(VERSION)
print(USAGE)
sys.exit()
optparser = OptionParser()
optparser.add_option("-v", "--version", action="store_true", dest="showversion",
default=False, help="Show the version")
optparser.add_option("-I", "--include", dest="include", action="append",
default=[], help="Include path")
optparser.add_option("-D", dest="define", action="append",
default=[], help="Macro Definition")
(options, args) = optparser.parse_args()
filelist = args
# print(filelist)
if options.showversion:
showVersion()
for f in filelist:
if not os.path.exists(f):
raise IOError("file not found: " + f)
if len(filelist) == 0:
showVersion()
ast, directives = parse(filelist,
preprocess_include=options.include,
preprocess_define=options.define)
# ast_str = get_ast_structure_str(ast)
create_graph_from_ast(ast, display_signal_only=True, display=True)
ast.show(attrnames=True)
if __name__ == '__main__':
main()