2、以太网基础:OSI模型与IEEE 802.3标准,MAC层功能与帧格式
以太网自诞生以来,经过四十余年发展,已成为有线局域网的事实标准。对于FPGA开发者而言,要在可编程逻辑中实现MAC(Media Access Control,介质访问控制)收发链路,首先必须透彻理解两个核心问题:以太网在OSI参考模型中处于什么位置?一个标准的以太网帧在MAC层究竟由哪些字段构成、每个字段的字节序和时序如何?本章将从OSI模型与IEEE 802.3标准的映射关系出发,深入剖析MAC层的功能边界,并以字节级精度拆解以太网帧格式,为后续FPGA中的RTL设计打下坚实的协议基础。
2.1 OSI模型与IEEE 802.3标准的映射关系
核心原理:分层模型与协议栈定位
OSI(Open Systems Interconnection)参考模型将网络通信划分为七层,每一层只向上一层提供服务,并只依赖下一层提供的服务。在以太网中,IEEE 802.3标准实际上只定义了物理层(L1)和数据链路层(L2)中的MAC子层。数据链路层被进一步拆分为两个子层:逻辑链路控制子层(LLC,Logical Link Control)和介质访问控制子层(MAC)。LLC子层负责复用/解复用上层协议(如IP、ARP),而MAC子层则负责帧的封装/解封装、介质访问控制(CSMA/CD)、地址寻址和差错检测。
对于FPGA开发者而言,MAC层是必须用硬件逻辑实现的核心模块。MAC层向上通过LLC或直接与IP层交互,向下通过MII(Media Independent Interface)、GMII、RGMII等接口与PHY芯片连接。PHY芯片负责物理信号的编码、调制、串并转换等模拟域工作,而FPGA中的MAC逻辑则处理纯数字域的帧收发。
判断方法:区分帧类型与协议层次
在实际开发中,判断一个数据帧属于哪种类型(Ethernet II 或 IEEE 802.3)是MAC层设计的基本功。判断依据是长度/类型字段的数值:
- Ethernet II帧(DIX帧):长度/类型字段值大于等于0x0600(1536),表示上层协议类型。例如0x0800表示IPv4,0x0806表示ARP,0x86DD表示IPv6。
- IEEE 802.3帧:长度/类型字段值小于等于0x05DC(1500),表示后续数据字段的实际长度。此时需要LLC头(DSAP、SSAP、Control)来进一步区分上层协议。
FPGA实现时,通常只需支持Ethernet II帧格式,因为现代以太网设备几乎全部使用该格式。但MAC设计仍需保留对长度字段的解析能力,以便兼容旧设备或特殊应用场景。
案例拆解:一个ARP请求帧的层次解析
假设FPGA设备收到一个ARP请求帧,其十六进制前段为:FF FF FF FF FF FF 00 11 22 33 44 55 08 06 00 01 08 00 06 04 00 01 ...。逐字段解析:
| 字段 | 值 | 含义 |
|---|---|---|
| 目的MAC | FF:FF:FF:FF:FF:FF | 广播地址 |
| 源MAC | 00:11:22:33:44:55 | 发送方MAC |
| 长度/类型 | 0x0806 | ARP协议(Ethernet II) |
| ARP头 | 0x0001 0x0800 0x06 0x04 0x0001 | 以太网+IPv4+MAC+IP+请求 |
FPGA在接收该帧时,MAC层只需识别目的MAC是否为广播地址或本机地址,然后将长度/类型字段值0x0806连同数据部分一起上交给上层协议处理模块。MAC层本身不解析ARP内容,这体现了分层设计的职责单一原则。
2.2 MAC层功能与帧格式详解
核心原理:MAC层的六大核心功能
MAC子层在IEEE 802.3标准中承担以下功能,这些功能在FPGA中对应具体的硬件逻辑模块:
- 帧封装与解封装:发送时添加前导码、SFD、目的/源MAC、长度/类型、FCS;接收时去除这些字段并校验FCS。
- 介质访问控制:半双工模式下实现CSMA/CD(载波侦听多路访问/冲突检测),全双工模式下则无需此功能。
- 地址管理:维护本机MAC地址,接收时进行地址过滤,只接收目的地址为本机、广播地址或组播地址的帧。
- 差错检测:发送时计算CRC32并附加为FCS字段;接收时重新计算CRC并与接收到的FCS比较,不一致则丢弃该帧。
- 帧间隔管理:发送完一帧后必须等待至少96 bit-time的帧间隙(IFG),以确保接收方有足够时间处理。
- 流量控制:全双工模式下支持Pause帧(802.3x),当接收缓冲区满时向对端发送暂停请求。
帧格式逐字段拆解
一个完整的以太网帧(不含前导码和SFD)由以下字段组成,FPGA设计时必须精确理解每个字段的字节序和时序要求:
| 字段 | 长度 | 值/范围 | FPGA处理要点 |
|---|---|---|---|
| 前导码(Preamble) | 7字节 | 0x55重复7次 | 用于接收时钟同步,FPGA接收时通常由PHY处理,MAC可忽略 |
| SFD(帧起始定界符) | 1字节 | 0xD5 | 标志帧的开始,FPGA检测到SFD后开始接收有效数据 |
| 目的MAC地址 | 6字节 | 单播/广播/组播 | 接收时进行地址匹配,不匹配则丢弃 |
| 源MAC地址 | 6字节 | 本机MAC | 发送时填入本机地址,接收时可用于学习 |
| 长度/类型 | 2字节 | ≥0x0600为类型,≤0x05DC为长度 | 决定帧类型,FPGA需寄存并输出 |
| 数据(Payload) | 46~1500字节 | 不足46字节需填充 | 最小帧长64字节,数据不足时填充0 |
| FCS(帧校验序列) | 4字节 | CRC32校验值 | 发送时计算,接收时校验,错误则丢弃 |
案例拆解:最小帧与最大帧的构造
假设FPGA需要发送一个仅包含6字节数据的UDP报文(不含IP/UDP头),MAC层构造过程如下:
- 数据字段实际长度 = 6字节,但最小帧要求数据字段至少46字节,因此需填充40字节的0x00。
- 帧总长度 = 6(目的MAC)+ 6(源MAC)+ 2(长度/类型)+ 46(填充后数据)+ 4(FCS)= 64字节,恰好满足最小帧长要求。
- 长度/类型字段填入0x0800(IPv4类型),而不是实际数据长度6,因为这是Ethernet II帧。
- FCS计算覆盖从目的MAC到数据字段末尾的所有字节,使用标准CRC32多项式0x04C11DB7。
在FPGA发送逻辑中,需要设计一个状态机:空闲→发送前导码→发送SFD→发送目的MAC→发送源MAC→发送长度/类型→发送数据(含填充)→计算并发送FCS→等待IFG→回到空闲。每个状态对应一个时钟周期或一组时钟周期,数据宽度通常为8位(GMII)或4位(MII)。
2.3 前导码、SFD与字节序的硬件实现要点
核心原理:为什么前导码是0x55而不是0xAA
前导码的7字节0x55(二进制10101010)和SFD的0xD5(二进制11010101)组合在一起,形成连续的曼彻斯特编码跳变,用于接收端恢复时钟并实现字节对齐。在100Mbps及以上速率中,PHY芯片负责前导码的生成和去除,FPGA通过MII/GMII接口接收到的数据通常已经去除了前导码和SFD。但在10Mbps速率下,某些PHY配置可能将前导码透传给MAC,此时FPGA需要自行检测SFD。
字节序方面,以太网采用大端序(Big-Endian)传输,即最高有效字节先发送。MAC地址的传输顺序是从最高字节到最低字节,例如MAC地址00:11:22:33:44:55,先发送0x00,最后发送0x55。FCS字段的传输顺序则是CRC32结果的最高字节先发送。
判断方法:如何确定PHY是否已去除前导码
在FPGA调试中,可以通过以下方法判断PHY的行为:
- 查看PHY芯片的数据手册,确认其MII/GMII接口是否包含前导码。大多数现代PHY(如RTL8211、88E1512)默认去除前导码和SFD。
- 使用逻辑分析仪抓取GMII接口的TXD信号,观察帧起始时是否有连续的0x55。
- 检查PHY的寄存器配置,部分PHY提供"Transmit Preamble"或"Receive Preamble"使能位。
如果PHY透传前导码,FPGA接收逻辑必须包含SFD检测状态机:持续监测数据是否为0x55,当检测到0xD5时,下一字节即为目的MAC的第一个字节。
案例拆解:GMII接口上的帧时序
以GMII接口为例(8位数据,125MHz时钟),一个完整帧的发送时序如下:
时钟周期: T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15
TXD[7:0]: 55 55 55 55 55 55 55 D5 DA DA DA DA DA DA SA SA
TX_EN: 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
其中T0周期TX_EN为低,表示帧间隙;T1~T7发送前导码0x55;T8发送SFD 0xD5;T9~T14发送目的MAC(6字节);T15开始发送源MAC。FPGA发送逻辑需要精确控制TX_EN信号,确保在发送前导码的第一个字节时拉高,在FCS最后一个字节发送完成后拉低。
2.4 常见误区与设计复盘
误区一:混淆最小帧长与数据字段长度
很多初学者将"最小帧长64字节"误解为"数据字段至少64字节"。实际上,64字节包含目的MAC(6)+源MAC(6)+长度/类型(2)+数据(46)+FCS(4)。当上层数据不足46字节时,MAC层必须填充到46字节。FPGA实现时,填充逻辑应在发送数据之前完成,且填充字节不计入上层协议的长度字段。
误区二:忽略FCS的计算范围
CRC32的计算范围是从目的MAC地址的第一个字节开始,到数据字段的最后一个字节(含填充字节)结束,不包括前导码、SFD和FCS本身。FPGA实现时,常见错误是将前导码也纳入CRC计算,导致发送端和接收端校验不一致。正确做法是:发送时在发送完数据字段后,立即输出CRC计算结果;接收时在接收完数据字段后,将本地计算的CRC与接收到的FCS逐字节比较。
误区三:地址过滤逻辑过于简单
有些设计只实现了单播地址匹配,忽略了广播地址(FF:FF:FF:FF:FF:FF)和组播地址(目的MAC最高字节最低位为1)。在FPGA接收逻辑中,地址过滤应支持三种模式:精确匹配、广播匹配、组播匹配(可选)。此外,还应支持混杂模式(接收所有帧),这在调试和网络分析中非常有用。
复盘总结:MAC层设计的核心清单
| 检查项 | 设计要点 | 验证方法 |
|---|---|---|
| 帧间隔IFG | 发送完成后至少等待96 bit-time | 用示波器测量两帧之间的间隔 |
| FCS生成 | CRC32多项式0x04C11DB7,初始值0xFFFFFFFF,结果取反 | 用Wireshark抓包验证 |
| 填充逻辑 | 数据不足46字节时填充0x00 | 构造短帧测试 |
| 地址过滤 | 支持单播、广播、组播、混杂模式 | 发送不同目的地址的帧验证 |
| 错误处理 | CRC错误、长度错误、溢出错误分别标记 | 注入错误帧验证 |
以太网MAC层虽然协议简单,但FPGA实现中涉及大量时序细节。建议在RTL设计前,先用Python或C语言编写一个参考模型,逐字节模拟帧的封装和解析过程,生成测试向量。这样在FPGA验证阶段,可以直接用参考模型产生的标准帧作为激励,对比DUT输出,快速定位逻辑错误。