FPGA千兆以太网传输实验从入门到调通:RGMII、ARP/UDP与CRC全解析
发布时间:2026/10/4 19:02:21 锦皓数字建站

做 FPGA 也有些年头了每年都会碰到不少新入坑的同学卡在千兆以太网这个实验上。说句实话千兆以太网传输实验可能是 FPGA 里最能让你“同时怀疑人生又觉得真香”的项目之一——它涉及时钟、状态机、协议栈、约束、抓包任何一个环节出问题都可能导致你 ping 不通、回环没数据、CRC 报错而且排查起来特别考验耐心。我在带新人做黑金 AX7A 系列板卡的千兆以太网实验时总结了不少可复用的经验今天干脆一次性把整个实验从硬件选型到协议设计、RTL 实现、时序约束再到问题排查完整串一遍。这篇内容适合正在学 FPGA 以太网的入门者也适合已经把实验跑通但想搞明白“为什么这样写”的进阶读者。实验主要围绕 RGMII 接口、UDP/IP 协议栈、ARP 请求应答、CRC 校验、DDR3 缓存和 FIFO 设计展开最后我会把测速、ICMP ping、Wireshark 抓包验证的过程记录下来并整理一份高频问题速查表。哪怕你用的不是黑金板卡只要 PHY 芯片是 RTL8211 或者 88E1518这套思路完全可以直接搬过去。1. 千兆以太网实验的硬件准备与接口选型1.1 从 GMII 到 RGMII为什么现在主流方案都选 RGMII以太网的物理接口有很多种MII、RMII、GMII、RGMII、SGMII 等。早期的 GMII 接口是 8 根数据线加控制线在千兆模式下面时钟跑到 125MHz一个时钟周期传一个字节逻辑上确实简单直观但它占用的引脚太多了——数据线 8bit 双向、TX_CTL、RX_CTL、TX_CLK、RX_CLK再加上 MDIO 管理接口对于 FPGA 这种引脚就是资源的器件来说非常浪费。RGMII 最大的改进是数据线减半从 8bit 变成 4bit控制信号也从独立的 TX_EN/TX_ER 合并成一根 TX_CTL。它利用 DDR 双沿采样在时钟上升沿传高 4 位数据下降沿传低 4 位数据。这样千兆模式下时钟仍然是 125MHz但数据吞吐率翻倍等效于 8bit 125MHz。代价就是时序变得敏感对 PCB 走线和 FPGA 内部的输入延时约束要求更高。我用黑金 AX7A035 做实验时板载 PHY 是瑞昱的 RTL8211接口就是标准的 RGMII。如果你用的是米联或者正点原子的板卡常见 PHY 还有美满的 88E1518、裕太微的 YT8511这些芯片的寄存器地址和操作方式大同小异换板子时只要改引脚约束和 PHY 地址就行。下表是 GMII 与 RGMII 的关键信号对比方便你快速建立概念。信号GMIIRGMIITXD8bit 125MHz4bit 125MHz DDRTX_CLK125MHz125MHz上下沿都采样TX_CTL独立 TX_EN / TX_ER合并上升沿发 TX_EN下降沿发 TX_EN XOR TX_ERRXD8bit 125MHz4bit 125MHz DDRRX_CTL独立 RX_DV / RX_ER合并同理引脚数量约 20约 12时序要求较低较高需要约束和可能的 IDELAY 调整第一次做千兆实验的人容易把注意力全放在逻辑代码上却忽略了这样一个事实在 RGMII 模式下FPGA 引脚上的数据是在 125MHz 双沿翻转的用示波器看波形每个 bit 只有 8ns 的窗口在窗口内采样错半个周期都会导致整包数据错位。所以后面第三步我会专门讲约束和采样窗口调整这部分才是调通的关键。1.2 板级链路与 PHY 寄存器自协商以太网物理层不是上电就能用的。PHY 芯片需要与对端网卡完成自协商确定速率千兆/百兆/十兆、双工模式全双工/半双工以及流控方式然后才能建立链路。FPGA 这边的 MAC 逻辑需要通过 MDIO 接口读写 PHY 的寄存器来查看协商结果。MDIO 是两线管理接口MDC 时钟和 MDIO 数据线。读写时序由 FPGA 内部状态机产生每次操作写 16bit 数据。常用寄存器里0x00是 BMCRbit15 是软件复位bit12 是自协商使能bit8 是双工模式bit6 是速率选择0x01是 BMSRbit2 是链路状态。读取0x01时如果 bit2 为 1说明物理链路已经建立。很多同学调试时 ping 不通第一反应是 MAC 逻辑写错了其实大概率是 PHY 没有完成自协商或者 MDIO 根本没读到正确的 ID更常见的是 PHY 芯片 25MHz 参考时钟没有工作。这里有一个经验上电后先读一遍 PHY 的0x02和0x03寄存器也就是 PHY ID 的高 16 位和低 16 位。RTL8211 的 ID 一般是0x001CC916附近88E1518 是0x01410DD0附近。读出来能对上至少能说明 MDIO 时序没问题。如果读出来全是 0xFFFF 或 0x0000优先检查 MDIO 引脚约束、上拉电阻、PHY 地址配置和复位引脚是否被拉高。2. 实验功能定位与协议栈设计思路2.1 这个实验究竟要做什么千兆以太网传输实验并不是让你真的去写一个完整 TCP/IP 协议栈——那工作量太大也没有必要。实验的核心目标是实现一个能处理标准以太网帧的 MAC 层收发通路然后在这个基础上做 UDP 数据包的收发完成 PC 与 FPGA 之间的高速数据传输。我通常把实验拆成三个递进的层次第一层物理链路打通PC 端能看到网口 link 状态为 1000Mbps Full Duplex。第二层MAC 收发通路正确能识别以太网帧中的 MAC 地址、类型字段能正确计算和校验 FCS。第三层完成 ARP 请求应答和 UDP 数据收发PC 能 ping 通 FPGA能单向灌数据FPGA 能回传数据并通过上位机或脚本测出实际吞吐量。第三层做完你就有资格去碰图像传输、ADC 高速采集、多端口 DDR 读写这类进阶项目了。因为高速数据通路的骨架已经立住了。之所以选 UDP 而不是 TCP原因很现实TCP 是面向连接的可靠协议需要维护序列号、确认号、窗口、超时重传、拥塞控制状态机非常复杂在 FPGA 里完整实现一遍至少需要几千行 RTL而且调试难度很大。UDP 是无连接协议头部只有 8 字节校验和甚至可以置零把精力集中在 MAC 层和流量控制上。很多工业场景比如视频传输、数据采集、RoCE 的 UD 模式本质也都是 UDP 风格的无状态传输。所以实验选 UDP 是最合理的路径。2.2 ARP 和 UDP 帧格式拆解要让 PC 能 ping 通 FPGA必须处理 ARP。PC 在发送 ICMP echo request 之前会先查 ARP 缓存表如果不知道目标 IP 对应的 MAC 地址就广播一个 ARP 请求。FPGA 收到请求后如果目标 IP 是自己的 IP就要返回一个 ARP 应答把自己的 MAC 地址告诉 PC。ARP 报文格式里需要注意几个字段硬件类型固定 0x0001协议类型固定 0x0800硬件地址长度 6协议地址长度 4操作码请求为 0x0001、应答为 0x0002。然后是发送端 MAC、发送端 IP、目标 MAC、目标 IP。应答报文里面发送端 MAC 填 FPGA 的 MAC目标 MAC 填 PC 的 MAC。UDP 报文封装在 IP 报文里。IPv4 头部通常是 20 字节版本号 4、首部长度 5单位是 4 字节、总长度、标识、片偏移、TTL、协议UDP 是 17、首部校验和、源 IP、目的 IP。UDP 头部 8 字节源端口、目的端口、UDP 长度、UDP 校验和。帧格式全貌如下以太网帧头: 前导7B SFD 0x55 目的MAC 6B 源MAC 6B 类型 0x0800 IP 头: 20B UDP 头: 8B UDP 载荷: 任意长度 FCS: CRC32 4B注意以太网帧最小长度是 64 字节从目的 MAC 开始算到 FCS 结束如果 IPUDP载荷凑不够 64 字节发送方要在载荷后面补 padding。FPGA 接收时可以不关心 padding但你自己构造发送帧时一定要把长度算对否则 PC 端的网卡驱动可能直接丢弃这个包甚至报 runt frame 错误。2.3 存储器与流量控制千兆以太网的理论线速是 1000Mbps也就是 125MB/s。FPGA 收到数据之后如果只是简单回环那 FIFO 就够了。但如果你后续要做图像采集、ADC 采样、多端口数据聚合DDR3 缓存几乎是绕不开的。热搜词里就有“基于 FPGA 的多端口 DDR 读写程序”讲的就是把多路低速数据汇聚后写入 DDR3然后通过千兆以太网读出。实验阶段我建议先用 FPGA 内部的 Block RAM 或者 FIFO 做数据缓冲把链路调通再去接 DDR3。因为一旦牵涉 DDR3 控制器你的调试范围会瞬间扩大DDR 初始化时序、Bank 管理、刷新、读写仲裁问题很难定位。我见过太多同学 MAC 还没调通就去调 DDR3结果两边都在报错根本分不清问题出在哪一端。流量控制方面UDP 接收端如果处理不过来要么丢包要么用 FIFO 的 almost_full 信号反压发送端。在 RGMII 接口里没有标准的反压信号给 PHY反压一般是通过上层协议实现的。实验里最简单的做法是把 FIFO 深度开大接收模块持续写发送模块持续读先保证不溢出再去考虑更复杂的流控。3. 核心 RTL 模块设计与实现过程3.1 时钟方案与 RGMII 收发时序千兆模式下RGMII 的 TX_CLK 和 RX_CLK 都是 125MHz。但这两个时钟有两个重要区别TX_CLK 由 MAC 侧提供RX_CLK 由 PHY 恢复出来。也就是说RX 时钟域和 TX 时钟域是异步的跨时钟域处理是实验的核心难点。发送方向上MAC 内部逻辑在 125MHz 的可写时钟域下工作数据总线是 8bit。要转成 RGMII 4bit DDR 输出做法是在时钟上升沿输出高 4 位TXD[7:4]下降沿输出低 4 位TXD[3:0]同时控制信号 TX_CTL 在上升沿输出帧使能 TX_EN下降沿输出 TX_EN XOR TX_ER。这里要求数据在上升沿和下降沿都要保持稳定所以必须用 ODDR 原语或者手工构造 DDR 输出寄存器。Xilinx 系列用ODDR原语最方便Altera 系列有ALTDDIO_OUT原语功能类似。接收方向上PHY 输出的 RX_CLK 是和 RXD 同步的理论上你只需要在上升沿采高 4 位、下降沿采低 4 位再把两部分拼成 8bit 数据。但实际中由于 PCB 走线长度差、PHY 芯片内部 skewRXD 相对 RX_CLK 会有几十皮秒到几纳秒的相位偏移导致你采出来的数据在字节边界上出错表现出来的现象就是 Wireshark 里看到帧头不对、CRC 错误、数据全是乱的。这时候就要用 IDELAY 对输入数据做可调的延迟把采样窗口对准数据稳定区域。我在 Xilinx 7 系列上常用的做法是例化IDELAYCTRL和IDELAYE2原语对 RXD[3:0] 和 RX_CTL 各加 1ns 左右的延迟。这个延迟值不是拍脑袋定的要靠实际抓信号看 BER 来调整。黑金 AX7A 的 PCB 布线质量还算不错通常 IDELAY 配到 8~16 个 tap 就能稳定工作每个 tap 约 78ps。但如果你用的是自己画的板子就要仔细看 PHY 数据手册里的 tskew 参数结合布线长度核算。3.2 接收通路字节合成、帧头锁定与 CRC 校验接收方向的核心流程图可以这样理解RGMII_RX 4bit DDR - 8bit 数据 - 检测前导码 0x55 - 帧头锁定 - 收集 MAC 帧 - CRC 校验 - 解析类型字段 - 提取载荷RGMII 接收数据在拼接成 8bit 时先采到的 4bit 是高位还是低位不同 PHY 有细微差别。RTL8211 的数据手册里写得比较清楚RXD[3:0] 在上升沿采到的对应 GMII 的 TXD[7:4]下降沿对应 TXD[3:0]。如果你的代码写反了收到的每字节数据就会变成高 4 位和低 4 位互换表现为源 MAC 地址完全对不上。帧头锁定的逻辑很简单检测到连续 7 个字节的 0x55下一个字节是 0xD5 时再往后的数据就是目的 MAC 地址的第一字节。由于 PHY 在链路空闲时会持续发空闲符号所以帧头锁定必须在数据有效信号有效的窗口内完成不能只靠数据值判断。CRC 校验是新手最容易忽略的坑。以太网帧的 FCS 是 CRC32多项式为0x04C11DB7输入输出都要按位反转初始值全 1结果取反。如果你在网上抄了一个 CRC 模块先确认它的输入输出是否做了比特反转否则算出来一定是错的。我实验里用的 CRC32 核心代码思路如下采用逐字节查表法兼顾速度和代码量// 单字节 CRC32 查表模块示意核心逻辑 // 多项式 0x04C11DB7反射输入输出 function [31:0] crc32_byte; input [31:0] crc; input [7:0] data; integer i; reg [31:0] c; begin c crc ^ data; for (i 0; i 8; i i 1) begin if (c[0]) c (c 1) ^ 32hEDB88320; else c c 1; end crc32_byte c; end endfunction注意这里0xEDB88320是0x04C11DB7的反转多项式对应反射算法。每次收到一个字节就查一次表更新 CRC 寄存器整帧收完后寄存器结果取反就是 FCS。校验时把收到的 FCS 与计算值比较一致说明这帧数据没问题。3.3 发送通路状态机、最小帧长与回环测试发送方向比接收方向稍微简单因为你完全掌握发送时机。MAC 发送状态机一般长这样localparam IDLE 3d0; localparam PREAMBLE 3d1; localparam HEADER 3d2; localparam DATA 3d3; localparam PAD 3d4; localparam FCS 3d5;IDLE 状态等待发送请求PREAMBLE 状态发送前导码 7 个 0x55HEADER 状态发送 1 个 0xD5 和目的 MAC、源 MAC、类型字段DATA 状态发送载荷数据如果数据长度不足 46 字节保证整帧加上头部和 FCS 至少 64 字节进入 PAD 状态补 0最后 FCS 状态发送 CRC32 计算结果。这里有个细节CRC 的计算范围是从目的 MAC 地址开始到载荷或者 padding 结束不包括前导码和 SFD。发送时要在最后一个数据字节发送完的同一个周期把计算好的 CRC 连续输出中间不能有气泡/idle 周期否则对端会认为帧提前结束。这也是新手经常遇到“PC 抓包能看到数据但 FCS 一直报错”的原因之一——CRC 输出时序不对。回环测试是调试的利器。在不接 PC 的情况下让接收通路直接把收到的数据重新打包发给 PC可以快速验证发送通路是否正常。回环有两种MAC 层回环是把收到的帧直接重发上层数据不做任何处理UDP 层回环是解析 UDP 头把源端口和目的端口交换原样把载荷发回去。推荐先做 MAC 层回环再用 Wireshark 看回包的时间戳和负载确认无误后再加 UDP 解析。3.4 ARP 应答与 UDP 收发模块实现ARP 状态机比较简单收到一个 ARP 请求后检查目标 IP 是否匹配匹配则返回应答。由于 ARP 报文只有 28 字节加上以太网头 14 字节和 FCS 4 字节总共 46 字节仍然不足 64 字节所以发送时要补 18 字节的 padding。当年我第一次写 ARP 应答时没注意 padding结果 PC 端能收到 ARP 包但 Linux 的 arp 命令显示 incompleteWindows 则直接丢包。ARP 状态机关键点如下localparam ARP_IDLE 3d0; localparam ARP_CHECK 3d1; localparam ARP_RESPOND 3d2; localparam ARP_DONE 3d3;IDLE 状态收到帧类型 0x0806 后进入 CHECK解析操作码如果是请求且 IP 匹配进入 RESPOND 状态构造应答帧发给发送通路。由于发包模块是共用的ARP 和 UDP 发送之间要做好仲裁避免同时发起发送导致总线冲突。UDP 接收模块的核心任务不是单纯地把载荷端到上层而是要解析出源 MAC、源 IP、源端口、目的端口、数据长度把这些元信息打包成一条“描述符”和载荷一起写入 FIFO。你后边上位机或者嵌入式端做数据处理时主要靠这些元信息来定位数据来自哪个端口。我见过有些同学只把载荷提取出来结果不知道包是谁发的、长度是多少后续根本没法用。IP 首部校验和对 FPGA 来说比较烦因为它要求对 20 字节头部做 16bit 累加和校验。虽然可以逐字节算但接收方向完全可以先不校验 IP 校验和先把数据流程跑通。等你把整体链路调稳定了再回头把校验和模块补上。这种做法在调试阶段很实用不要一上来把所有功能堆满那样出问题你根本不知道从哪查起。4. 从零调通的实操流程、约束与抓包验证4.1 顶层模块例化与引脚分配把 RGMII 收发、ARP、UDP、CRC、FIFO 这些模块组合到一起后顶层模块的信号大概长这样module eth_top ( input rst_n, input eth_rxc, input [3:0] eth_rxd, input eth_rx_ctl, output eth_txc, output [3:0] eth_txd, output eth_tx_ctl, inout mdio, output mdc, input sys_clk_125m );黑金 AX7A 板卡的 RGMII 引脚在原理图里有标注直接把管脚约束写进 XDC 文件即可。需要注意 PHY 的复位引脚很多板子把 PHY 复位接在 FPGA 的一个普通 GPIO 上上电后要通过寄存器拉高并持续至少 10ms否则 PHY 一直处于复位状态MDIO 也读不到 ID。4.2 时序约束的常用写法RGMII 的约束是实验能不能过的重要分水岭。最基本的要把 125MHz 时钟定义好create_clock -name eth_rxc -period 8.000 [get_ports eth_rxc] create_clock -name eth_txc -period 8.000 [get_ports eth_txc]如果 PHY 的 RX_CLK 是送给 FPGA 的需要约束输入延时。RTL8211 在千兆模式的输出 delay 约为 1.5~2ns可以先用典型值set_input_delay -clock eth_rxc -max 2.000 [get_ports {eth_rxd eth_rx_ctl}] set_input_delay -clock eth_rxc -min 0.200 [get_ports {eth_rxd eth_rx_ctl}]对 TX 端的输出约束则是为了保证数据在 TX_CLK 沿附近有足够的建立保持时间。在 RGMII 标准里PHY 内部的延迟机制不同有些 PHY 要求 MAC 发送时使用DDR输出有些要求加delayed clock所以这部分参数要和实际 PHY 匹配。如果你用黑金的板卡工程模板里通常有现成的约束先跑一遍时序报告看有没有时序违例。实现后如果提示clock crossing或者hold违规要先处理约束问题而不是疯狂改代码因为很多 RGMII 采样错位问题本质就是约束不对。4.3 用 Wireshark 与 ILA 逐步验证验证顺序非常重要我推荐的顺序是先看链路再测 ARP再测 UDP最后测吞吐量。第一步上电后看 PC 端网卡状态是否识别到 1000Mbps。识别不到说明 PHY 或 RMII 链路有问题后面所有逻辑都不用看。第二步PC 上ping FPGA_IP同时打开 Wireshark 抓包。看到 ARP 请求和应答成对出现说明 ARP 模块正常ping 通说明 ICMP 回显也正常需要在 FPGA 端实现 ICMP echo 应答或者在 UDP 实验里临时把 ICMP 帧回传。第三步用网络调试助手或者自写脚本给 FPGA 发 UDP 包。在 Wireshark 里看 FPGA 发送回来的包确认源 MAC、源 IP、源端口、载荷内容。如果 ping 不通一定要用 ILA 抓 FPGA 内部信号不要瞎猜。ILA 核里至少抓这几组信号RGMII 接收数据、RX_CTL、CRC 错误标志、ARP 状态机状态、发送通路握手信号。抓一轮就能定位是接收 CRC 错、ARP 状态机没跳还是发送总线仲裁卡死了。4.4 用脚本构造 UDP 报文统计丢包光靠网络调试助手发送数据无法做精确的吞吐量统计。我习惯用 Python 直接构造 UDP 报文发送端和接收端都打时间戳每分钟统计一次丢包率。脚本核心就几十行import socket import time # 目标为 FPGA 的 IP 和端口 dst_ip 192.168.1.10 dst_port 5000 payload_len 1024 total_packets 100000 sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sent 0 start time.time() for i in range(total_packets): data i.to_bytes(4, little) b\x00 * (payload_len - 4) sock.sendto(data, (dst_ip, dst_port)) sent 1 if sent % 1000 0: time.sleep(0.001) sock.close() elapsed time.time() - start print(fsent {sent} packets in {elapsed:.2f}s)FPGA 收到后把载荷原样回传PC 端再用一个 Python socket 接收统计序号连续性和丢包率。实测中在 RGMII 千兆 PHY FIFO 回环的场景下1024 字节载荷的单向流量跑到 100MB/s 以上没问题也就是接近 900Mbps 的有效速率。如果你的测速结果只有几十 Mbps大概率不是 PHY 或 MAC 的问题而是你的上位机发送线程、网卡中断合并或者 PCIe 总线的瓶颈。5. 高频问题速查与避坑记录5.1 链路不通或 link 灯不亮先查 FPGA 是否给 PHY 提供了 25MHz 参考时钟再查 PHY 复位引脚是否被拉高复位时间是否足够然后查 MDIO 能否读到 PHY ID。链路不亮基本就是这三个原因。很多时候不是因为逻辑问题而是因为你忘了给 PHY 发复位信号或者板上 PHY 使用了独立晶振而你把它当成了需要 FPGA 提供时钟的版本。5.2 CRC 错误频繁出现CRC 错误从现象上分两种。一种是所有包都错那基本是 CRC32 算法本身有问题检查多项式、反射、初值、取反。另一种是某些包错、某些包对那大概率是 RGMII 采样时序不稳定检查输入延时约束和 IDELAY 配置或者发送通路里出现了气泡。5.3 回环通但 PC 无法识别 FPGA 发的数据这种情况往往不是数据没发出来而是 PC 端抓包其实能看到包但你的网卡驱动因为“无效校验和”或者“无效长度”把它丢弃了。先用 Wireshark 抓包工具看一下 PC 是否收到了 FPGA 发出的帧如果收到了但标记为 bad检查以太网帧的长度字段和 IP 长度、UDP 长度之间是否一致。很多 UDP 包发不出去就是因为 UDP length 字段没改PC 端接收时会因为长度不匹配直接丢弃。5.4 PHY 配置遗漏与复位时序不同 PHY 芯片上电后默认状态不一样有的默认是百兆有的默认是十兆。如果 PC 端始终协商成千兆或者协商失败尝试通过 MDIO 把 BMCR 寄存器整个重写一遍开启 1000M 全双工并重启自协商。PHY 复位后要等待至少 2ms 再访问 MDIO否则总线可能还没有准备好。我个人踩过的一个坑是MDIO 的读操作时序里读出来的 16bit 数据并不是在“地址阶段结束后立刻出现”而是要在第 32 个 MDC 周期才返回。如果状态机时序写错读到的数据永远是全 1但你误以为是 PHY 没工作浪费了很多时间。查 MDIO 时序最简单的办法是用 ILA 同时抓 MDC、MDIO 输出和读数据输出对照数据手册里时序图逐周期核对。5.5 测速只有几十 Mbps 的性能瓶颈测速达不到千兆我先怀疑上位机再怀疑中间链路最后才怀疑 FPGA。Windows 自带的网络工具在高速 UDP 下表现很差推荐用 Linux 或者 Python 多线程收发。如果 PC 端能跑到 500Mbps但接上 FPGA 之后只有几十 Mbps重点检查 FPGA 接收通路里有没有频繁的 FIFO 满反压或者 ARP/UDP 解析模块的处理周期是否太长。有些模块在状态机里每隔一个周期插入一个 wait 状态虽然逻辑正确但吞吐率直接减半。6. 实验完成后可以继续扩展的方向千兆以太网实验打通之后你能做的东西就非常多了。第一个方向是图像传输把摄像头采集的数据写入 DDR3通过千兆网实时发送到 PC 上位机显示这就是一个完整的采集传输系统也能自然衔接 MIPI 摄像头、HDMI 输入等外设。第二个方向是多端口数据聚合多路 ADC 或传感器数据通过多个 AXIS 接口进入 DDR3 仲裁再由千兆网统一上传匹配你看到的“基于 FPGA 的多端口 DDR 读写程序”这类题目。第三个方向是更底层的网络功能比如把 UDP 换成 RoCEv2 的 UD 模式或者加 TCP 卸载引擎。在此之上工程化的问题也不可忽视。实验在 JTAG 调试时一切正常但断电重上电后程序丢了所以要学会把 bit 流固化到 QSPI Flash 里。这在板卡上就是烧写一个.mcs或.bin文件的事情但很多人第一次不知道还要这个步骤以为 JTAG 下载完就大功告成结果一关机全没了。平时写模块的时候建议把 CRC 校验、状态机握手、FIFO 水位状态这些关键信号引到 ILA 里形成一套标准的调试模板后续做任何高速接口实验都能复用。最后还有一个经验FPGA 复位信号并不特殊没有哪个引脚是“固定的复位脚”都是自己约束到普通 GPIO 的所以时钟复位电路设计务必先想清楚是高有效还是低有效、是异步复位还是同步释放。千兆以太网实验里复位的问题往往隐藏在链路丢失、状态机卡死这些现象背后排查顺序要放在最前面。等你把这一整套流程调熟了再回去看那些更复杂的项目会发现最底层的东西还是这些——时序、状态机、CRC、FIFO、跨时钟域本质都是相通的。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。