Files
skills-win/rtl-ip-replace/scripts/ipflow_common.py
T
bowei ea4541ee90 sync: SHANGHAI-U9 2026-07-27 三个 Simulink→RTL skill 转系统级 + 新增 simulink-rtl-redev
- simulink_rtl_dev / rtl-ip-replace: 从工程级 .claude/skills 迁到用户级并去工程耦合
  (模型名/Notes 文档依赖/工程实测基线移出; addpath 与脚本路径改用户级)
- rtl-ip-replace/scripts/gen_cmp_tb.py: Vivado 路径不再写死, 改读 VIVADO_PATH /
  XILINX_VIVADO (兼容 install root / bin / bin\vivado.bat 三种写法), 回落时提示
  去设 skills_env.md 的 VIVADO_PATH
- simulink-rtl-redev: 新增。原生模型改动后的仿真模型同步规范, 含两个实测过的工具
  check_sync.py (三条时序链新鲜度闸门) 与 measure_k.m (时域/频域/包络三估计器互证)
- sim-rtl-flow/SKILL.md: 加入 sync_sim:* 步骤, 引用上述三个 skill
2026-07-27 10:39:53 +08:00

111 lines
4.4 KiB
Python

"""Shared helpers: source copying + PROVENANCE.log (mandatory traceability).
RULE (user directive 2026-07-23): script-processed RTL lives ONLY in the fixed
directory <repo>/vivado/rtl_ip/<model>/ ; the Vivado project may reference RTL
ONLY from there, NEVER from the MATLAB hdlsrc directly. PROVENANCE.log in the
fixed directory records the absolute path of the original MATLAB RTL.
Generated Xilinx IPs live in <fixed_dir>/ip/.
"""
import difflib, hashlib, os, re, shutil, time
SRC_ORIG = 'src_orig' # verbatim snapshot of the MATLAB RTL this run is based on
TRANSFORM_DIFF = 'TRANSFORM.diff'
def src_files(d):
return [fn for fn in sorted(os.listdir(d))
if fn.endswith('.v') and not fn.endswith('_tb.v')]
def sha1_file(p):
return hashlib.sha1(open(p, 'rb').read()).hexdigest()
def copy_sources(hdlsrc, outdir, force=False):
os.makedirs(outdir, exist_ok=True)
copied = []
for fn in src_files(hdlsrc):
dst = os.path.join(outdir, fn)
if force or not os.path.exists(dst):
shutil.copy(os.path.join(hdlsrc, fn), dst)
copied.append(fn)
snapshot_sources(hdlsrc, outdir)
write_provenance(outdir, hdlsrc)
return copied
def snapshot_sources(hdlsrc, outdir):
"""Task12 rule 14: keep the ORIGINAL MATLAB RTL this run is based on, so the
next run can diff against it and reuse unchanged work (incremental mode)."""
d = os.path.join(outdir, SRC_ORIG)
os.makedirs(d, exist_ok=True)
for fn in src_files(hdlsrc):
dst = os.path.join(d, fn)
if not os.path.exists(dst) or sha1_file(dst) != sha1_file(os.path.join(hdlsrc, fn)):
shutil.copy(os.path.join(hdlsrc, fn), dst)
return d
_HUNK = re.compile(r'^@@ -\d+(,\d+)? \+\d+(,\d+)? @@')
def write_transform_diff(outdir):
"""src_orig/*.v -> rewritten *.v, as removed/added lines only (n=0) with hunk
line numbers normalised away: two runs whose scripts performed the SAME
rewrite produce byte-identical files, even if the MATLAB source changed
elsewhere (that is exactly the class-B case of Task12 §5.2)."""
orig = os.path.join(outdir, SRC_ORIG)
out = []
for fn in src_files(orig):
mod = os.path.join(outdir, fn)
if not os.path.exists(mod):
out.append(f'=== {fn}: MISSING in outdir')
continue
a = open(os.path.join(orig, fn), errors='replace').read().splitlines()
b = open(mod, errors='replace').read().splitlines()
d = [_HUNK.sub('@@', ln) for ln in
difflib.unified_diff(a, b, fromfile=f'orig/{fn}', tofile=f'ip/{fn}',
n=0, lineterm='')]
if d:
out.extend(d)
p = os.path.join(outdir, TRANSFORM_DIFF)
open(p, 'w').write('\n'.join(out) + '\n')
return p
def scripts_sha1(script_dir=None):
"""Fingerprint of the skill itself -- changed scripts forbid inheriting a
previous cycle-true PASS (Task12 §5.4/5.5)."""
d = script_dir or os.path.dirname(os.path.abspath(__file__))
h = hashlib.sha1()
for fn in sorted(os.listdir(d)):
if fn.endswith(('.py', '.tcl')):
h.update(fn.encode())
h.update(open(os.path.join(d, fn), 'rb').read())
return h.hexdigest()[:12]
def write_provenance(outdir, hdlsrc):
hdlsrc = os.path.abspath(hdlsrc)
lines = ['# PROVENANCE.log -- generated by rtl-ip-replace, do not edit',
'# RULE: the Vivado project must use RTL from THIS directory only;',
'# direct use of the MATLAB-generated hdlsrc below is FORBIDDEN.',
'source_hdlsrc: ' + hdlsrc,
'updated_at: ' + time.strftime('%Y-%m-%d %H:%M:%S'),
'ip_subdir: ip/',
'files:']
for fn in src_files(hdlsrc):
p = os.path.join(hdlsrc, fn)
h = sha1_file(p)[:12]
mt = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(os.path.getmtime(p)))
lines.append(f' {fn} src_sha1={h} src_mtime={mt}')
lines.append('src_snapshot: ' + SRC_ORIG + '/ # original MATLAB RTL kept for the next incremental run')
lines.append('scripts_sha1: ' + scripts_sha1())
open(os.path.join(outdir, 'PROVENANCE.log'), 'w').write('\n'.join(lines) + '\n')
def append_provenance(outdir, lines):
"""Append the incremental-run block (Task12 §5.6). Called last, after the
transform scripts have rewritten PROVENANCE.log."""
with open(os.path.join(outdir, 'PROVENANCE.log'), 'a') as f:
f.write('\n'.join(lines) + '\n')