Vivado 信号被优化找不到:Set up Debug 搜不到信号速查
更新时间:2026-10-23。FAQ 速查页,面向 FPGA 入门 阶段第一次在板子上抓波形的同学。症状很典型:RTL 里明明声明了
debug_cnt这个信号,仿真波形里也能看到,可一打开 Set up Debug 向导想把它挂到 ILA 上,搜索框里怎么输都是空;或者更隐蔽——信号能搜到,抓回来的波形却是一根恒为 0 的直线。这类「信号消失」九成不是 Vivado 的 bug,而是综合器按规则合法地把它优化掉了,或者层级被打平后名字变了。ILA 的基本用法不在本篇范围,先会用 ILA 再看这里,入门见 ILA 首次使用。
本文要回答的问题
- Set up Debug 向导搜不到信号,和综合阶段的哪些优化直接相关?
- 信号能挂 ILA 但波形恒为常量,是不是也被优化了?
mark_debug、keep、dont_touch三个属性到底差在哪,作用域怎么写才对?- 层级被 flatten 之后,原来的信号名在网表里变成了什么?
- 想保留整棵层级的信号名,综合选项要怎么改、代价是什么?
一、典型现象与一句话根因
以下文案按 Vivado 常见输出整理,工程名与信号名均已占位:
1. Set up Debug 向导里搜不到信号(综合通过后插入 ILA 的阶段):
WARNING: [Chipscope 16-213] No debug core(s) found matching the specified criteria.
CRITICAL WARNING: [Vivado 12-1342] No nets matched 'get_nets *debug_cnt*'.2. XDC 里写了 MARK_DEBUG 约束,实现阶段报对象不存在:
CRITICAL WARNING: [Common 17-55] 'set_property' expects at least one object.
Resolution: Check that the objects specified exist in the current design.3. 综合日志里信号被点名删除(最容易被忽略的一条线索):
INFO: [Synth 8-3333] propagating constant across sequential element.
INFO: [Synth 8-702] instance 'u_sub/cnt_reg' of module '...' removed.一句话根因:综合器的职责是删减一切「对最终输出无影响」的逻辑——信号未驱动负载、被常量折叠、被寄存器合并,都会被合法删掉;而 Set up Debug 工作在综合后的网表上,被删的信号在网表里根本不存在,自然搜不到。 名字找不到的另一半原因是层级默认被 flatten,信号名从 u_sub/cnt 变成了 u_sub_cnt_reg 之类的扁平形式。排查的总原则只有一句:先去综合日志确认这条信号是不是被优化掉了,再决定是改 RTL 让它有真实负载,还是用属性强制保留。
二、排查决策图
先用下面这张决策图确定方向,再照第三节的表对号入座。读图方式:红色是入口现象,蓝色是排查动作,绿色是判定通过的分支,橙色是修复动作,紫色是防复发收尾。核心顺序是「先查日志定性,再动属性」——不看日志就往上糊 dont_touch,大概率保留了一堆没用的逻辑还找不到真正的病根。
这张图对应两类根因轴:一类信号真的没了(被删、被折叠),只能靠属性或改 RTL 保留;另一类信号还在但名字变了(层级打平),改搜索模式就能命中。注意「日志无删除记录」分支指向换名再搜而不是直接加属性——很多同学的信号其实活得好好的,只是网表里的名字和 RTL 里长得不一样了。
三、病因处置表
| 报错现象 | 最可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| Set up Debug 完全搜不到该信号 | 信号未驱动任何负载,被整体裁剪 | 综合日志搜 removed 关键字 | 给信号真实负载,或加 dont_touch |
| 搜得到但波形恒为 0/1 | 常量折叠:驱动逻辑被证明恒为常量 | 日志搜 propagating constant | 检查复位/使能逻辑是否恒无效 |
| RTL 名搜不到,模糊通配也搜不到 | 层级 flatten 后改名 | get_nets *cnt* 看扁平形式 | 用扁平名挂 ILA,或保留层级 |
mark_debug 加了还是被优化 | 属性写错对象(写在 wire 但优化点在寄存器) | 网表里看属性落在哪个 cell 上 | 属性直接写在寄存器声明上 |
XDC set_property MARK_DEBUG true 报对象不存在 | get_nets 模式没匹配到任何网表 | Tcl 控制台单跑 get_nets 验证 | 修正匹配模式,先综合网表里探名 |
| 中间寄存器链只剩首尾两级 | 寄存器合并/复制优化 | 日志搜 merging、replication | 中间级加 keep,接受资源上涨 |
| 仿真有波形、网表没有对应名 | 组合逻辑被综合进 LUT,无独立网表 | 网表搜驱动它的 LUT | 给该路径加寄存器再打 mark_debug |
| 工程一改层级名就全断 | 调试约束写死了层级路径 | 换层级名重综合验证 | 约束用通配,或固定层级不打平 |
四、三个最高频根因的修法
根因一:信号对输出无贡献,被合法删除。 这是最高频也最冤枉的一种——RTL 里声明了一个只用于观察的计数器、状态寄存器,它的输出没有连到任何顶层端口、RAM 地址或后续逻辑,综合器按「无用逻辑」规则把它连根拔掉,综合日志里只有一行不起眼的 INFO。两种修法按目的选:如果信号本该有功能(比如它本该去控制什么但你忘了连),那这是 RTL bug,回去把逻辑补连上;如果它就是纯观测信号,用属性强制保留:
(* mark_debug = "true" *) reg [15:0] debug_cnt;
(* keep = "true" *) wire [7:0] debug_bus;根因二:常量折叠,信号活着但永远是定值。 症状是信号能挂上 ILA、波形也能抓,但抓回来一根直线。典型剧本是使能条件写错导致某段逻辑恒不执行,综合器向前推导出寄存器恒为复位值,于是把整个驱动链折叠成常量,网表里只剩一根绑死的线。先去综合日志搜 propagating constant 和信号名,确认折叠事实,再回头查使能/复位逻辑——这种情况下保留属性没有意义,保留一个恒为 0 的信号对调试毫无帮助,真正要修的是让它动起来。常量折叠在时序不收敛的设计里也很常见,跨篇背景见 流水线与资源优化。
根因三:层级被 flatten,名字对不上。 Vivado 综合默认 -flatten_hierarchy rebuilt,会把子模块层级打平再重组,信号名从 u_sub/cnt 变成类似 u_sub_cnt_reg[3] 的扁平形式,按原层级名搜自然一无所获。两条路:一是接受扁平名,在网表里用通配探名再挂调试:
open_run synth_1
get_nets -hier *debug_cnt*
set_property MARK_DEBUG true [get_nets -hier *debug_cnt*]二是保留层级,综合设置里把 flatten_hierarchy 改成 none,并给要观测的子模块加 keep_hierarchy——代价是跨模块优化变弱、时序与资源可能变差,只建议在调试阶段临时用,正式出比特流前改回来。属性写进 XDC 的等价形式如下,注意 get_nets 必须作用在综合后的网表对象上,在 RTL 阶段跑必然报对象不存在:
set_property MARK_DEBUG true [get_nets {u_sub/cnt[*]}]三个属性的差别一句话说清:mark_debug 只管「挂调试探针」并顺带阻止优化;keep 阻止该信号被合并/吸收但不管调试可见性;dont_touch 最强,连优化带布局布线都不许动,适合整个调试期钉住一块逻辑。日常调试用 mark_debug 足够,dont_touch 滥用会明显拖慢实现并抬高资源,资源开销怎么看见 资源利用率报告解读。XDC 约束的基本语法见 XDC 约束入门,ILA 更深的触发与多核联调见 ILA 与 VIO 联机调试。
五、修复后验证与防复发
修完不要只看「这次搜到了」。先在综合网表里跑 get_nets -hier *<信号名>* 确认对象真实存在,再 get_property MARK_DEBUG 回读属性确认属性落对了对象;然后完整重跑综合与实现(不要用增量结果掩盖问题,综合反复不收敛的坑另见 Vivado 综合结果过期死循环速查),最后上板抓一次真实波形闭环。防复发三件套:关键调试信号的 mark_debug 属性直接写在 RTL 源码里随代码入库,不要只在 XDC 里临时糊;团队约定调试属性的命名规范(比如统一 dbg_ 前缀),code review 时能一眼看到哪些信号为观测而保留;每次插完 ILA 在综合日志里 grep 一遍 removed 与 constant,把信号被优化这件事从「上板才发现」提前到「综合完就发现」。
一句话总结
Vivado 信号被优化找不到的本质是综合器合法删减与层级打平改名的叠加:未驱动负载的信号被整体裁剪、恒值逻辑被常量折叠、flatten 让原名对不上网表;先查综合日志定性(removed/constant/无记录三分支),再对号入座——纯观测信号用 (* mark_debug = "true" *) 保留、恒值信号回去修使能逻辑、改名信号用 get_nets -hier 通配探名或临时 -flatten_hierarchy none 保留层级,最后重跑综合上板抓波闭环,并把调试属性随 RTL 入库防复发。