HDL最小修复与一致性检查
一个工作流,用于生成修复HDL设计错误的最小安全补丁,然后验证修复不会破坏硬件契约或导致跨工件的不一致性。
本技能涵盖的内容
此技能是双技能流水线(定位→修复)中的修复环节。它接受两种入口路径:
- 带有根本原因假设注释(来自
hdl-fault-localization或等效工具)——解析注释,选择最佳假设,然后继续操作。 - 带有现有修复意图——当用户或先前智能体已给出具体错误位置、修复方向或补丁差异时,将该意图提升为临时假设并继续操作。
本技能执行四项任务,不做其他事情:
- 最小补丁规划——解决所选假设所需的最小变更集,不进行无关修改。
- 副作用扫描器——检查硬件契约对(ready/valid、reset/flush/replay、FSM转换、陈旧状态、流水线顺序)。
- 工件链接检查器——确保配置、生成文件、寄存器描述和生成脚本保持一致。
- 测试验证——运行测试套件,并通过回退假设处理失败。
此技能不执行故障定位。如果错误尚未定位,请停止并要求先进行定位。
何时使用此技能
此技能仅在问题已定位时激活。以下任一条件满足即可进入:
- 提供了根本原因假设注释(来自
hdl-fault-localization或等效工具)。 - 用户或先前智能体给出了明确的错误位置(文件、模块、信号)和修复方向(要更改的内容以及原因)。
- 用户陈述了明确的修复意图(例如,“加宽此指针”、“添加缓冲器”、“修复FSM转换”)。
- 存在需要审查副作用或一致性的现有补丁差异。
如果不存在这些入口信号——错误未定位、没有假设、也没有具体的修复意图可供提升——立即停止,并要求先进行定位。 不要尝试诊断错误;这是单独的故障定位技能的责任。诸如“修复此错误”、“有问题”或“我的测试台失败”等模糊请求,且没有定位信息,不视为入口信号——它们缺乏此技能修复范围所需的特异性。
典型的触发短语:“应用修复”、“制作补丁”、“实施修复”、“检查此补丁的副作用”、“在此更改后验证硬件契约”、“审计跨工件一致性”。
输入要求
开始前必须满足以下至少一项。如果都不存在,请停止并要求先进行定位。
- 根本原因假设注释——一个文件或内联文本,描述一个或多个假设,每个假设带有证据强度和理由。这是首选输入,由
hdl-fault-localization生成。 - 明确的错误位置 + 修复方向——用户或先前智能体已识别出特定文件、模块或信号,并描述了要进行的更改。将此修复意图提升为临时假设。
- 现有修复意图——一个陈述的计划(例如,“将指针从4位加宽到5位”),可视为单一假设注释。
- 现有补丁差异——一个提议的代码更改,用于审查副作用和工件一致性。
此外,收集:
- 相关源文件——涉及的HDL模块、测试台和支持代码的路径。
- 测试命令——运行测试套件的确切命令。
- 失败日志——可选但推荐用于上下文。
核心工作流
按顺序执行以下步骤。每一步的输出都将输入到下一步。
步骤0:入口门检查(在任何代码分析之前)
在阅读任何源文件、日志或波形之前,验证用户消息中是否存在至少一个入口信号。按此顺序检查:
- 是否有根本原因假设注释(文件路径、内联YAML或带有标签假设和证据的结构化文本)?
- 用户是否指定了具体的错误位置和修复方向(特定文件、模块或信号以及对要进行的更改的描述——不仅仅是“修复它”或“有问题”)?
- 用户是否陈述了具体的修复意图(例如,“将指针加宽到5位”、“添加缓冲器”、“将FSM转换从A改为B”)?
- 是否存在要审查的现有补丁差异?
如果这些都不存在——用户只说“修复此错误”、“我的测试台失败”、“有问题”或类似的模糊请求,且没有定位——立即停止。 不要阅读源代码。不要尝试诊断错误。输出:
此技能需要先进行定位。请先运行故障定位(hdl-fault-localization),或提供以下之一:
- 根本原因假设注释
- 明确的错误位置(文件/模块/信号)和修复方向
- 具体的修复意图(更改内容和原因)
- 要审查的现有补丁差异
只有在确认存在入口信号后,才继续进行步骤1。
步骤1:建立修复假设
如果有正式的根原因假设注释可用,则解析它以提取:
- 每个假设,带有标签和描述。
- 支持每个假设的证据(强、中、弱)。
- 每个假设的建议修复方向。
- 假设之间的任何回退顺序或依赖关系。
如果注释包含多个假设,列出所有假设。如果只包含一个,简化选择——但在提交前仍评估其证据强度。
如果未提供假设注释但存在修复意图(明确的错误位置+修复方向、陈述的修复计划或现有补丁差异),则将该意图提升为临时假设。给它一个标签(例如,“P1-sync-fifo-pointer-widen”)并记录根据用户描述支持它的证据。在步骤2-7中,此临时假设被视为唯一假设。不要尝试生成替代假设或执行故障定位——此技能的范围止于修复执行。
步骤2:选择要首先修补的最佳假设
并非所有假设都是平等的。应用这些选择标准:
- 证据强度——优先选择有具体证据(波形痕迹、日志模式、可重现条件)的假设,而不是推测性的。
- 修补风险——优先选择修补范围集中(一个或两个模块,无结构更改)的假设,而不是需要广泛重写的假设。
- 可逆性——优先选择如果不起作用则易于回滚的假设的修补。
- 依赖顺序——如果假设B依赖于假设A的正确性,则先修补A。
记录为什么选择此假设而不是其他选项。如果无法在两个同等强的假设之间做出决定,选择修补风险较低的一个,并将另一个标记为主要回退。
步骤3:生成最小补丁计划
“最小补丁”并不意味着“只更改一个文件”。它的意思是:解决所选假设所需的最小更改集,不进行任何无关修改。
对于计划修改的每个文件,回答:
- 为什么必须更改此文件?——从假设到该特定更改的因果链。
- 到底更改了什么?——在信号/逻辑级别描述更改,而非实现细节。
- 为什么这是最小更改?——解释为什么较小的更改不足够,或较大的更改不必要。
拒绝任何以下更改:
- 美学性的(格式化、重命名、与错误无关的注释更新)。
- 重构性的(“趁我在,让我清理一下”)。
- 硬编码测试期望以使测试通过。
- 在没有证据表明测试本身有误的情况下修改测试文件。
步骤4:执行副作用扫描器
硬件设计在信号之间具有隐式契约。更改契约的一侧通常会破坏另一侧。在应用补丁之前,扫描这些契约违规:
ready/valid对
对于修改模块及其直接邻居中的每组ready/valid握手对:
- 补丁是否更改了
valid被断言或取消断言的时机?如果是,消费者的ready逻辑是否仍然正常工作? - 补丁是否更改了
ready被采样或驱动的时机?如果是,生产者的valid逻辑是否仍然合理? - 背压是否仍然正确处理——流水线能否在不丢失数据的情况下停顿?
复位/刷新/重放
对于每个复位、刷新或重放信号:
- 补丁是否更改了复位时清除或保留的状态?
- 刷新路径是否仍然正确排出或无效化飞行中的数据?
- 重放路径是否仍然将状态恢复到正确的检查点?
FSM转换完整性
对于补丁接触到的每个有限状态机:
- 从复位是否可达所有状态?
- FSM是否可能死锁(某个状态没有有效退出)?
- FSM是否可能活锁(状态之间无限循环而不前进)?
- 补丁是否添加或删除任何状态转换?如果是,验证新转换表是否完整。
陈旧状态
- 补丁是否引入任何寄存器或信号,可以在交易或时钟周期之间持有陈旧值,而本应被清除?
- 补丁是否依赖于某个信号被某个不再正确触发的机制清除?
流水线顺序
- 补丁是否更改流水线中的操作顺序?如果是,下游阶段是否仍然按预期顺序接收数据?
- 补丁是否更改流水线深度(添加或删除阶段)?如果是,是否调整了所有旁路和转发路径?
记录每个类别的发现,即使结果是“未发现任何问题”。
步骤5:执行工件链接检查器
HDL项目通常具有配置文件、寄存器映射和生成的代码,必须与HDL源代码保持同步。检查这些链接:
配置文件
扫描引用补丁修改的信号、参数或模块的配置文件(YAML、HJSON、JSON、TOML、INI或类似格式)。如果补丁更改了参数值、模块名称或端口列表,则更新配置以匹配。
生成的文件
检查项目中是否有任何文件是自动生成的(由代码生成器、脚本或构建步骤)。如果补丁更改了为生成器提供输入的源代码,则要么:
- 重新生成输出文件,或
- 标记不一致以供手动重新生成。
寄存器描述
如果设计包含寄存器映射(CSV、XML、IP-XACT、SystemRDL或类似格式),请检查寄存器字段位置、宽度和访问类型在补丁后是否与HDL发生偏移。
生成器脚本
检查生成HDL或配置文件的Python、Perl、Tcl或Shell脚本。如果补丁更改了这些脚本依赖的模式(命名约定、信号宽度、接口协议),脚本可能会生成损坏的输出。
记录所有检查的工件以及发现的任何不一致。
当补丁仅更改内部逻辑(没有公共接口、参数、寄存器字段、地址映射、生成的源代码或配置可见行为)时,工件链接检查简化为“不适用——内部补丁,无跨工件影响”。避免扫描整个项目树以查找无法受更改影响的工件。仅当补丁触及上述表面之一时,才运行完整的工件搜索。
步骤6:应用补丁并运行测试
将补丁应用于实际源文件。然后运行测试命令:
- 运行测试套件一次。
- 如果所有测试通过——记录结果并继续进行步骤7。
- 如果某些测试失败——分析:
- 这些失败是否预先存在? 检查失败日志以确认这些测试在补丁之前是否已失败。预先存在的失败不是补丁的错——记录它们但不阻止修复。
- 这些失败是否由补丁引起? 如果补丁引入了新的失败,则修复不完整或不正确。进入回退路径。
- 这些失败是否揭示了测试错误? 仅在您有具体证据证明测试期望错误时才得出此结论,而不是仅仅因为补丁更改了行为。
步骤7:处理失败——回退到下一个假设
如果补丁以由补丁引起的方式导致测试失败(非预先存在或测试错误):
- 不要尝试用即兴调整来挽救补丁。这会将假设驱动的修复变为猜测。
- 如果执行环境支持干净的回滚(例如,
git checkout、git stash或管理补丁状态的外部测试工具),则在尝试回退之前还原失败的补丁。如果不支持回滚,则在继续之前显式检查并撤销失败的编辑——不要将新补丁层叠在损坏的补丁之上。 - 选择下一个假设来自假设注释(具有次优证据和风险组合的假设)。
- 记录在补丁决策注释中:哪个假设失败,为什么(哪个测试中断),以及现在尝试哪个假设。
- 返回步骤2使用回退假设。
如果所有假设都已耗尽且没有补丁通过测试,则报告假设集不足——根本原因可能不在任何假设的解释范围内。
输出:补丁决策注释
在工作流结束时(无论补丁成功还是失败),使用此确切结构生成补丁决策注释:
patch_decision_note:
selected_hypothesis: <已修补的假设>
patch_scope: <补丁更改内容的一句话摘要>
modified_files:
- <文件路径>: <必须更改此文件的原因>
- <文件路径>: <必须更改此文件的原因>
side_effects:
- <类别>: <发现>
- <类别>: <发现>
artifact_consistency:
- <工件>: <状态>
- <工件>: <状态>
test_results: <所有测试通过/补丁导致失败/由于环境原因未运行>
final_status: <成功/失败>
fallback_hypotheses_remaining: <是/否>
next_steps: <如果成功,则部署;如果失败,则重新定位>