做FPGA以太网通信,不少人一开始就在MAC和PHY之间的接口选择上犯了难。GMII、RGMII、SGMII,名字看着像,用起来完全是两码事。尤其是SGMII,看着就两条差分线,似乎很简单,但真正调起来,PHY配置、时钟恢复、链路协商、8B/10B编解码,任何一个环节卡住,网口就是不亮。我最早从GMII切到SGMII的时候,以为只是换换引脚约束,结果被链路自协商折腾了一整周。这篇就以SGMII接口和PHY配置为主线,把我在实际项目中踩过的坑、验证过的方法,以及这套链路从复位到数据收发的完整流程,一次讲清楚。
1. 为什么用SGMII:三种常用MAC-PHY接口的取舍
先别急着看代码和寄存器,选型这件事放在最前面讲。很多初学者喜欢直接抄参考设计,觉得哪个接口火就用哪个,结果到了布线、时序收敛、跨板调试的时候才发现根本不是那么回事。SGMII并不是在所有场景下都是最优解,它只是千兆以太网场景里一个均衡度很高的方案。
1.1 GMII的并行困境
GMII(Gigabit Media Independent Interface)是IEEE 802.3标准里定义的并行接口,数据位宽8bit,125MHz时钟下双向同时传输,加上TX_EN、TX_ER、RX_DV、RX_ER、GTX_CLK、RX_CLK等控制信号,整体下来要十几根信号线。在单纯的PCB板上拉线倒也没什么,但如果你的FPGA是BGA封装,引脚资源紧张,一片板子上有多个网口,那GMII的布线代价就会逼你重新做选择。
更让人头疼的问题是时钟域的约束。GMII不是源同步接口,但数据与时钟的skew要求很苛刻,PCB上每根走线都要尽量等长。125MHz的8位并行总线,在Layout时还勉强能控制,但一旦跑上DDR3或者做多通道并行处理,MAC侧的时序约束很容易出现负slack。我见过不止一次,板子回来后因为GMII的一组线等长差了几十mil,千兆模式怎么都练不上去,最后只能跑百兆。这类问题在调试阶段极其隐晦,既不是逻辑错误,也不是寄存器配错,纯粹是物理层的时序裕量被蚕食干净了。
1.2 RGMII的时序压缩
RGMII(Reduced Gigabit Media Independent Interface)就是为了解决GMII信号线太多而出现的。它的思路很简单——把8位数据线改成4位,然后在时钟的上升沿和下降沿各采一次,用DDR的方式补齐带宽。这样一来,信号线数量大幅缩小,时钟仍然是125MHz,但数据率翻倍成了250Mbps/引脚。
RGMII的最大争议在于它的时序模型:FPGA侧送给PHY的TX时钟通常需要做90度相移,以保证PHY在采数据时落在眼图中央。这部分在代码里的实现方式通常是ODDR原语加相位约束,不算难,但需要你对时序要求有明确理解。RGMII对PCB布线依然有一定要求,尤其是时钟和数据的等长,违反了之后轻则链路不稳定,重则完全不通。相比SGMII,RGMII省了引脚但没有省掉时序压力,只是把压力从并行总线的多根线转移到更窄的时序窗口上。
1.3 SGMII的串行方案
SGMII(Serial Gigabit Media Independent Interface)彻底抛弃了并行数据线,改用一对发送差分线和一对接收差分线,线速率为1.25Gbps,内部通过8B/10B编码将8bit数据扩展成10bit并串行发送。与GMII/RGMII相比,SGMII的最大优势是引脚少、PCB布线简单,而且它不要求高频并行时钟线与数据线严格等长,因为数据时钟内嵌在串行码流中,接收端可以通过CDR恢复。
SGMII的联合了百兆和十兆速率,这很关键——尽管物理线路始终跑在1.25Gbps,但当链路协商速率为100M或10M时,MAC与PHY之间的有效数据率会相应降速,SGMII层通过插入空闲码来填满带宽。这意味着同一套串行线路可以适配不同速率,切换时不需要重新布板。
对比一下:GMII适合做调试和教学,直观但对引脚和布线不友好;RGMII在低成本、低引脚数PCB上很常见,但时序要求高;SGMII则是高速、多网口、高可靠性场景下的首选,代价是你必须在FPGA内部实现或者例化一套PCS逻辑。很多人一听到要自己做8B/10B和时钟恢复就打退堂鼓,其实Xilinx、Intel以及主流国产FPGA都提供了现成的SGMII IP核或硬核,真正要自己写核心逻辑的情况非常少。我们真正要注意的是如何把这些IP与PHY芯片协同工作起来。
2. SGMII链路机制:不只是两根线的事
SGMII看起来信号就四根(TX_P/N、RX_P/N),但它内部的工作机制比RGMII复杂得多。很多人调试SGMII遇到问题,就是因为它根本搞不清这条串行链路上到底在传什么东西。下面把协议层面的几个关键机制拆开聊。
2.1 物理通道与链路速率
SGMII物理层的串行数据速率固定在1.25Gbps,每一对差分线承载这个速率。发送和接收方向完全对称,全双工工作。这1.25Gbps的由来是1Gbps有效数据加上8B/10B编码带来的25%开销:1000Mbps × 10/8 = 1250Mbps。
FPGA内部的结构通常是——MAC层产生8bit并行数据,经过PCS层的8B/10B编码后变成10bit码字,再通过并串转换器(SerDes)按1.25Gbps的速度逐bit发出。接收方向反过来:CDR从差分线上恢复出串行数据和时钟,串转并还原成10bit码字,经过8B/10B解码后得到8bit数据和控制信号,送给MAC层。
还有一个容易搞混的概念:10M/100M低速模式下,SGMII物理层怎么工作。答案是物理线路速率永远不变,依然1.25Gbps,但有效数据在MAC与PCS之间不是每个周期都有效。比如100M模式下,有效数据占比约1/10,其余位置填充空闲符号。这点理解之后,对于后面看PHY的link状态和调试带宽问题非常有帮助。
2.2 8B/10B编码与码流同步
8B/10B编码是SGMII的底层核心。为什么要用8B/10B?两个理由——直流平衡和时钟恢复。原始数据流的0/1分布是不确定的,如果长串连续相同电平,接收端的CDR很难恢复出正确的时钟沿。8B/10B编码将每个8bit字节映射成10bit码字,且通过计算运行不一致性(Running Disparity)保证整个码流中0和1的数量尽可能均衡,也就保证了电平翻转密度。
在SGMII链路上,除了数据码字,还有控制码字,最关键的是K码(Comma码)。K28.5(编码为0011111010或1100000101)被用作码流对齐标记。接收端在bit流中不断搜索这个特定的Comma图案,一旦找到,就据此确定码字边界,完成字对齐。这个过程在FPGA里通常由SerDes的接收对齐状态机自动完成,但配置SGMII IP时对齐方式(Alignment)一定要选对,比如基于K28.5或者基于可编程对齐模板。
另外,SGMII每接收一个码字就要判断它是数据码还是控制码。K码有多种用途:IDLE(K28.5)、Start of Packet(K27.7)、End of Packet(K29.7)等。以太网MAC层在发送数据帧时,帧头帧尾都要打上对应的控制码;接收时如果没有能正确识别这些控制码,上层就会丢弃该帧。
2.3 链路自协商:PHY和MAC如何握手
SGMII的自协商(Auto-Negotiation)可能是整个链路中最容易被误解的环节。注意:SGMII自协商和PHY与对端设备之间的自协商是两回事,但要协同工作。
SGMII链路建立初期,MAC侧PCS和PHY之间需要协商出工作速率(10M/100M/1000M)。这个过程在SGMII规范里是通过在空闲码(IDLE)中嵌入配置信息完成的。PHY和MAC各自发送带有速率能力字段的IDLE码流,双方读到对方的能力后,选择共同支持的最高速率并锁定,然后把link状态拉高。
这里有一个FPGA调试中很常见的坑:如果FPGA侧的SGMII IP没有正确启动自协商状态机,或者PHY配置为强制1000M而不是自协商模式,双方速率不匹配,PHY侧link灯可能是灭的,或者FPGA侧rx_byte_aligned状态一直拉不起来。我调试的时候习惯先把SGMII IP的自协商打开,等链路稳定后再看MAC层的收发状态,减少变量数。
3. PHY配置实战:寄存器级操作与MDIO时序
SGMII链路建不起来,问题经常出在PHY芯片的配置上。PHY芯片上电后的默认状态不一定满足你的系统要求,尤其是时钟来源、速率模式、接口模式这些关键项,必须通过MDIO总线写寄存器来控制。
3.1 MDIO总线时序
MDIO(Management Data Input/Output)是一种两线管理接口,一条MDC时钟线,一条MDIO数据线,用来访问PHY内部的寄存器。它由MAC侧发起操作,读或写16bit长度的寄存器数据。MDC最高频率在IEEE规范里建议不超过2.5MHz,不过大多数PHY芯片能承受更高,FPGA做主控时一般生成1MHz左右最稳。
MDIO的帧格式分几个阶段:
- 前导码(Preamble):32个连续的1,用于同步。
- 起始码(Start of Frame):01。
- 操作码(Op Code):读为10,写为01。
- PHY地址(PHY ADDR):5bit,用来选中总线上哪个PHY。PHY的地址通常由硬件引脚决定,常见配置是0x01或0x00。
- 寄存器地址(REG ADDR):5bit。
- 写操作时,后面直接跟16bit写数据,在MDC上升沿采样;读操作时,先插入2bit的转向时间(Turnaround),再输出16bit数据。
我在FPGA里写过MDIO驱动,代码逻辑非常简单:一个状态机,一个计数器,按bit把帧拼出来就行。真正需要注意的是MDIO是双向引脚,读的时候还必须切换方向,如果不小心让FPGA一直驱动MDIO输出,读出来的数永远是全0xFF或者全0x00,这是新手特别容易踩的坑。
3.2 核心寄存器解读
PHY芯片的寄存器空间前16个是IEEE 802.3定义的通用寄存器,后面的厂商自定义。要做SGMII的PHY配置,最常用的寄存器是这几位:
寄存器0(Control):最常用的是第15位(Soft Reset)、第14位(Loopback)、第13位(Speed Select LSB)和第6位(Speed Select MSB)。这两个速度位组合:00=10M,01=100M,10=1000M,11=Reserved。如果你要强制千兆模式,就把第6位置1,第13位置0。
寄存器1(Status):第15位是100BASE-T4支持,第14位是100M全双工支持,第13位是100M半双工支持,第12位是10M全双工,第11位是10M半双工,第10位是100BASE-TX全双工,第9位是100BASE-TX半双工,第8位是10BASE-TX全双工,第7位是10BASE-TX半双工,第6位是MF preamble suppress,第5位是Auto-Negotiation Complete,第2位是Link Status。调试时最常看的就是第2位Link Status,为1表示链路通。另外第5位自协商完成,如果一直是0,说明自协商还没跑完。
寄存器4(Auto-Negotiation Advertisement):用来向对端广播自己的能力,比如是否支持10M、100M、1000M,以及全双工/半双工。要让PHY和交换机之间协商上千兆全双工,这一位的配置要正确。
寄存器5(Auto-Negotiation Link Partner Ability Register):读它可以看到对端广播了什么能力。如果两端能力不符合预期,比如交换机只支持百兆,你强制配了千兆,导致link失败。这时应回退到自协商模式,让双方自己商量。
3.3 一个完整配置流程
假设我用的是一个常见千兆PHY芯片(比如RTL8211系列),FPGA通过MDIO总线对PHY做初始化,我一般按下面这个顺序操作:
先做PHY的硬件复位,等待复位完成。然后通过MDIO写寄存器0,把软复位位置1。软复位之后不要立刻写其他寄存器,必须等待bit15自动变回0,说明复位完成。接着配置寄存器4,广播自己支持的能力。比如写0x01E1,这个值表示支持10M半双工/全双工、100M半双工/全双工、1000M半双工/全双工。
再写寄存器0,让bit12(Auto-Negotiation Enable)和bit9(Restart Auto-Negotiation)置1,同时把bit13和bit6清零,让PHY进入自协商状态。然后进入等待状态,读取寄存器1,看bit5(Auto-Negotiation Complete)是否为1。自协商完成后,读取寄存器1的bit2,确认Link Status为1。
这里有一个很隐蔽的坑:寄存器的Link Status是“latching low”的,只要发生过断链,它就会一直为0,直到你把寄存器1整读一遍之后,它才重新反映真实状态。所以在读这个bit之前,必须先读一次寄存器1。如果发现Link断,也要考虑是不是位锁存导致的误判。
配置完PHY之后,不要急着发数据,先确认SGMII侧的状态。对PHY来说,SGMII的接口模式可能也有寄存器要配。在某些PHY芯片上,如果你不配置接口模式选择位,PHY可能默认工作在RGMII模式,导致FPGA这边SGMII怎么都对不齐。所以上电后第一件事是读芯片的ID寄存器(寄存器2和3),确认MDIO能通、驱动芯片型号和原理图一致,再继续配置其他字段。
4. 从零到通:SGMII环回测试与FPGA侧PCS设计要点
先用最低成本的方式把链路打通,再谈后续的数据收发。环回测试是调试SGMII链路最有效的手段。我推荐按“PHY环回、SGMII近端环回、远端环回、最终端到端”这个顺序逐步推进。
4.1 最省事的验证路径:PHY内部环回
把PHY的寄存器0第14位置1,数据从FPGA的SGMII_TX信号进入PHY,从PHY的SGMII_RX信号返回FPGA。此时数据没有经过物理网线和对端设备,纯粹验证FPGA到PHY之间的SGMII路径。
如果这个环回都不通,说明问题在FPGA与PHY之间的串行链路、SGMII IP配置,或者MDIO配置上。一旦这个环回通了,就证明FPGA的PCS发送接收链路和PHY的SGMII接口基本没问题。
如果PHY内部环回通常是过不了。重点排查SGMII IP有没有复位、TX差分线有没有接反、参考时钟是否正常。
如果千兆模MAC向PHY发送的以太网帧,经PHY环回后,MAC能正确收到自己的帧,说明整条链路已经通了。
4.2 FPGA内部PCS的关键模块与速率适配
在FPGA内部,如果用的是Xilinx的1G/2.5G Ethernet PCS/PMA IP,至少要知道它内部包含哪些模块。一般由PMA(Physical Media Attachment)和PCS(Physical Coding Sublayer)组成。PMA处理并串转换和时钟恢复,PCS负责8B/10B编解码、自协商、链路状态管理。
按标准的话说,FPGA内部信号通路的时钟关系大致是:在千兆模式下,用户侧数据接口为8bit @125MHz。再往里面走,经过8B/10B编码后变成10bit数据,然后被SerDes以1.25Gbps发出。100M模式时,用户侧是8bit @12.5MHz,后面编码还是10bit,线速率仍是1.25Gbps,但中间会填大量空闲码。这个速率适配往往被忽视。很多人在千兆模式下能够正常收发,一跑到百兆模式就发现带宽不对、丢包严重,就是因为没有正确理解MAC接口数据率已经降到12.5MHz。
时钟恢复是另一个关键点。SGMII接收端从串行码流中恢复时钟,这个时钟频率不一定完全等于标称的1.25GHz,会有ppm级的偏差。因此接收侧的FIFO要做跨时钟域处理,或者在IP内部用异步FIFO把恢复时钟域的数据搬到用户时钟域。在设计MAC时,发送和接收方向一定预留FIFO,不要直接让MAC逻辑咬着SerDes的时钟跑。
4.3 时序约束与上板调试前检查
SGMII的时序约束比GMII/RGMII简单,因为内部同步逻辑都在SerDes和IP核里。但你仍然需要做几件事:
第一,SGMII的差分时钟引脚要在XDC或QSF文件里定义引脚和电平标准,常用的是LVDS或LVPECL,不同PHY的参考设计不一样,务必查规格书。
第二,SGMII IP的复位信号不要随便接。上电后要先等待PHY初始化完成,最好由外部控制器在PHY配置结束后再释放SGMII IP的复位。如果PHY还在配置过程中,FPGA侧已经开始发码流,可能出现SGMII链路在早期一直不能对齐的情况。
第三,所有跨时钟域的异步信号都要打两拍同步,尤其是外部PHY的中断、Link状态信号。SGMII的link状态如果直接接到FPGA内部状态机做复位控制,亚稳态问题会放大。这种高速链路加外部慢速信号,复位释放一个没处理好就可能起不来。
5. 高速线路上最容易翻车的几个环节
SGMII虽然信号线少,但1.25Gbps的线路速率对信号完整性还是提出了要求。板子跑了千兆就不稳定,偶尔link down,联调的时候总是时好时坏,大多是以下几类原因。
5.1 信号完整性与PCB检查清单
SGMII的差分对走线要按100欧姆差分阻抗控制,AC耦合电容要靠近接收端放置。电容容值一般是0.1uF,如果放反或者漏放,信号会直接被隔断。SGMII不像以太网PHY到RJ45那一段有变压器,FPGA和PHY之间的SGMII是交流耦合的,没有电容信号就过不来。
差分对两条线等长尽量控制在5mil以内,对内等长比线对之间等长更重要。不同SGMII lane之间(如果你有多个网口)不要平行走长距离,这会引入串扰。过孔的stub也会在1.25GHz下引发阻抗不连续,建议高速线尽量不走换层,非换不可时要加回流地孔。
调试时如果发现链路偶尔断开,优先检查SGMII差分信号的眼图。没有示波器的话,可以观察PHY芯片的寄存器Link状态,配合FPGA侧的错误计数器定位。我在调试时发现,很多看似程序bug的问题,实际上就是SGMII走线上串扰把接收端的信噪比拉低,导致偶尔出现误码。
5.2 时钟与复位:高速链路的两大命门
SGMII的参考时钟一般要求125MHz或与之对应,且抖动指标有硬性要求。如果从普通的时钟芯片直接拉一路过来未做cleanup,容易导致CDR性能下降。有条件的板子一定要优先选择PHY的专用时钟,或使用晶体振荡器提供低抖动时钟。
复位这里需要特别注意。PHY芯片的硬件复位引脚时序有最小复位脉冲宽度要求,上电后要满足PHY的电源稳定时间再复位。FPGA内SGMII IP的复位也要满足时序要求,不能与PHY的配置流程混乱。其实一次不够的话,就把复位时间拉长一些,等PHY侧寄存器完全可访问后再拉高SGMII IP的复位,宁可慢一点也不要抢时序。
5.3 状态机与链路down调的坑
SGMII的链路建立是一个状态机过程,从复位、配置、自协商、同步对齐、到最终进入数据收发,中间任何一步卡住,都可能表现为link丢或数据不通。
如果FPGA里自己实现了SGMII状态机,建议把状态机状态暴露出来做调试信号。比如同步完成信号、自协商完成信号、错误计数等,通过ILA或逻辑分析仪观察。不要只在最终结果那里等一个link up信号,那样出了错根本不知道卡在哪一步。
如果用的是自带SGMII硬核的FPGA,链路状态信号通常从IP核引出。调试时先看reset_done、aisg_lock等信号,再看PHY侧的link状态,两边都对了才轮到MAC层的事情。
我遇到过一种很典型的情况:PHY配置没问题,SGMII也显示对齐了,但收发数据始终不对。最后发现是FPGA侧MAC的接口速率配置错了,SGMII协商到100M,但MAC还按1000M模式收发,帧间隙完全不对。所以前面强调的速率适配,在状态机设计里真的要落实到位。
6. 一些体会和调试思路上的建议
SGMII这套链路,如果按从简到繁的步骤排查,通常会节省大量时间。第一步确保MDIO能读到PHY ID,第二步做PHY的环回测试,第三步切换到SGMII IP环回验证FPGA内部PMA/PCS,第四步才去接外部对端。很多工程师一上来就直接连交换机调试,出了问题满屏抓瞎,毫无头绪。
特别是SGMII这种高速串行链路,它的故障现象往往不直接指向原因。比如对端可以ping通但有大量丢包,有可能是PHY速率协商到了100M但系统逻辑跑的是千兆时序;再比如链路灯亮但带宽远低于预期,可能是SGMII内自适应速率与MAC速率不一致。
调试工具方面,除了常见的ILA抓内部信号,我建议把PHY的所有寄存器空间中实现起来。很多情况下错误是PHY上报的,比如接收错误计数器、CRC错误计数器,这些寄存器能帮你非常直观地判断链路质量。
在实际项目中,我逐渐形成了一个习惯:任何高速链路调试,先从能力出发做排除法。MDIO访问不到?先从PHY芯片供电和地址引脚查起。能访问但寄存器值异常?查复位和PDN引脚。环回不通?查SGMII接口模式、AC耦合电容和差分引脚约束。一层一层往下测,思路就会非常清晰。
最后分享一个我自己调整过的温度细节:SGMII链路对温度比较敏感。刚开始长时间跑没问题,高负载跑一小时后开始偶尔出现CRC错误。查了半天发现是PHY芯片散热不良,温度升高后内部PLL抖动变大,SGMII接收端误码骤增。后来在PHY底下加了大面积的地和散热焊盘,问题彻底消失。高速链路的问题,不是只有逻辑和协议,物理层面的事不要忘。