资讯详情

FPGA实战:DM9000A以太网UDP通信硬件实现与避坑指南

📅 2026/10/30 5:27:51 | 华诺云谱 👁 阅读
FPGA实战:DM9000A以太网UDP通信硬件实现与避坑指南
简介这份资源面向FPGA与嵌入式网络开发的学习者提供基于DM9000A千兆以太网控制器、在FPGA上实现UDP通信的参考工程可用于视频流或低速数据的网络收发实验帮助理解MAC/PHY控制逻辑、UDP协议栈封装解封装及驱动交互流程。压缩包共961个文件约7.2MB以Quartus工程文件为主包含o、d、v等综合与Verilog源码文件pdom、prefs、xml、qsf、qpf等工程配置以及sof、pof、elf等下载与固件文件另有mif、hex初始化数据和txt、log、rpt等说明与报告目录结构完整便于按模块查阅。已有246人学习下载。读者可从中获得DM9000A初始化、数据收发与错误检测的硬件逻辑参考以及UDP数据包收发函数和网络参数配置思路适合作为FPGA网络通信项目的起步框架并需自行针对丢包、乱序与带宽管理做上层完善。1. 一块网卡芯片和一片 FPGA 之间到底要打通多少层手里有一份 DM9000A 的 FPGA UDP 工程代码第一次打开的时候我盯着顶层文件看了十几分钟——不是看不懂是没想到这么点东西能把以太网跑通。DM9000A 是一颗很常见的 10/100M 以太网控制器接口简单、时序清晰很多做 FPGA 网络实验的板子都会挂一颗。这份代码干的事就是让 FPGA 通过 DM9000A 收发以太网帧在硬件里直接拼出 UDP 报文不经过软核、不跑协议栈。适合谁适合已经能写 Verilog 状态机、想搞清楚「MAC 层到 UDP 到底怎么在硬件里落地」的开发者也适合拿它当网络外设驱动模板做二次开发的人。千兆网这个词常被拿来和它并列但 DM9000A 本身是百兆器件代码里的时序和位宽都是按百兆设计的这一点后面会专门说。2. 工程结构与数据通路从 PHY 到 UDP 的完整链路2.1 目录分层与模块职责这类工程一般不会太大但分层很关键。按常见组织方式源码目录大致是这样dm9000a_udp/ ├── rtl/ │ ├── top.v // 顶层例化各子模块并连板级引脚 │ ├── dm9000a_ctrl.v // DM9000A 读写时序控制 │ ├── eth_rx.v // 接收帧解析剥离前导码和 CRC │ ├── eth_tx.v // 发送帧组装补前导码和 CRC │ ├── udp_rx.v // UDP 头解析提取端口和载荷 │ ├── udp_tx.v // UDP 头组装计算校验和 │ └── crc32.v // 以太网 FCS 计算 ├── sim/ │ └── tb_top.v // 仿真激励 ├── constr/ │ └── pin.xdc // 引脚约束 └── doc/top.v只做连线和时钟复位处理真正的逻辑都在子模块里。dm9000a_ctrl.v是整份代码里最「硬件」的部分因为它要严格按芯片手册的读写时序去拉 CS、IOR、IOW 这些信号eth_rx/eth_tx处理的是标准以太网帧格式udp_rx/udp_tx只关心 IP 头之后的 8 字节 UDP 头。这样分层的好处是换一颗 PHY 芯片只需要重写dm9000a_ctrl.v上层 UDP 逻辑不动。2.2 接收通路帧怎么从网线走进 FPGA接收方向的数据流是PHY 收到帧 → DM9000A 内部缓冲 → FPGA 通过并口把数据读出来 → 剥离前导码和 FCS → 判断是不是 UDP → 提取载荷。关键在并口读时序常见做法是状态机轮询芯片的接收状态寄存器有数据就进读周期。// dm9000a_ctrl.v 片段轮询接收状态并读出一帧 localparam S_IDLE 3d0, S_POLL 3d1, S_READ 3d2, S_DONE 3d3; always (posedge clk) begin case (state) S_IDLE: begin cs_n 1b1; ior_n 1b1; if (rx_start) state S_POLL; end S_POLL: begin // 读 ISR 寄存器bit0 为接收标志 cs_n 1b0; addr 8hFE; ior_n 1b0; if (!ior_n isr_data[0]) state S_READ; end S_READ: begin // 连续读 MRR 寄存器每读一次地址自增 cs_n 1b0; addr 8hF2; ior_n 1b0; if (byte_cnt frame_len) state S_DONE; end S_DONE: begin cs_n 1b1; ior_n 1b1; state S_IDLE; end endcase end这段状态机的逻辑说明S_POLL读中断状态寄存器地址 0xFE判断有没有收到帧S_READ读内存读寄存器MRR地址 0xF2DM9000A 的特性是每读一次这个寄存器内部读指针自动加一所以连续读就能把整帧数据搬出来。参数上要注意frame_len来自芯片的前导长度寄存器不能写死byte_cnt是读出的字节计数读到帧长就停否则会把下一帧的头也读进来。时钟频率决定了读周期能不能满足芯片的最小建立保持时间一般 50MHz 以内是安全的再高就要看手册里的时序参数了。2.3 发送通路UDP 报文怎么在硬件里拼出来发送方向反过来应用层给一个载荷和目的端口udp_tx.v先拼 8 字节 UDP 头源端口、目的端口、长度、校验和再交给eth_tx.v拼 14 字节以太网头目的 MAC、源 MAC、类型 0x0800最后补 4 字节 FCS。UDP 校验和是可选的IPv4 下可以填 0 表示不校验很多简化实现就这么干。// udp_tx.v 片段组装 UDP 头 always (posedge clk) begin if (tx_start) begin udp_hdr[15:0] src_port; // 源端口一般固定 udp_hdr[31:16] dst_port; // 目的端口由上层给 udp_hdr[47:32] payload_len 16d8; // UDP 长度 头 载荷 udp_hdr[63:48] 16h0000; // 校验和填 0不校验 hdr_cnt 0; tx_busy 1b1; end if (tx_busy hdr_cnt 4) begin tx_data udp_hdr[63 - hdr_cnt*16 -: 16]; hdr_cnt hdr_cnt 1; end end逻辑说明udp_hdr是一个 64 位寄存器按大端顺序存放 8 字节头payload_len是上层给的载荷字节数加 8 才是 UDP 长度字段。参数上最容易错的是长度字段——它算的是 UDP 头加载荷不含 IP 头和以太网头写错了对端会直接丢包。校验和填 0 是 IPv4 允许的偷懒做法但如果对端是严格的实现某些嵌入式协议栈可能会被丢弃调试时先确认这一点。2.4 时钟与复位策略这类工程通常只有一个外部晶振DM9000A 的并口时钟和以太网收发时钟是分开的。常见做法是用一个 PLL 出两路一路给并口控制逻辑一路给 MAC 侧。复位要同步释放异步复位同步释放是标配否则状态机可能在上电瞬间跑飞。如果板子上 DM9000A 的复位引脚是 FPGA 控制的记得上电后拉低足够长时间手册一般要求 10ms 以上这一点在仿真里看不出来只有上板才会翻车。3. 跑起来仿真、约束与上板验证的完整步骤3.1 仿真环境搭建与激励编写先别急着上板仿真能省掉一半的调试时间。tb_top.v里要做的事产生时钟、给 DM9000A 的并口行为建模用一个简化的 SRAM 模型模拟芯片内部缓冲、灌一帧预置的 UDP 报文进去看udp_rx能不能正确提取载荷。// tb_top.v 片段模拟 DM9000A 返回一帧数据 task dm9000a_read_model; input [7:0] data; begin (negedge ior_n); dout data; // 芯片在 IOR 下降沿后输出数据 (posedge ior_n); end endtask initial begin // 预置一帧以太网头 IP 头 UDP 头 载荷 HELLO frame[0] 8h00; frame[1] 8h11; // 目的 MAC 前两字节 // ... 省略中间字节 frame[42] 8h48; frame[43] 8h45; // H E frame[44] 8h4C; frame[45] 8h4C; // L L frame[46] 8h4F; // O frame_len 47; rx_start 1b1; #1000; if (payload_out 40h48454C4C4F) $display(PASS); else $display(FAIL: %h, payload_out); end逻辑说明这个 task 模拟芯片在ior_n下降沿后把数据放到总线上上升沿撤掉和真实时序一致。激励里预置的帧要包含完整的以太网头14 字节、IP 头20 字节、UDP 头8 字节载荷从第 43 字节开始。参数上frame_len要算准少一个字节状态机就提前结束。跑仿真时重点看两个地方payload_out是不是和预期一致以及byte_cnt有没有越界。3.2 引脚约束与时钟约束约束文件是上板能不能跑的关键。引脚约束按板子原理图来这里不展开重点说时钟约束。并口控制逻辑的时钟要约束周期以太网侧如果有独立时钟也要单独约束。常见错误是只约束了主时钟忘了给 PLL 输出加create_generated_clock结果时序报告一片绿但实际跑起来偶发丢包。# pin.xdc 片段 create_clock -period 20.000 -name sys_clk [get_ports clk_in] create_generated_clock -name clk_50m -source [get_ports clk_in] \ -divide_by 2 [get_pins pll_inst/CLKOUT0] set_input_delay -clock sys_clk 5.000 [get_ports dm_data[*]] set_output_delay -clock sys_clk 5.000 [get_ports dm_data[*]]说明set_input_delay/set_output_delay的数值要按 DM9000A 手册里的建立保持时间反推5ns 是个保守起点。如果时序报告里并口路径是负 slack先降时钟频率验证功能再回头优化。3.3 上板验证从 ARP 到 UDP 回环上板后第一步不是直接发 UDP而是先确认链路层通不通。用 PC 直连板子看 PC 的网卡灯亮不亮、能不能看到板子发的 ARP。如果代码里没实现 ARPPC 是发不出 UDP 包的——这是新手最常卡住的地方。验证顺序建议先抓包确认板子能发出任意以太网帧哪怕目的 MAC 是广播再确认能收帧最后才调 UDP 端口和载荷。抓包工具看源 MAC 是不是板子的如果全是错帧回头查 FCS 计算和发送时序。4. 避坑与排查五个上板才会暴露的问题4.1 现象仿真全过上板一帧都收不到原因通常是 DM9000A 的复位时序不够。仿真里芯片模型是理想化的上电即就绪真实芯片要求复位拉低至少 10ms且复位释放后还要等内部 PHY 自协商完成可能几百毫秒。解决在top.v里加一个复位计数器复位释放后延时 500ms 再开始轮询期间状态机停在 IDLE。4.2 现象能收帧但载荷全是 0xFF原因多半是读指针没复位。DM9000A 的 MRR 寄存器读指针在读完一帧后要手动写 MRR 地址重新对齐否则下一次读会从上一帧的尾部继续。解决每次S_READ开始前先写一次地址寄存器把读指针拉回帧头别指望芯片自动回绕。4.3 现象UDP 包发出去了对端不回先查 UDP 长度字段。长度字段算错比如把 IP 头也算进去会导致对端协议栈直接丢弃而且抓包工具可能显示「长度异常」但不明显。另一个常见原因是目的端口写反了大小端——UDP 头里端口是大端Verilog 里拼接时高低字节顺序要对。解决抓包看 UDP 头的长度字段和端口字段和预期逐字节比对。4.4 现象偶发丢包跑几分钟就断时序问题。并口读写路径如果 slack 是负的大部分时候能跑温度一变或者负载一高就出错。解决看时序报告的 worst negative slack优先修并口路径实在修不动就降并口时钟百兆以太网对并口带宽要求不高降频不影响吞吐。4.5 现象换一块板子就不工作引脚约束或 PHY 地址不同。DM9000A 的片选和地址线在不同板子上接法可能不一样有的板子把 CMD 引脚接高地址位有的接低。解决对照原理图逐根核对约束文件别直接复用别的工程的 xdc。5. 二次开发把这套代码改成你自己的网络外设这份代码最大的价值不是「能跑 UDP」而是它把「并口时序 帧解析 报文组装」拆成了可替换的模块。二次开发时我一般按这个顺序动刀先换dm9000a_ctrl.v适配新芯片比如换成带 SPI 接口的 PHY再改udp_rx/udp_tx的端口和载荷位宽最后在top.v里把载荷接到你自己的业务逻辑上。具体说一个改造点把固定载荷改成从 Block RAM 读。现在的udp_tx载荷是上层直接给的如果要做「FPGA 采集数据定时上报」就在udp_tx前面加一个 BRAM 读控制器用payload_len控制读多少个字节发完一帧再触发下一次采集。改动量很小但要注意 BRAM 读延迟要和tx_data的节拍对齐否则会发出错位的数据。改造目标改动模块注意点换 PHY 芯片dm9000a_ctrl.v重写读写时序上层接口保持不变改 UDP 端口udp_rx.v / udp_tx.v端口字段大端别写反加业务数据源top.v 新增 BRAM 控制器读延迟与发送节拍对齐提吞吐并口时钟 状态机流水先看时序 slack 再提频验证方法上我习惯每改一个模块就跑一次仿真用同一组预置帧做回归确认payload_out不变。上板前再用抓包工具确认帧格式没变。有个血泪经验改udp_tx的时候顺手把校验和填 0 改成了真算校验和结果对端反而丢了包——因为校验和算法里伪首部源 IP、目的 IP、协议号没拼对。从那以后我每次动校验和相关代码都强制先用固定输入算一遍期望值再上板。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑