- 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
12 KiB
name, description
| name | description |
|---|---|
| simulink-rtl-redev | 改动原生模型(xxx_h.slx)之后,如何保证仿真模型(xxx_hs.slx)同步、仿真结论仍然算数。 典型触发场景:Vivado 综合时序不满足要改流水、硬件调试发现问题要改 RTL、定点位宽调整。 核心:生成脚本不会把原生核的改动翻译成 m 代码,只改一侧 = RTL 已变而仿真还在验证旧行为。 提供两个工具:同步新鲜度闸门 check_sync.py(三条时序链,退出码即结论)、 延迟实测 measure_k.m(时域/频域/包络三个估计器互证,不一致返回 NaN 而非猜测值)。 另含改动分类、验证三步、环内/环外加流水的差别、六条禁令。 触发词:改了原生模型、同步仿真模型、xxx_h 和 xxx_hs 不一致、时序违例改流水、 硬件调试改RTL、仿真模型过时、等价闸门、cycle-true 同步、check_sync、measure_k、 测延迟、K 是多少、加流水延迟多少拍、原生模型 仿真模型 双轨、改完怎么验、 makehdl 之前要做什么。 规范全文见工程 Notes/Task16-3.md。适用于任何"原生模型+仿真模型"双轨结构的工程。 |
simulink-rtl-redev — 原生模型改动后的仿真模型同步
这个 skill 解决什么
两个模型描述同一段算法:
| 记号 | 名称 | 内容 | 用途 |
|---|---|---|---|
xxx_h.slx |
原生模型(-e) | 目标模块全部用可综合原生块搭建 | 生成 RTL |
xxx_hs.slx |
仿真模型(-x/-q) | 由原生模型派生,跑不动的原生核换成等价的 m 实现 | 跑场景仿真 |
核心原则:改了原生模型,必须同步改仿真模型,并重新验证两者行为一致。
原因:从原生模型派生仿真模型的脚本只做"摘掉原生核、换上 m 实现、接线", 它不会把原生核的改动翻译成 m 代码。只改原生模型再重跑生成脚本, 仿真模型不会跟着变——它只是把同一份未改动的 m 实现重新包一遍。
后果:RTL 已经变了,而仿真还在验证旧行为。板上出问题时仿真给不出线索, 因为它测的根本不是同一个设计。
什么时候需要手工同步
只看改动落在哪里:
| 改动位置 | 是否需要手工同步 m 实现 |
|---|---|
| 原生核之内 | 需要。这是两套实现的重叠区 |
| 原生核之外(其余链路) | 不需要。生成脚本原样继承,重生成即可 |
Agent 路径:先跑闸门
任何时候怀疑"仿真结论还算不算数",第一件事是跑同步新鲜度闸门。
一次性:写 manifest
在工程里建一份 manifest(建议放 Notes/sync_manifest_<model>.json),
声明这个模型的源与派生产物。root 相对 manifest 所在目录,其余路径相对 root:
{
"model": "<model>",
"root": "..",
"native_model": "matlab/<proj>/xxx_h.slx",
"build_scripts": ["matlab/<proj>/build_core.m"],
"gen_scripts": ["matlab/<proj>/make_sim.m"],
"mcode_impl": ["matlab/<proj>/core_mcode.m"],
"runtime_deps": ["matlab/<proj>/pscore.m", "matlab/<proj>/coef.mat"],
"sim_model": "matlab/<proj>/xxx_hs.slx",
"rtl_source_model": "matlab/<proj>/xxx_h_<Mod>_E.slx",
"gate_result": "Notes/gate_<model>.txt",
"gate_tools": ["matlab/<proj>/gate.m", "matlab/<proj>/cmp_core.m"]
}
runtime_deps 必填运行时才从路径解析的 .m 与运行时读取的数据文件
(.mat、系数表、数据字典)。改它们时模型本身一个字节都不变,漏列等于没查。
rtl_source_model 与 gate_tools 可省(省了就不查对应项)。
每次改完模型:跑闸门
cd <工程根>
python "%USERPROFILE%\.claude\skills\simulink-rtl-redev\check_sync.py" Notes\sync_manifest_<model>.json
Linux/macOS 把路径换成 ~/.claude/skills/simulink-rtl-redev/check_sync.py。
退出码即结论:0 通过,1 有过时产物,2 manifest 有问题(路径不存在等)。
可直接串进脚本做前置门禁。
选项:--quiet 不打印文件清单,--json 输出机器可读结果。
它查三条时序链:
链 1(派生新鲜):max(源文件) < min(派生产物)
链 2(闸门新鲜):max(派生产物) < 闸门结果
链 3(工具新鲜):max(闸门工具) < 闸门结果
链 1 是最容易漏的那条。 只查"闸门晚于全部源文件"会放行下面这种情况: 闸门确实在改完源之后跑的,但仿真模型停留在改动之前。本工具在真实工程上正是这样 抓出了一个已存在的漂移——链 2、链 3 都 PASS,只有链 1 FAIL。
同步流程
[1] 改原生实现(改构建脚本,不直接手改 .slx)
|
[2] 把同样的改动落到 m 实现 <-- 漏掉这步是本 skill 存在的理由
|
[3] 重新生成仿真模型
|
[4] 若改动带来延迟变化:先实测新增拍数 K
|
[5] 跑等价闸门 --> 原生核 与 m 实现 是否一致
|
[6] 跑短程冒烟 --> 链路是否还通
|
[7] 跑全场景全长 --> 对照基线,指标是否达标
|
[8] 从原生模型生成 RTL
任一步不过,回到 [1] 重走,不要从中间插入——仿真模型一旦重生成,后面的结果全部作废。
[4] 必须在 [5] 之前:延迟变了,闸门比对要带偏移,K 没测出来这一步做不了。
跑完 [3] 之后、进 [5] 之前,先用 check_sync.py 确认新鲜度,能省掉一次白跑的闸门。
三类改动的差别
| 类别 | 例 | m 实现要改吗 | 延迟 | 场景判据 |
|---|---|---|---|---|
| 不改延迟 | 资源共享、块重构、常量折叠 | 通常不用 | 不变 | 与基线逐位相同 |
| 改延迟 | 插流水寄存器 | 补等量延迟 | +K | 吸收 K 后与基线逐位相同 |
| 改定点 | 位宽、二进制点、饱和/舍入 | 必须改 | 不变 | 行为已变,重新定性并建立新基线 |
- 延迟必须实测,不能按设计意图推算。 用
measure_k.m(下节),至少两种互不依赖的方法测出一致值。 - 在反馈环内插流水,代价远大于环外。 环外只是一个可被注入侧参数吸收的常数延迟; 环内会改变环路群延迟,必须重新定标环路参数(步长、移位、门限),并先在单元台验证 阶跃响应再上全链。能搬到环外就搬到环外。
实测新增延迟 K:measure_k.m
流程 [4]。B 类(加流水)改动必须先测 K 才能进 [5]——闸门的判据本身要用 K 作偏移。
addpath(fullfile(getenv('USERPROFILE'),'.claude','skills','simulink-rtl-redev'));
[K, R] = measure_k(ref, dut); % ref/dut 为实数或复数 IQ 向量,同采样率
ref 是改动前(或参考抽头)的信号,dut 是改动后(滞后 K 拍)的信号。
返回 K = 认定的整数延迟,方法不一致时返回 NaN,不给猜测值。
R 里有各方法的分项结果。可选参数:'MaxLag'(4096)、'OnsetTol'(1e-3)、
'FracTol'(0.05)、'Verbose'(true)。只用基础 MATLAB,不依赖 Signal Processing Toolbox。
三个估计器,前两个域完全不同、始终可用,第三个仅在信号有静默前导时适用:
| 方法 | 域 | 说明 |
|---|---|---|
| 1 互相关 argmax | 时域 | 整数 |
| 2 互谱相位斜率 | 频域 | 分数;纯延迟使 angle(Y·conj(X)) 对频率成直线,斜率即 −K |
| 3 起始点差 | 幅度包络 | 整数;阈值取各自峰值的比例,故 DUT 的噪声底不会误触发;连续激励信号判 n/a 而非失败 |
判据:方法 1 与 2 必须一致;方法 3 适用时也必须一致;插值峰距整数不超过 FracTol。
为什么非要两种。 实测:两路完全无关的信号,相关器照样给出 K = 241
(|rho| 仅 0.0198 的假峰)——单靠它会把一个纯噪声峰当成延迟。方法 2 给出 −26.350,
两者互不相认,工具才判 FAIL。这就是"至少两种互不依赖的方法"的全部理由。
实测过的六种情形:
| 情形 | 结果 |
|---|---|
| 干净整数延迟 40,复数 IQ | PASS,3 法一致 |
| 增益 0.37× + 全程噪声底 | PASS,2 法一致(方法 3 自动判 n/a) |
| 连续激励无静默段,延迟 17 | PASS,2 法一致 |
| 分数延迟 12.5 拍 | FAIL:方法 1 给 13、方法 2 给 12.500,且插值峰偏离整数 0.5 |
| 两路无关信号 | FAIL:241 vs −26.350 |
| 真延迟 40 + 3 阶非线性失真 | PASS,2 法一致(|rho| 0.989) |
分数延迟那一条尤其要留意:它说明改动没有引入干净的整数流水延迟(碰到了分数内插/重采样 路径)。这时不能四舍五入接着走,要回去查改的是不是环内。
等价闸门的语义(极易搞错)
闸门比对的是原生核与 m 实现这两套实现,不是"新行为与旧行为"。因此:
- 闸门对所有类别的改动都必须跑,判据都是"一致";
- 即使行为相对上一版变了,只要两侧按同样意图改完,两套实现对新行为的描述仍必须一致;
- 改完两侧仍不一致,说明两边理解有分歧——这正是闸门要抓的。
不要以"行为变了"为由跳过闸门。 跳过它就等于放弃了对双实现是否同步的唯一检查。
闸门的局限:它只证明"在所用激励下一致",不证明全状态空间等价。 状态机边界、饱和、复位时序这类角落必须补定向用例,不能指望随机激励覆盖到。
六条禁令
| # | 规矩 | 理由 |
|---|---|---|
| 1 | 仿真模型是产物,不能手改;要改就改生成脚本再重生成 | 手改必被下次重生成冲掉,git 上无法溯源 |
| 2 | 只改一侧的改动视为未完成,不得进入验证 | 两套实现已分叉 |
| 3 | 没跑过闸门,不得跑场景仿真,也不得生成 RTL | 前者测的可能是旧设计,后者错误直接进硅 |
| 4 | 旧结果永不覆盖,每次运行带唯一标签、落唯一目录 | 失败记录是"改动前后对比"的另一半;陈旧编译缓存会静默复现旧结果 |
| 5 | 判据不得为了通过而修改 | 一条带机理分析的 FAIL,价值高于一个来路不明的 PASS |
| 6 | 时序违例优先改模型,禁止用多周期豁免放宽慢角富余路径 | 布线器会吃满被放松的预算,表现为"报告通过、板上异常" |
Gotchas
- 时间戳只是权宜之计。
copy/touch/版本签出都会扰动 mtime。check_sync.py因此只能作自查,不是证明。更可靠的做法是让生成脚本与闸门自动记录 所用源码的校验和,运行前比对不符即拒绝开跑——那属于工具建设,本 skill 不含。 - "闸门比全部源文件新"不等于没问题。 这正是链 1 存在的理由,见上文。
runtime_deps漏列 = 没查。 运行时解析的 .m 和.mat/系数表改动时, 模型校验和纹丝不动。这类依赖必须显式声明,工具无法自动发现 (load('x.mat')这种字符串依赖追不到)。- manifest 里每个声明的路径都必须存在,否则 exit 2。这是故意的: 路径写错而静默跳过,比报错危险得多。
- exit 2 与 exit 1 含义不同:2 是 manifest 坏了(你的配置问题), 1 是真的有过时产物(你的工程问题)。串脚本时别把两者混为一谈。
Troubleshooting
| 症状 | 原因 / 处置 |
|---|---|
ERROR: manifest refers to something that is missing -> <key>: <path> |
该路径不存在。exit 2。检查 root 与相对路径;root 是相对 manifest 所在目录的 |
| 链 1 FAIL | 派生产物早于源。先把原生核改动落到 m 实现,再重生成,再重跑闸门。只重生成不同步 m 实现无效 |
| 链 2 FAIL | 闸门跑在当前派生产物之前 —— 重跑闸门 |
| 链 3 FAIL | 闸门工具在记录的通过之后改过 —— 重跑闸门 |
| 三条链全 PASS 但板上仍与仿真不符 | 新鲜度没问题,问题在别处:查闸门覆盖(定向用例是否覆盖到出问题的状态),或查 runtime_deps 是否漏列 |
ERROR: manifest declares no sources / no derived products |
manifest 缺 native_model 一类的键,或值是空列表 |
规范全文
本 skill 是 Notes/Task16-3.md 的可执行化。规范原文(含制定过程与十轮评审纠正的
逻辑错误)见该文档;本 skill 只承载执行路径与工具。