ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DWC_pcie_ctl_ep链路训练LTSSM波形分析:从RTL定位到卡死排查

DWC_pcie_ctl_ep链路训练LTSSM波形分析:从RTL定位到卡死排查 DWC_pcie_ctl_ep这个IP仿真跑起来不难难的是把链路训练Link Training这一段彻底看懂。群里几乎每周都有人发同样的截图ltssm_state卡在某个值不动了link始终up不起来。第5篇实操我们把基础仿真跑通了波形文件也有了可拿到那一堆信号线很多人根本不知道怎么读。这篇实操6我就专门讲Training阶段的RTL与波形联合分析——RTL里怎么定位训练相关逻辑波形里怎么读懂状态机的每一步以及卡死的时候怎么从波形反推根因。1. Training是第一道硬门槛LTSSM到底在“训”什么1.1 链路训练的本质先说个容易混淆的点这里的Training跟AI训练没有半点关系。PCIe链路训练Link Training是物理层的一项核心机制本质上是链路两端在上电或复位之后通过交换特定格式的训练序列Training Sequence简称TS1/TS2完成一系列握手动作最终把物理链路状态稳定下来进入L0正常工作态。你完全可以把它理解成两个人第一次见面时的“对暗号”——先确认对方在场再确认互相能听懂话然后商定用什么语言、多大音量讲话最后确认彼此都准备好了开始正式谈正事。暗号没对上后面传输层、事务层再厉害也白搭因为物理通道根本没建立起来。在RTL级别这段逻辑由LTSSMLink Training and Status State Machine状态机负责。LTSSM是PCIe物理层实现里最复杂的状态机之一它管理着链路的检测、训练、恢复、低功耗切换等全套行为。对于做DWC_pcie_ctl_ep集成和仿真的工程师来说Training不通过后面所有模块的验证都是空中楼阁。所以实操系列把Training作为第6篇不是没道理的——前几篇把环境、工程、基础仿真跑通之后第一个要啃的硬骨头就是它。1.2 LTSSM状态机速览Detect到L0的完整旅程先给出一个精简版的LTSSM主状态流转图我用文字描述一下你后面会在波形里看到的关键状态链状态中文俗称这个阶段在干什么正常退出条件Detect检测确认链路另一端是否存在检测接收通道电气信号活动检测到接收器存在 → PollingPolling轮询发送TS1序列接收对端TS1完成位同步、符号同步收到有效TS1 → ConfigurationConfiguration配置协商链路宽度、极性、Lane编号交换TS1/TS2双方TS2交换完成 → L0L0正常工作传输TLP/DLLP数据报文出错/挂起 → Recovery/L0sRecovery恢复重新训练链路可升速、降速、重新配置重新训练完成 → L0Detect到L0这几步是上电训练的主线流程。整条链路的宽度协商x1/x2/x4/x8、极性反转lane polarity inversion和通道编号重排lane reversal都会在Configuration阶段完成。很多Training卡死问题就出在这几个子状态没有走完。1.3 Endpoint是被动方你的仿真里必须有个“对端”标题里的DWC_pcie_ctl_epep是Endpoint端点设备。这个角色有一个非常重要的属性——训练是被动的。Endpoint不会自己发起链路训练它只能在检测到对端Root Complex发送的训练序列之后被动回应并配合完成整个训练过程。这意味着如果你只在testbench里例化了一个DWC_pcie_ctl_ep没有挂RC侧模型也不挂任何BFMBus Functional Model你的Training状态机就会永远停在Detect.Quietlink永远up不起来。这不是你的RTL配错了而是仿真环境里缺少“对端”。实际操作中有几种常见方案在testbench里同时例化DWC_pcie_ctl_rcRC侧Controller和一个EP让两者互练这是最常见的方式。使用Synopsys VIP由VIP扮演RC发起训练这种方式在协议一致性验证里更灵活。自己写一个简单的训练序列发送BFM只负责按时序发TS1/TS2、响应训练状态适合早期冒烟测试。我自己最推荐第一种因为两个Controller背靠背互练训练完成后还能直接跑TLP收发的后续验证一鱼两吃。2. 在DWC_pcie_ctl_ep的RTL中定位训练逻辑方法比文件名可靠2.1 RTL目录“地图”先看物理层这一路拿到DWC_pcie_ctl_ep的RTL源码包之后别急着打开所有文件。先看目录结构脑子里要有张“地图”。DesignWare PCIe Controller的RTL一般会按子层组织application layer应用层、transaction layer事务层、data link layer数据链路层、physical layer物理层以及配置控制逻辑。Training相关的代码绝大部分都在physical layer这一路。你大概能看到类似这样的文件rtl/ ├── app_lnk/ // 应用层逻辑 ├── trn_lnk/ // 事务层 ├── dlt_lnk/ // 数据链路层 ├── phy_lnk/ // 物理层重点 │ ├── pcie_phy.v │ ├── pcie_ltssm.v │ └── ... └── config_lnk/ // 配置空间与寄存器注意一点不同版本、不同交付包里物理层模块完全可能叫pcie_trl.v、pcie_pipe.v之类的名字也可能把LTSSM状态机直接内嵌在pcie_phy.v里而不是独立成一个文件。所以下面这个方法才是真正靠谱的。2.2 grep定位法把ltssm和训练序列从源码里挖出来与其靠文件名猜不如直接把状态机相关的关键字挖出来。在RTL根目录下执行# 搜索LTSSM相关的所有RTL文件 grep -rln ltssm --include*.v --include*.sv . # 搜索训练序列相关的状态枚举定义 grep -rn LTSSM_STATE\|LTSSM_STATE_\|POLLING\|CONFIG_LINKWIDTH --include*.v --include*.sv . # 查找LTSSM状态编码的宏定义文件 grep -rn define.*LTSSM --include*.h --include*.v .这个方法在信号命名混乱的IP交付包里特别好用。我曾经遇到过某个版本把所有LTSSM相关逻辑塞在一个叫pcie_core_clk_mux.v的文件里光看文件名根本想不通一grep全暴露了。定位到代码文件之后推荐按这个顺序阅读先看LTSSM状态编码定义宏或localparam。再找状态机主跳转逻辑通常是case语句或者大量状态寄存器的赋值。最后看状态转移条件里依赖了哪些PHY接口信号。这一步做扎实了后面看波形时才有对照物。2.3 训练相关的关键信号清单我在实际调试中整理了这样一组信号你在RTL代码里搜索并对照即可信号名称以实际IP包为准方向作用ltssm_state输出当前LTSSM状态编码训练期间会持续变化pipe_txdata / pipe_txdatak输出发送到PHY的数据和K码标志TS1/TS2序列时段特征明显pipe_rxdata / pipe_rxdatak输入从PHY收到的数据和K码标志pipe_rxvalid输入接收数据有效标志对端训练时周期性拉高pipe_rxelecidle输入接收电气空闲指示用于Detect阶段判断线路状态pipe_txelecidle输出发送电气空闲控制pipe_phystatus输入PHY状态完成指示PIPE接口标准中用于复位等操作确认link_up / link_active输出链路训练完成标志进入L0后拉高这些信号在物理层顶层一般都能直接看到。如果你用PIPE接口连接外部PHY模型那pipe_开头的信号一定会暴露到PHY接口边界上非常好找。这里有个容易忽略的点有些版本会把ltssm_state做成sub-state级别也就是把Polling阶段细分成Polling.Active、Polling.Configuration、Polling.Speed、Polling.Deemphasis每个子状态都有独立编码。这对波形分析来说是好事因为你能看得更细但也意味着状态编码表会比协议文档里那11个主状态多很多。3. 波形分析实战读懂从Detect到L0的每一步3.1 波形Dump配置至少你得先看见这些信号拿到波形一切好说拿不到波形你只能靠$display日志猜。所以第一步是把波形文件配好。如果你用Verdi VCS的环境常见做法是initial begin $fsdbDumpfile(pcie_training.fsdb); $fsdbDumpvars(0, tb_top); $fsdbDumpMDA(0, tb_top); // 把memory也带上调试状态机时有用 end如果用纯VCS的vpd格式ucli database -vpd waves.vpd dump -add tb_top -depth 0 run无论哪种记住一条原则模拟开始后立刻打开全信号dump窗口不要过滤。链路训练阶段早期时间点很关键比如复位释放后的第一个100us内如果漏dump了后面分析状态机时你会发现缺少关键起点。等到真的开始细细调试再用$fsdbDumpvars指定层次减少文件体积。3.2 状态编码大坑先查宏定义再认状态这是新手最容易栽的地方。很多人对照协议文档里LTSSM的11个主状态发现波形里的数值完全对不上。比如Polling在协议里是状态1但波形里ltssm_state的数值是0x11甚至是个5位的onehot值。原因很简单IP内部的LTSSM状态编码与协议文档里的状态编号本来就不是一回事。协议文档里说有多少个状态IP实现时完全可以把每个子状态都单独编码。DWC内部为了实现sub-state细粒度控制常常会把状态编码扩展成几十个值。PIPE接口标准里倒是规定了LTSSM状态要映射到5位PIPE 4.0但具体怎么映射还是要查PHY实现文档。所以拿到每个新的IP版本我做的第一件事永远是# 把状态编码定义文件打印出来 grep -rn LTSSM_STATE ./rtl/phy_lnk/ | head -50先把LTSSM_STATE_DETECT_QUIET、LTSSM_STATE_POLLING_ACTIVE这些宏的数值记下来或者直接把宏定义文件里的状态名和数值整理到一张表里。然后再开波形查状态数字才能对上号。如果你用的仿真工具支持也可以把ltssm_state信号定义成带标签的枚举类型让工具直接把状态名显示在波形里。Verdi里可以给信号添加自定义Bus Display把每个数值映射成状态名调整波形可读性会好很多。3.3 一条正常训练波形里应该发生的“桥段”以Endpoint仿真为例一条完全正常的训练波形你至少应该看到这样几个事件复位释放之后ltssm_state先落在Detect.Quiet。这个阶段管子是安静的pipe_txelecidle和pipe_rxelecidle都处于无效状态未空闲。然后对端RC开始从它的发送通道发TS1序列。你如果盯着pipe_rxdata看会发现rxdatak出现K码标志rxdata里能看到K28.5字符序列。同时LTSSM检测到接收通道有电气活动状态从Detect.Quiet跳到Detect.Active然后进入Polling.Active。Polling阶段本端也开始回发TS1。这时观察pipe_txdata能看到一堆TS1有序集发送出来。TX和RX的TS1握手对上了状态进入Polling.Configuration再进入Polling.Speed确认速率最后进入Configuration.Linkwidth。Configuration阶段最明显的特征是TS1和TS2交替出现。链路宽度协商完成后会有一段专门的TS2交换双方互报“我已准备好”。TS2交换完毕ltssm_state跳到L0link_up或link_active信号拉高。到这一步training宣告成功。我把这套正常“桥段”记下来之后后面再跑任何PCIe仿真先扫一眼这几个关键拐点有没有按顺序出现基本就能判断训练是否成功。4. Training卡死场景从波形特征反推RTL根因4.1 卡在Polling出不来先怀疑符号同步和TS1没收到最常见的卡死场景是状态机在Polling.Active和Polling.Deemphasis之间反复横跳怎么都进不了Configuration。波形上的典型特征是ltssm_state一直在Polling这一组的几个值之间循环pipe_txdata确实在发TS1但pipe_rxvalid要么一直没拉高要么偶尔拉高一下又丢。这说明本端发送没问题问题出在接收方向——你大概率没有稳定接收到对端的TS1。这时候回RTL看代码重点找接收侧有没有完成符号同步也就是PCS层的symbol alignment逻辑。有的PHY模型里这个逻辑是行为级的能直接识别TS1有的则要求Controller内部自己做判断。如果接收侧的某个同步状态位一直无法置起链路就会卡死在Polling。另外还要排查一个很多人忽视的点对端RC侧是不是真的把训练序列发出去了。如果你的对端是VIP检查VIP的启动时序是否和本端复位释放时序配合如果是两个Controller互练注意两边的时钟频率和复位释放时间是否错得太远。实操里我还遇到过一种情况testbench里PHY模型没有喂参考时钟导致PCS逻辑根本没工作但ltssm_state看起来又在变化——因为它只是根据电气空闲信号在瞎猜状态实际上根本没锁定信号。这种情况波形上看rxvalid永远为低排查半天才知道是PHY侧时钟忘开了。4.2 卡在Configuration链路宽度协商多lane的坑另一种常见卡死点是Configuration阶段。典型表现是ltssm_state进入Configuration之后在Linkwidth和Lanenum子状态之间来回跳或者直接跳回Detect重新开始。RTL根因通常是多lane场景下的链路宽度协商失败。比如你的DWC_pcie_ctl_ep配置成x4但实际仿真中四条lane没有全部都训练成功其中某条lane的pipe_rxvalid一直不拉高或者那条lane的对端根本没驱动信号。Controller等不到完整链路宽度自然无法完成Configuration。排查时把所有lane的pipe_rxdata、pipe_rxvalid、pipe_rxelecidle信号都拉进波形逐lane检查。我之前遇到过一次奇葩情况四条lane里有一条的极性反转逻辑反了收到的TS1符号位是反的Controller这边receiver永远不能锁定那条lane。波形上能看到那条lane的rxdata和其他lane明显不一致顺着这个线索才找到根因。另一个隐蔽的坑是lane reversal相关配置。如果板级布线导致lane物理编号反了PCIe是要支持lane reversal的但这个能力需要在RTL里正确使能。没有使能或者使能条件没有被触发Configuration阶段就会因为lane编号对不上而失败。4.3 状态机突然跳回Detect复位和干扰要背锅还有一种更让人抓狂的场景Training前半段一切正常ltssm_state已经走到L0了link_up都拉高了结果过几个周期状态机突然跳回Detect.Quiet一切从头再来。这种波形特征指向两个方向。一是复位出了问题。训练过程中如果有复位信号出现毛刺或者复位撤除时序不满足要求LTSSM会被强制打回初始状态。检查复位信号波形特别是异步复位路径上的毛刺以及复位释放时钟沿是否干净。二是芯片内部DFT/测试逻辑干扰。带有扫描链或DFT逻辑的SoC如果训练过程中test_mode被意外拉起来或者DFT复用信号影响了PHY接口LTSSM同样会被打回Detect。波形上往往表现为ltssm_state瞬间跳变没有任何中间过渡状态。这种情况在纯RTL仿真里可能很难出现但在网表仿真或者带了DFT cell的仿真里比较常见。所以如果你跑的仿真里带了DFT逻辑Training失败时除了看ltssm_state记得把test_mode、test_rst_n以及相关的MUX选择信号一起拉进波形看一眼。还有一点经验之谈链路训练本质上是模拟、数字混合敏感的过程误码率或者电气空闲误判也可能导致L0状态掉回Recovery或Detect。不过纯RTL仿真里这类问题通常是PHY模型行为参数没配对造成的优先检查PHY模型配置即可。我个人的习惯流程是先看是“卡住不动”还是“跳回重来”再根据这两种特征决定先查接收侧同步逻辑还是先查复位和测试模式干扰。把现象归类排查范围就小了一大半。最后再分享一个调试小技巧在仿真代码里加一段状态机跳转监控比对着波形数周期要快得多。ifdef SIM_DEBUG logic [4:0] prev_ltssm_state; always (posedge core_clk or posedge phy_rst_n) begin if (phy_rst_n) prev_ltssm_state 0; else prev_ltssm_state ltssm_state; end always (posedge core_clk) begin if (ltssm_state ! prev_ltssm_state) $display([%0t] LTSSM state changed: %h - %h, $time, prev_ltssm_state, ltssm_state); end endif这段代码在训练卡死的时候能直接把状态跳转的时序打印出来配合波形一起看往往几分钟就能定位到是哪个转移条件不满足。对不同工具环境你也可以用更规范的SVA断言来做状态跳转检查。总之别指望只看裸波形就解决所有问题RTL代码分析和波形分析是两条腿少一条都走不远。这套方法在你后面做Transaction Layer、Data Link Layer解析的时候还能继续用只是把ltssm_state换成trn接口、dllp接口罢了。
返回列表