ARTICLE DETAIL

资讯详情

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

Vivado Tri_mode_ethernet_mac Core Container解包与RGMII时序修改实战

Vivado Tri_mode_ethernet_mac Core Container解包与RGMII时序修改实战 1. 为什么Core Container模式值得单独拿出来讲用过Vivado的人都知道Tri_mode_ethernet_mac这个IP核在以太网开发里算是老面孔了从早期的ISE时代一路演进过来功能覆盖10M/100M/1G三种速率支持GMII、RGMII、SGMII等多种PHY接口。但很多人第一次在Vivado里例化它的时候会碰到一个让人摸不着头脑的选择——Core Container。默认情况下Vivado会勾选这个选项然后你生成IP、打开示例工程、跑仿真一切看起来都正常。可一旦你要把IP集成到自己的工程里尤其是需要修改接口或者做引脚约束的时候问题就来了你找不到那个熟悉的tri_mode_ethernet_mac_0.v取而代之的是一堆.xci和.xcix文件RTL代码像是被藏进了一个黑盒子里。这不是Vivado在故意为难你而是Xilinx从2016.x版本开始推行的一种IP封装策略。Core Container的本质是把IP的所有源文件、约束文件、仿真文件打包成一个独立的容器目录让IP在工程中以一种“自包含”的方式存在。好处是版本管理清晰、IP升级方便、多工程复用不容易出错。坏处也很明显你没法直接改RTL了。对于以太网MAC这种经常需要根据PHY芯片手册微调接口时序的IP来说这简直是卡脖子。我这次的项目背景是这样的一块自研的Zynq-7020板子PHY用的是Realtek RTL8211F接口模式选的是RGMII。Vivado版本是2020.2Tri_mode_ethernet_mac配置成1G/100M/10M自适应启用MDIO和统计计数器。本来以为按照PG051文档走一遍就行结果在Core Container模式下折腾了整整两天才把RGMII的时序跑通。这篇文章就是把踩过的坑一个个填平从IP配置、容器解包、RGMII接口修改到时序约束全部捋一遍。如果你也在用这个IP核尤其是RGMII接口这篇内容应该能帮你省下不少调试时间。2. Core Container模式的核心机制与解包思路2.1 Core Container到底封装了什么先搞清楚这个容器里装了什么。当你勾选Core Container后Vivado会在工程目录下生成一个类似tri_mode_ethernet_mac_0的文件夹里面通常包含这几个关键部分synth/目录存放综合后的网表文件.dcp这是容器模式的核心IP在综合阶段直接调用这个网表不再重新编译RTL。sim/目录仿真用的行为级模型通常是加密的Verilog文件。srcs/目录包含IP的顶层包装文件、约束文件.xdc和一些辅助脚本。.xci文件IP的配置文件记录了你所有的参数选择。关键点在于综合流程走的是.dcp网表而不是RTL。这意味着即使你找到了RTL源文件并修改了综合工具也不会理你。很多人在这里翻车——改了tri_mode_ethernet_mac_0.v里的信号名重新跑综合结果报错说端口不匹配就是因为综合用的还是旧网表。那为什么Xilinx要这么做从工程管理角度讲容器模式确实有优势。一个大型项目里可能例化十几个IP如果每个IP都展开成RTL工程文件数量会爆炸版本控制也很痛苦。容器模式把IP变成一个“原子单元”升级时只需要替换容器目录不会影响其他逻辑。但对于需要深度定制的场景这个封装就成了障碍。2.2 什么时候该用容器模式什么时候该关掉我的经验是如果IP的接口和时序完全符合你的需求直接用容器模式省事。比如你用SGMII接口PHY是标准的Marvell 88E1512时序上不需要任何调整那容器模式没问题。但如果你用的是RGMII而且PHY芯片的时序参数和Xilinx默认值有偏差那就必须关掉容器模式拿到RTL自己改。关掉的方法很简单在IP配置的“Core Container”页面把“Enable Core Container”的勾选去掉。但注意这个操作不可逆——一旦生成IP后再想切换只能删掉IP重新配置。我试过在工程里直接改.xci文件里的参数结果Vivado直接报IP锁错误最后还是老老实实重建。还有一个折中方案保持容器模式但通过“Edit in IP Packager”把IP解包成可编辑的工程。这个流程后面会详细讲适合那些不想重建IP但又需要改RTL的情况。2.3 解包容器的两种实操路径路径一重建IP时直接关闭容器。这是最干净的做法。在IP Catalog里重新配置Tri_mode_ethernet_mac到“Core Container”页面取消勾选然后Generate Output Products时选择“Global”而不是“OOC”Out-of-Context。这样Vivado会把RTL源文件直接展开到工程里你可以像普通Verilog文件一样编辑。路径二通过IP Packager解包。如果IP已经生成且不想重建可以在Sources窗口右键IP选择“Edit in IP Packager”。Vivado会打开一个临时工程里面包含IP的所有源文件。你可以在这里修改RTL然后重新打包生成新的IP。这个方法的缺点是每次修改都要重新打包而且打包后的IP和原始IP的版本管理容易混乱。我一般只在紧急修改时用这个方法长期项目还是走路径一。注意无论用哪种方法修改RTL后一定要重新生成IP的输出产物否则综合工具用的还是旧的网表或缓存。3. RGMII接口修改的关键细节与实操步骤3.1 RGMII接口的时序特点与常见问题RGMII接口和GMII最大的区别在于数据位宽从8位降到4位但时钟频率翻倍。1G速率下RGMII的时钟是125MHz数据在时钟的上升沿和下降沿都采样DDR模式。这就带来了一个经典问题时钟和数据之间的 skew。Xilinx的Tri_mode_ethernet_mac IP默认会在FPGA侧对TXC发送时钟做90度相移使得时钟边沿对齐数据的中心。但这个默认值是基于Xilinx自己的PHY测试板得出的换一块板子、换一个PHY芯片这个相移可能就不对了。RTL8211F的 datasheet 里明确写了TXC和TXD之间的 skew 典型值是1.5ns到2.0ns取决于走线长度和PHY内部延迟。如果FPGA侧的相移和这个值不匹配就会出现丢包、CRC错误甚至链路无法建立。我一开始用默认配置MDIO能读到PHY的ID但ping不通用ILA抓波形发现TXD的数据眼图完全闭合。3.2 修改RTL实现可调的TXC相移要解决这个问题必须修改IP的RTL把固定的90度相移改成可配置的。具体操作如下第一步找到RTL中的时钟生成模块。在解包后的源文件里搜索tri_mode_ethernet_mac_0_clk_gen或者类似的模块名。这个模块负责生成TXC和GTX_CLK。在RGMII模式下TXC通常是通过一个ODDR原语实现的把FPGA内部时钟转发到引脚。第二步定位ODDR的例化代码。原始代码大概长这样ODDR #( .DDR_CLK_EDGE(SAME_EDGE), .INIT(1b0), .SRTYPE(SYNC) ) ODDR_txc ( .Q(txc_out), .C(clk_125m), .CE(1b1), .D1(1b1), .D2(1b0), .R(1b0), .S(1b0) );这里的D1和D2固定为1和0输出就是50%占空比的时钟。要实现相移需要把clk_125m替换成一个经过MMCM或PLL移相的时钟。比如用MMCM生成两个时钟clk_125m_00度和clk_125m_9090度然后根据需求选择。第三步添加一个参数或寄存器来控制相移选择。我通常会在顶层加一个txc_phase_sel信号通过AXI-Lite或者直接引脚控制。这样在板级调试时可以通过改变这个信号来扫描不同的相移值找到最佳采样点。// 相移选择逻辑 wire clk_txc; assign clk_txc txc_phase_sel ? clk_125m_90 : clk_125m_0; ODDR #( .DDR_CLK_EDGE(SAME_EDGE), .INIT(1b0), .SRTYPE(SYNC) ) ODDR_txc ( .Q(txc_out), .C(clk_txc), .CE(1b1), .D1(1b1), .D2(1b0), .R(1b0), .S(1b0) );第四步重新生成IP并综合。注意修改RTL后IP的.xci文件里的参数可能和RTL不一致需要手动同步。我一般会在IP Packager里重新打包确保.xci和RTL匹配。3.3 接收路径的IDDR与延迟调整发送路径解决了接收路径同样需要关注。RGMII的RXC是从PHY过来的时钟FPGA需要用IDDR来采样RXD。Xilinx的IP默认会在RXC上插入一个延迟通过IDELAY或逻辑延迟但这个延迟值也是基于默认PHY的。RTL8211F的RXC和RXD之间的skew可能不同需要调整。在RTL中搜索IDDR或idelay相关的代码。通常IP会例化一个IDELAYE2原语延迟值由idelay_value参数控制。你可以把这个参数引出到顶层通过寄存器配置。实测下来RTL8211F在1G模式下RXC的延迟值在0到8之间扫描通常3到5是最佳点。IDELAYE2 #( .IDELAY_TYPE(VAR_LOAD), .DELAY_SRC(IDATAIN), .IDELAY_VALUE(4), .REFCLK_FREQUENCY(200.0), .HIGH_PERFORMANCE_MODE(TRUE) ) IDELAYE2_rxc ( .CNTVALUEOUT(cntvalueout), .DATAOUT(dataout), .C(clk_200m), .CE(ce), .CINVCTRL(1b0), .CNTVALUEIN(cntvaluein), .DATAIN(1b0), .IDATAIN(rxc_in), .INC(1b0), .LD(ld), .LDPIPEEN(1b0), .REGRST(1b0) );提示IDELAYE2的参考时钟必须是200MHz这个时钟需要单独生成。如果工程里没有200MHz可以用MMCM从系统时钟分频得到。3.4 引脚约束与IO标准设置RGMII的引脚约束也是容易出错的地方。首先TXC和RXC必须分配到带有时钟能力的引脚MRCC或SRCC否则ODDR/IDDR无法正常工作。其次IO标准要设置为HSTL_I或LVCMOS33具体取决于PHY的电压。RTL8211F的RGMII接口通常是3.3V LVCMOS所以IO标准设为LVCMOS33驱动能力设为8mA。约束文件里需要加上set_property PACKAGE_PIN W13 [get_ports eth_rxc] set_property IOSTANDARD LVCMOS33 [get_ports eth_rxc] set_property PACKAGE_PIN V13 [get_ports eth_rxd[0]] set_property IOSTANDARD LVCMOS33 [get_ports eth_rxd[0]] # ... 其他数据引脚类似还有一个细节RGMII的TXC在FPGA侧是输出但PHY侧是输入。所以FPGA的TXC引脚需要设置为输出而RXC引脚设置为输入。这个方向不能搞反否则链路直接不通。4. 时序约束与调试实战4.1 RGMII时序约束的写法RGMII的时序约束是另一个大坑。Xilinx的IP自带一个.xdc文件里面有一些默认约束但那些约束是基于IP内部逻辑的不包含从FPGA引脚到PHY的板级延迟。如果你不做额外的约束Vivado的时序分析会认为TXC和TXD之间的skew是0这显然不符合实际。正确的做法是在顶层约束文件里对RGMII接口添加set_output_delay和set_input_delay约束。以1G模式为例TXC周期是8ns125MHz数据在时钟边沿变化。假设PHY的建立时间要求是1.0ns保持时间要求是0.5ns那么# 发送路径 set_output_delay -clock [get_clocks eth_txc] -max 1.0 [get_ports eth_txd*] set_output_delay -clock [get_clocks eth_txc] -min -0.5 [get_ports eth_txd*] set_output_delay -clock [get_clocks eth_txc] -max 1.0 [get_ports eth_tx_ctl] # 接收路径 set_input_delay -clock [get_clocks eth_rxc] -max 1.5 [get_ports eth_rxd*] set_input_delay -clock [get_clocks eth_rxc] -min 0.5 [get_ports eth_rxd*] set_input_delay -clock [get_clocks eth_rxc] -max 1.5 [get_ports eth_rx_ctl]这些值需要根据PHY的datasheet和PCB走线长度来调整。如果走线长度是5cm信号传播速度约6.7ps/mm那么延迟约0.33ns。把这个值加到建立/保持时间上就是最终的约束值。4.2 用ILA抓波形定位问题约束写好了但链路还是不通怎么办这时候ILA就是最好的朋友。我通常会在RGMII接口附近插入一个ILA核抓取TXC、TXD、RXC、RXD和相关的控制信号。触发条件设为“CRC错误”或“接收数据有效但CRC不对”。抓波形时要注意ILA的采样时钟必须和被测信号同步。对于TXC域的信号用TXC作为ILA时钟对于RXC域的信号用RXC作为ILA时钟。如果用一个时钟抓另一个时钟域的信号看到的波形是乱的。我遇到的一个典型问题是TXD的数据在TXC的上升沿和下降沿都变化但PHY采样时发现某个bit总是错。用ILA抓波形后发现TXC的相移不够数据变化沿太靠近时钟沿。把相移从90度调到120度后问题解决。4.3 常见问题速查表问题现象可能原因排查方法解决方案MDIO能读ID但ping不通TXC相移不对ILA抓TXD和TXC调整MMCM相移扫描0-180度链路时通时断RXC延迟不稳定检查IDELAY参考时钟确保200MHz参考时钟稳定CRC错误率高数据skew过大测量PCB走线长度调整set_output_delay约束综合报DRC RTSTAT-2时钟引脚分配错误检查引脚是否在MRCC/SRCC重新分配时钟引脚仿真通过但上板失败容器模式网表未更新检查IP是否重新生成删除IP重新生成输出产物注意DRC RTSTAT-2错误通常是因为时钟信号被分配到了普通IO引脚。RGMII的TXC和RXC必须分配到时钟专用引脚这个在原理图设计阶段就要确认。5. 容器模式下的仿真与固化注意事项5.1 仿真环境的搭建Core Container模式下仿真用的模型是加密的你没法看到内部逻辑但可以正常跑仿真。需要注意的是仿真时RGMII的PHY模型需要自己写一个简单的行为级模型模拟PHY的收发行为。Xilinx的示例工程里通常包含一个phy_model但那个模型是基于GMII的RGMII需要自己改。我一般会写一个简单的RGMII PHY模型用IDDR和ODDR模拟PHY侧的采样和发送。这个模型不需要太精确只要能验证数据通路的正确性就行。仿真时重点看MAC是否正确地发送了前导码、SFD和数据帧以及接收路径是否能正确解析。5.2 固化文件的生成Vivado在连接硬件的情况下生成固化文件这个流程本身不复杂但容器模式下有个坑IP的网表文件可能没有被正确包含在比特流里。我遇到过几次综合和实现都通过了但生成的比特流下载后以太网不工作。后来发现是IP的.dcp文件在实现阶段没有被正确引用。解决方法是在生成比特流之前手动检查IP的状态。在Sources窗口右键IP选择“Generate Output Products”确保所有输出产物都是最新的。然后在Implementation设置里确认“Incremental Compile”没有勾选因为增量编译有时会跳过IP的重新综合。另外固化文件.bin或.mcs的生成需要在Implementation完成后进行。在Vivado里选择“Generate Bitstream”然后在Hardware Manager里选择“Create Boot Image”。注意如果工程里用了Zynq还需要配置FSBL和BOOT.bin的生成流程。5.3 版本兼容性问题Vivado的版本更新很快不同版本之间Tri_mode_ethernet_mac IP的行为可能有差异。我在2020.2上调通的配置拿到2022.2上重新生成IP后RGMII的时序又不对了。后来发现是2022.2的IP默认相移值改了从90度变成了0度。所以每次升级Vivado版本后都要重新检查IP的配置和时序约束。还有一个常见问题是License。Tri_mode_ethernet_mac是免费IP不需要额外License但如果你用了其他付费IP比如某些高速接口License文件的位置和版本要匹配。Vivado 2020.2的License在2022.2上可能不认需要重新生成。6. 个人实操心得与后续扩展这个项目折腾下来最大的体会是不要迷信IP的默认配置。Xilinx的IP文档写得很详细但默认值是基于他们的测试板换一块板子就可能不适用。尤其是RGMII这种对时序敏感的接口必须根据实际硬件调整。另一个心得是容器模式适合快速原型不适合深度定制。如果你的项目需要修改IP的RTL最好在项目初期就关掉容器模式把RTL展开到工程里。后期再改成本会高很多。后续如果还要扩展可以考虑把RGMII的相移和延迟控制做成AXI-Lite寄存器通过软件动态调整。这样在批量生产时不同板子之间的微小差异可以通过软件校准不需要重新综合FPGA。这个思路在工业级产品里很常见值得一试。最后分享一个小技巧在调试RGMII时可以先用100M模式验证链路因为100M模式下RGMII的时钟是25MHz时序要求宽松很多。等100M通了再切到1G模式调时序。这样可以把问题和速率解耦定位起来更快。
返回列表