بنقرة واحدة
new-verilog-project
新建 Verilog 仿真项目,搭建环境。触发词包括:新建项目、建立Verilog环境、初始化工程、搭建仿真环境、新建Verilog工程
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
新建 Verilog 仿真项目,搭建环境。触发词包括:新建项目、建立Verilog环境、初始化工程、搭建仿真环境、新建Verilog工程
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
创建 SystemVerilog 测试平台文件。触发词包括:创建TB、写testbench、新建测试平台、生成TB、写TB、创建仿真测试文件
编写和审查可综合的 Verilog RTL 代码。当用户要求编写、设计、实现、修复或审查任何 Verilog/RTL 模块、 硬件模块或数字逻辑时自动触发。触发词包括:写Verilog、写RTL、实现模块、设计电路、review代码、 审查Verilog、FSM、状态机、FIFO、pipeline、流水线、arbiter、仲裁器、counter、计数器、 shift register、移位寄存器、handshake、握手协议、AXI、APB、SPI、I2C、UART、 clock divider、分频器、debounce、去抖、edge detector、边沿检测、synchronizer、同步器、 dual-port RAM、双端口RAM。即使用户只说"写一个模块"或"实现这个功能"而没有显式提到"Verilog", 也应使用此 skill。涵盖新代码生成和已有 Verilog 代码的 review/debug。
استنادا إلى تصنيف SOC المهني
| name | new-verilog-project |
| description | 新建 Verilog 仿真项目,搭建环境。触发词包括:新建项目、建立Verilog环境、初始化工程、搭建仿真环境、新建Verilog工程 |
在当前工作目录下创建完整的 Verilog 仿真项目结构。
./
├── RTL/ (仅在不存在时创建;已存在则保留原内容不动)
├── TB/
│ └── tb_top.sv (仅在 TB/ 内无仿真文件时由 tb-creator skill 生成)
├── .vscode/
│ └── tasks.json
├── .gitignore
├── gen_filelist.py
├── gen_dumpvars.py
├── clean.py
└── CLAUDE.md
{
"version": "2.0.0",
"tasks": [
{
"label": "Generate Filelist",
"type": "shell",
"command": "python",
"args": ["gen_filelist.py"],
"group": "build"
},
{
"label": "iverilog compile",
"type": "shell",
"command": "iverilog",
"args": [
"-o", "sim.vvp",
"-g2012",
"-f", "filelist.f"
],
"group": {
"kind": "build",
"isDefault": false
},
"problemMatcher": []
},
{
"label": "vvp run",
"type": "shell",
"command": "vvp sim.vvp -fst",
"group": {
"kind": "build",
"isDefault": false
},
"problemMatcher": []
},
{
"label": "Gen Dumpvars",
"type": "shell",
"command": "python",
"args": ["gen_dumpvars.py", "--patch"],
"group": "build",
"problemMatcher": []
},
{
"label": "clean",
"type": "shell",
"command": "python",
"args": ["clean.py"],
"group": "build",
"problemMatcher": []
},
{
"label": "compile and run",
"dependsOn": ["Generate Filelist","Gen Dumpvars","iverilog compile", "vvp run"],
"dependsOrder": "sequence",
"group": {
"kind": "build",
"isDefault": false
},
"problemMatcher": []
}
]
}
import os
extensions = ('.v', '.sv')
dirs = ['RTL', 'TB']
with open('filelist.f', 'w') as f:
for d in dirs:
if not os.path.exists(d):
continue
for root, _, files in os.walk(d):
for file in files:
if file.endswith(extensions):
path = os.path.join(root, file).replace('\\', '/')
f.write(path + '\n')
print("Generated filelist.f")
#!/usr/bin/env python3
"""
gen_dumpvars.py
自动扫描 RTL 文件中的非压缩数组,结合实例化层次,
生成 DUMP_ARRAY 宏调用,可选地直接更新 TB 的波形 initial 块。
用法:
python gen_dumpvars.py # 仅打印生成结果
python gen_dumpvars.py --patch # 同时更新 TB 文件
"""
import re, sys, argparse
from pathlib import Path
FILELIST = "filelist.f"
SV_KEYWORDS = {
'module','endmodule','input','output','inout','wire','reg','logic',
'integer','genvar','begin','end','if','else','for','always','initial',
'assign','parameter','localparam','generate','endgenerate','task',
'function','endtask','endfunction','case','casex','casez','endcase',
'posedge','negedge','repeat','while','fork','join','string','bit',
'byte','int','real','time','signed','unsigned','automatic',
'supply0','supply1','tri','triand','trior','wand','wor',
}
# ── 工具 ──────────────────────────────────────────────────────────
def strip_comments(src):
src = re.sub(r'//[^\n]*', '', src)
src = re.sub(r'/\*.*?\*/', ' ', src, flags=re.S)
return src
def read_filelist(path=FILELIST):
files = []
with open(path) as f:
for line in f:
line = line.strip().replace('\\', '/')
if line and not line.startswith('//'):
files.append(line)
return files
# ── 解析 ──────────────────────────────────────────────────────────
def extract_params(body):
"""提取 parameter / localparam 的字面量值"""
params = {}
for m in re.finditer(
r'\b(?:parameter|localparam)\b\s*(?:\[[^\]]*\]\s*)?(\w+)\s*=\s*([^;,\n]+)',
body
):
name = m.group(1)
expr = m.group(2).strip()
try:
val = eval(expr, {"__builtins__": {}}, dict(params))
params[name] = int(val)
except Exception:
pass
return params
def resolve(expr, params):
try:
return int(eval(expr.strip(), {"__builtins__": {}}, params))
except Exception:
return None
def parse_module(body):
"""
解析模块体,返回:
arrays : [(arr_name, size)]
reg_insts : [(mod_type, inst_name)] -- generate 块之外
gen_insts : [(gen_label, mod_type, inst_name)] -- generate 块内
"""
params = extract_params(body)
# ── 非压缩数组声明(reg / wire)──────────────────────────────
arrays = []
for a in re.finditer(
r'\b(?:reg|wire)\b\s*(?:signed\s*)?(?:\[[^\]]*\]\s*)?' # 类型 + 可选位宽
r'(\w+)\s*' # 数组名
r'\[\s*([^\]:]+?)\s*:\s*([^\]]+?)\s*\]\s*;', # [hi : lo];
body
):
name = a.group(1)
if name in SV_KEYWORDS:
continue
hi = resolve(a.group(2), params)
lo = resolve(a.group(3), params)
if hi is not None and lo is not None:
arrays.append((name, abs(hi - lo) + 1))
# ── generate 块内的实例化 ─────────────────────────────────────
gen_insts = []
for gen in re.finditer(r'\bgenerate\b(.*?)\bendgenerate\b', body, re.S):
for blk in re.finditer(
r'\bbegin\s*:\s*(\w+)\b(.*?)\bend\b',
gen.group(1), re.S
):
label = blk.group(1)
blk_body = blk.group(2)
for m in re.finditer(
r'\b(\w+)\s*(?:#\s*\([^;]*?\)\s*)?(\w+)\s*\(', blk_body
):
mtype, iname = m.group(1), m.group(2)
if mtype not in SV_KEYWORDS and iname not in SV_KEYWORDS:
gen_insts.append((label, mtype, iname))
# ── generate 块外的常规实例化 ─────────────────────────────────
body_no_gen = re.sub(r'\bgenerate\b.*?\bendgenerate\b', '', body, flags=re.S)
reg_insts = []
for m in re.finditer(
r'\b(\w+)\s*(?:#\s*\([^;]*?\)\s*)?(\w+)\s*\(', body_no_gen
):
mtype, iname = m.group(1), m.group(2)
if mtype not in SV_KEYWORDS and iname not in SV_KEYWORDS:
reg_insts.append((mtype, iname))
return arrays, reg_insts, gen_insts
def parse_all(files):
"""返回 {mod_name: (arrays, reg_insts, gen_insts)}"""
all_mods = {}
for f in files:
try:
src = Path(f).read_text(encoding='utf-8', errors='replace')
clean = strip_comments(src)
for m in re.finditer(
r'\bmodule\s+(\w+)\b(.*?)\bendmodule\b', clean, re.S
):
name, body = m.group(1), m.group(2)
all_mods[name] = parse_module(body)
except Exception as e:
print(f'[警告] 解析 {f} 失败: {e}', file=sys.stderr)
return all_mods
# ── 层次遍历 ──────────────────────────────────────────────────────
def collect(all_mods, start_insts):
"""
DFS 收集所有 DUT 内部非压缩数组。
start_insts: [(mod_type, inst_name)] — TB 的顶层 DUT 实例
返回 [(path, size)]
"""
results = []
visited = set()
def dfs(mod_name, prefix):
key = (mod_name, prefix)
if key in visited or mod_name not in all_mods:
return
visited.add(key)
arrays, reg_insts, gen_insts = all_mods[mod_name]
for arr_name, size in arrays:
results.append((f'{prefix}.{arr_name}', size))
for mtype, iname in reg_insts:
if mtype in all_mods:
dfs(mtype, f'{prefix}.{iname}')
# generate 实例:波形只关注 [0](其余通道结构相同)
for label, mtype, iname in gen_insts:
if mtype in all_mods:
dfs(mtype, f'{prefix}.{label}[0].{iname}')
for mtype, iname in start_insts:
if mtype in all_mods:
dfs(mtype, iname)
return results
# ── 生成 initial 块文本 ───────────────────────────────────────────
def gen_block(tb_mod, entries):
lines = [
'initial begin',
' $dumpfile("wave.fst");',
f' $dumpvars(0, {tb_mod});',
]
for path, size in entries:
lines.append(f' `DUMP_ARRAY({path}, {size})')
lines.append('end')
return '\n'.join(lines)
# ── 更新 TB 文件 ──────────────────────────────────────────────────
def patch_tb(tb_path, new_block):
src = Path(tb_path).read_text(encoding='utf-8')
lines = src.split('\n')
start_i = end_i = None
for i, line in enumerate(lines):
if re.search(r'\binitial\s+begin\b', line):
window = '\n'.join(lines[i: i + 6])
if '$dumpfile' in window:
start_i = i
depth = 0
for j in range(i, len(lines)):
depth += len(re.findall(r'\bbegin\b', lines[j]))
depth -= len(re.findall(r'\bend\b', lines[j]))
if depth == 0 and j > i:
end_i = j
break
break
if start_i is not None and end_i is not None:
new_lines = (lines[:start_i]
+ new_block.split('\n')
+ lines[end_i + 1:])
Path(tb_path).write_text('\n'.join(new_lines), encoding='utf-8')
print(f'[已更新] {tb_path}')
else:
# 找到 endmodule 的位置,把 dump initial 块插入到它前面
endmod_i = None
for i, line in enumerate(lines):
if re.search(r'\bendmodule\b', line):
endmod_i = i
break
if endmod_i is not None:
new_lines = (lines[:endmod_i]
+ ['']
+ new_block.split('\n')
+ ['']
+ lines[endmod_i:])
Path(tb_path).write_text('\n'.join(new_lines), encoding='utf-8')
print(f'[已插入] {tb_path}(在 endmodule 前新增 dump initial 块)')
else:
print('[警告] 未找到 endmodule,无法自动插入,请手动添加。', file=sys.stderr)
# ── main ──────────────────────────────────────────────────────────
def main():
ap = argparse.ArgumentParser(description='自动生成 $dumpvars 波形 initial 块')
ap.add_argument('--patch', action='store_true',
help='直接更新 TB 文件中的 dump initial 块')
args = ap.parse_args()
files = read_filelist()
tb_files = [f for f in files if Path(f).stem.startswith('tb_')]
all_mods = parse_all(files)
# 找 TB 顶层模块名 & DUT 实例列表
tb_mod = None
start_insts = []
for tf in tb_files:
src = Path(tf).read_text(encoding='utf-8', errors='replace')
clean = strip_comments(src)
m = re.search(r'\bmodule\s+(\w+)\b(.*?)\bendmodule\b', clean, re.S)
if m:
tb_mod = m.group(1)
_, reg_insts, _ = parse_module(m.group(2))
for mtype, iname in reg_insts:
if mtype in all_mods and mtype != tb_mod:
start_insts.append((mtype, iname))
break
if not tb_mod:
print('错误:找不到 TB 模块', file=sys.stderr)
sys.exit(1)
entries = collect(all_mods, start_insts)
# 去重,保留首次出现
seen, unique = set(), []
for path, size in entries:
if path not in seen:
seen.add(path)
unique.append((path, size))
block = gen_block(tb_mod, unique)
print('\n=== 生成的 dump initial 块 ===')
print(block)
print('==============================\n')
if args.patch:
for tf in tb_files:
patch_tb(tf, block)
if __name__ == '__main__':
main()
import os
import glob
import shutil
for fst in glob.glob("*.fst"):
base = os.path.splitext(fst)[0]
for ext in [".fst", ".vcd"]:
target = base + ext
if os.path.exists(target):
os.remove(target)
print(f"Deleted: {target}")
for f in ["filelist.f", "sim.vvp"]:
if os.path.exists(f):
os.remove(f)
print(f"Deleted: {f}")
for cache_dir in glob.glob("**/__pycache__", recursive=True):
shutil.rmtree(cache_dir, ignore_errors=True)
print(f"Deleted: {cache_dir}")
for pyc in glob.glob("**/*.pyc", recursive=True):
os.remove(pyc)
print(f"Deleted: {pyc}")
print("Clean done.")
# 仿真产物
*.fst
*.vvp
filelist.f
# Python 缓存
__pycache__/
*.pyc
## 回答规范
每次回答结束后,必须在末尾附上:
- 当前使用的模型名称
- 当前的effort 级别(如果有)
RTL 目录:使用 Glob 检查 RTL/ 下是否有任意文件:
RTL/.gitkeep(空文件,确保目录存在)RTL/ 做任何操作使用 Write 工具依次创建以下文件(直接覆盖,不询问):
.vscode/tasks.json.gitignoregen_filelist.pygen_dumpvars.pyclean.pyCLAUDE.md.claude/settings.local.json(内容如下,用于自动授权 iverilog 编译和仿真命令){
"permissions": {
"allow": [
"Bash(iverilog -o sim.vvp -g2012 -f filelist.f)",
"Bash(vvp sim.vvp -fst)"
]
}
}
TB 目录:使用 Glob 检查 TB/ 下是否存在 .v 或 .sv 文件:
tb-creator skill 生成 TB/tb_top.svTB/ 做任何操作tasks.json:创建或覆盖 .vscode/tasks.json,不询问用户任何问题
全部完成后,告知用户"Verilog 项目环境已就绪",并列出创建/跳过的文件清单。