基于FPGA的EMAC模块和FIFO模块

2022-07-28,,

    IP核是指在电子设计中预先设计的用于搭建系统芯片的可重用构件,可以分为软核、固核和硬核三种形式。软核通常以可综合的RTL代码的形式给出,不依赖于特定的工艺,具有最好的灵活性。硬IP核是针对某种特定工艺生成的物理版图,具有最优化且可预知的面积、速度和功耗,但其可移植性和灵活性较差。固核是前两者在灵活性和性能之间的折衷。

以太网技术主要研究内容包括物理层和MAC子层。MAC子层控制器既可以集成于网络终端设备中实现网络接入,同时又是开发网桥、交换机等网络互连设备,延伸以太网传输范围的基础,在以太网接入中起到很关键的作用。另外,对于不同的以太网传输媒介,MAC子层不需要改动或者只需很小的改动。因此,开发以太网MAC控制器的IP核具有重要的意义。

以太网最重要的技术集中于物理层和MAC层。对于不同的传输介质,物理层屏蔽掉了信道的不同对MAC的影响,因此MAC层相对的改动要少的多,这使得设计MAC控制器IP核具有很强的实际意义。这里将使用xilinx公司的嵌入式三态以太网IP核来实现MAC核。

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

关于MAC核,更多的资料请查看如下网址:

http://xilinx.eetrend.com/article/993

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

 

 

 

 

 

 

 

1.2 系统框图和框图说明

由于系统AFDX接口采用的MAC方案物理结构和EMAC核的结构相似,本项目采用的是EMAC核的IP核进行设计。

由于该核具有大量的接口,所以系统在生成IP核后会根据用户的IP核的设置,自动生成其调用模块。这里根据系统的结构做简单的修正便可使用。

这里这个MAC核的基本物理结构如下所示:

 

 

 

    这里MAC核通过MII接口和PHY芯片进行外部通信,通过发送FIFO和接收FIFO进行FPGA内部数据的通信。

IP核的设置如下所示:

EMAC核具体的配置如下所示:

EMAC核的基本结构如下所示:

其设置如下所示:

这个界面就是设置两个MAC核,然后根据您提供的方案,选择DCR为host Type。

这里选择物理层接口为MII接口。选择这个接口以后,Speed选项将自动变为10/100Mbps。

后面几个选项保存默认就可。

由于MAC具有相当多的接口,非常的复杂。论文中就不需要多做介绍了。

 

两个MAC核的仿真结果如下所示:

MAC0核:

MAC1核:

这两个仿真图就是两个核的对外MII接口的仿真图。具体的时序含义可以产看PHY芯片的datasheet,里面有时序图。

    这里两个MAC核的仿真意义是相同的,所以这里就对第一个MAC核的仿真波形进行说明,当MAC核正常工作的时候,在数据发送的时候,这里mii_tx_en_0为帧使能信号,当有数据发送的时候,该信号为1,当发送为0的时候,该信号使能为0,mii_txd_0为发送的数据,接收信号,当有接收信号进入MAC核的时候,mii_rx_dv_0为高电平,对应的数据为接收的数据,当接收的数据发生错误的时候,mii_rx_er_0会出现高电平的,如果接收到的数据没有发生错误,那么该信号为低电平。

二、AFDX发送接收模块

发送

2.1模块说明

发送数据的基本过程如下:

要发送数据时,将待发送数据传输到MAC的发送缓存中。发送缓存接收到的数据达到设定值时,数据发送模块开始进行帧间隔计时。

发送帧的前导码;

发送帧起始定界符;

帧长计数和CRC校验和计算,同时将数据按半位元组(4bits)发送给MII接口;

在发送过程中,如果MAC检测到该帧的长度小于最小帧长(64字节),则进行数据填充达到64字节为止。

AFDX帧结构详细解析

其含义为:

>前导码:7个字节长度的“10101010”比特信号;

>帧起始定界符(SFD):为1个字节长度的“10101011”;

>目的地址(DA):目的地址的长度为6个字节(48个比特:16bit的VL)。格式如图2所示;

>源地址(SA):为6个字节,只能为单播地址。其格式如下所示:

>类型:固定值H0800;

> IP头:和802.3相同;

> UDP头:和802.3相同;

> AFDX数据域:数据长度为17~1471字节。为了满足最小帧长度的要求(≧64字节),需要对短信息帧进行填充若干字节使之达到最小帧长。

  (这里设计时将考虑进行填充帧的方法达到小帧的最低要求64*8bit);

>序列号:每条VL在发送每一个数据帧的时要加入序列号,用于区分冗余帧,序列号范围为0~255。对于相同的VL,每发送一个数据帧该序列号自动加1,序列号增加到255时下一个数据帧的序列号循环为1。

>帧校验序列(FCS): CRC-32校验码。

注意:,其具体的结构为:

即在第三位到第八位为时间信息,这个时间信息为定时计数器输出的时间信息。

发送对数据进行封装并进行相应的控制。

根据上面的设计说明,整个AFDX帧的发送模块可以做如下的状态机设计:

     整个发送数据的帧结构含义为:

·一:发送7边“10101010”进入第二状态;

·二:发送一个“10101011”进入第三状态;

·三:发送一个 XXXX_XX11_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX  +  XXXX_XXXX_XXXX_XXXX(VL)

·四:发送一个0000_0010_0000_0000_0000_0000_0000_0000 + “0000 + 网络号码(4位)” + “发送数据帧的端系统的编号(8位)” + “冗余网络(3位)” + “00000”

·五:发送:0000_1000_0000_0000

·六:发送:

版本(4”+“长度4”+“优先级服务类型8”+

总长度16”+“标示符16”+“标示符3”+

分段漂移13”+“生存时间8”+“生存时间8”+

头部校验16”+“IP地址32”+“IP地址32

·七:源端口(16位) +目的端口(16位)”+长度(16位)”+求校验和(16位)“

·八:发送具体的数据,其中数据的前面的部分为时间插入,之后为数据

·九:检测VL地址,如果是同一个VL地址,那么计数器就会加1,如果是不同的VL地址,计数器变为0.

·十: CRC校验码,4输入的并行的CRC校验过程,如果不通过校验,则全为0,如果需要进行校验,则按以下的过程进行计算。

 

i_clk

系统时钟

i_rst

系统复位

i_start_or_not

发送使能信号

i_data

发送的数据,字节为单位

i_data_number

数据个数

i_aim_address

目的地址

i_orig_address

源地址

i_head_ip

IP头

i_head_udp

UDP头

o_afdx_frame

表示当前帧

o_afdx_frame2

表示当前帧

o_AFDX_data

根据输出格式,MII接口接收的是4bits的数据格式

o_AFDX_data2

根据输出格式,MII接口接收的是4bits的数据格式

current_state

状态转移信号

 

    AFDX数据的传输是全双工的,其发送数据的工作过程如下:

主机要发送数据时,首先将待发送的数据传输到MAC的发送缓存中。发送缓存接收到的数据达到设定值时,开始长度检测,检测完成后,数据发送模块开始进行帧间隔计时。根据帧计数器的值开始发送帧的前导码、发送帧起始定界符、将数据4bits发送给MII接口,从而最终由物理层将数据发送到网络介质上。

该模块的仿真结果如下所示:

    这里这里仿真波形的信号为i_start_or_not为高电平的时候,AFDX发送工作开始工作,i_data为需要发送的数据,i_data_number为需要发送数据的个数,i_aim_address为发送信号的目标地址,i_orig_address为发送的源地址,i_head_ip为发送信号的IP头,i_head_udp为发送信号。当发送开始的时候,系统首先检测需要发送的数据的长度,如果数据长度大于64,则开始发送,如果发送数据长度小于64,那么进行填充,补充到64为止。通过AFDX发送模块,得到发送的帧数据o_AFDX_data以及帧信号对应的帧使能信号o_afdx_frame。

//以下的内容可以不写。

发送模块的主要功能就是将数据封装,其基本流程如下所示:

Data加入前导码;

Data加入起始分界符;

Data加入目标地址;

Data加入源地址;

Data加入IP头;

Data加入UDP头;

通过上述的过程,可以讲数据进行封装。

 

2.5 程序流程图(状态机)

    发送状态机

以上就是AFDX发送部分的状态机,发送数据主要包括等待,数据长度检测,插入前导码和帧起始界定符,数据发送以及CRC校验结果状态。系统在工作的时候,一直处于wait状态,当需要发送数据的时候,状态机将进入下一个状态从而开始数据的发送。

   

接收

2.1模块说明

接收为发送的反过程,首先对接收都得4位信息进行帧检测,当检测到前导码和起始鉴定符的时候,认为一帧数据开始接收到了,然后开始对数据帧进行解析,得到帧数据中的各类数据信息。其理论和发送正好相反,这里就不多介绍了。

当MAC接收到数据有效后,从MII接口读入数据,然后开始检测前导码和帧起始定界符,当检测到有效的帧起始定界符,就认为是有效帧的开始,此时开始对帧长进行计数。数据接收模块在接收的过程中剥离了接收到的帧的前导域、SFD域、CRC域和PAD域。

AFDX接收过程,数据通过PHY芯片解码,进入到MAC核,然后进入接收FIFO。

2.2 仿真和仿真说明

其仿真结果如下所示:

这里当外部数据通过PHY解码后进入MAC核,接收端开始进入接收状态机,首先检测前导码和帧起始界定符。如果检测成果,那么系统进入下一个状态。从上图的仿真结果可以看到,当检测完前导码和帧起始界定符的时候,current_state将进入下一个状态。然后开始接收数据,o_data就为接收到的数据。

2.3 程序流程图(状态机)

    接收状态机

AFDX接收状态机处于初始状态,则一直在wait状态,当外部PHY有数据送入到MAC核中,那么当MAC核接收到数据和帧使能信号的时候,那么开始进入前导码状态搜索过程,然后进入帧起始界定符的状态,当成功检测之后,开始进行数据的接收,在接收过程中,如果接收到的帧长度过小或者过大,那么说明该帧无效,丢弃,当长度合适,那么开始接收数据。

 

三、MII模块

3.1模块说明

主机对物理层的管理是通过向MAC核的寄存器写指令,然后再通过MAC接口管理模块对外部物理层对应的寄存器进行配置来实现的。MII接口管理模块提供一个连接到外部PHY控制器的接口。

MII总线在IEEE802.3中规定的MII总线是一种用于将不同类型的PHY与相同网络控制器(MAC)相连接的通用总线。网络控制器可以用同样的硬件接口与任何PHY进行连接。

MII数据接口总共需要16个信号,包括TX_ER,TXD,TX_EN,TX_CLK,COL,RXD,RX_EX,RX_CLK,CRS,RX_DV等。MII以4位半字节方式传送数据双向传输,时钟速率25MHz。其工作速率可达100Mb/s。MII管理接口是个双信号接口,一个是时钟信号,另一个是数据信号。

3.2 系统框图和框图说明

 

 

MII模块的主要功能就是将MAC核的数据和外部PHY进行数据的通信,将外部数据送入MAC核,或将MAC核的数据发送至PHY。

3.3 模块管脚说明

MAC模块对外部物理层对应的寄存器进行读/写配置来实现的。MII接口管理模块提供一个连接到外部PHY控制器的接口,用来配置PHY的寄存器并获得其状态信息。其接口如下所示:

 

这里主要是通过FPGA控制PHY,进行MAC和PHY信号的数据通信,PHY主要有16个脚。

其中数据的发送和接收为TXD[3:0],RXD[3:0],对应的时钟为TX_CLK,RX_CLK,控制MII模块的时钟为25Mhz

这里,我们设计的MII接口如下所示:

 

注意,这里的各个接口和你实际的接口对应如下所示:

你的接口

程序中对应的接口

TX_EN

MII_TX_EN

TX_ER

MII_TX_ER

TXD[3:0]

MII_TXD

TX_CLK

TX_CLK

RX_CLK

RX_CLK

RX_DV

MII_RX_DV

RX_ER

MII_RX_ER

RXD[3:0]

MII_RXD

CRS

MII_CRS

COL

MII_COL

 所以代码设计的脚和你的PHY芯片已经修改为对应的了。

     其几个重要接口脚的含义如下所示:

程序中对应的接口

 

MII_TX_EN

帧使能信号

MII_TX_ER

发送出错误使能信号

MII_TXD

发送的数据

TX_CLK

接收时钟

RX_CLK

发送时钟

MII_RX_DV

帧使能信号

MII_RX_ER

接收到错误使能信号

MII_RXD

接收的数据

MII_CRS

载波侦听

MII_COL

冲突

3.4 仿真和仿真说明

Mii的标准时序如下所示:

MII接收时序:

 

    接收数据,当信号RX_DV为1的时候,MII开始接收数据,每个时钟接收一个数据,如果没有接收到错误的数据,那么RX_ER始终为低电平。

MII发送时序:

 

    发送数据,当信号TX_EN为1的时候,MII开始发送数据,每个时钟发送一个数据i,此时CRS为高电平,并相对于TX_EN信号延迟一个时钟周期。COL为低电平信号。

 

    该模块的仿真如下所示:

 

这个模块就是通过MII口将MAC核和PHY芯片进行连接。实现FPGA和PHY的数据之间的传输。仿真图中红色仿真波形为MII接口和PHY芯片接口部分,而绿色的仿真波形对应的接口是和FPGA内部MAC核的接口。

四、CRC校验模块

4.1模块说明

CRC的全称为Cyclic Redundancy Check,中文名称为循环冗余校验。它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制。实际上,除数据通信外,CRC在其它很多领域也是大有用武之地的。例如我们读软盘上的文件,以及解压一个ZIP文件时,偶尔会碰到“Bad CRC”错误,由此它在数据存储方面的应用可略见一斑。

差错控制理论是在代数理论基础上建立起来的。这里我们着眼于介绍CRC的算法与实现,对原理只能捎带说明一下。若需要进一步了解线性码、分组码、循环码、纠错编码等方面的原理,可以阅读有关资料。

利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,然后发送出去。在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则,在差错控制理论中称为“生成多项式”。

4.2 系统框图和框图说明

32位的CRC校验过程如下所示:

   对应的CRC校验代码如下所示:

assign next_crc[0] = crc_reg[30] ^ d[1] ^ crc_reg[24] ^ d[7];

assign next_crc[1] = d[6] ^ d[7] ^ d[0] ^ crc_reg[30] ^ crc_reg[31] ^ d[1] ^ crc_reg[24] ^ crc_reg[25];

assign next_crc[2] = crc_reg[26] ^ d[5] ^ d[6] ^ d[7] ^ crc_reg[30] ^ d[0] ^ d[1] ^ crc_reg[31] ^ crc_reg[24] ^ crc_reg[25];

assign next_crc[3] = d[4] ^ crc_reg[26] ^ d[5] ^ crc_reg[27] ^ d[6] ^ d[0] ^ crc_reg[31] ^ crc_reg[25];

assign next_crc[4] = d[4] ^ crc_reg[26] ^ d[5] ^ crc_reg[27] ^ crc_reg[28] ^ d[7] ^ crc_reg[30] ^ d[1] ^ crc_reg[24] ^ d[3];

assign next_crc[5] = d[4] ^ crc_reg[27] ^ d[6] ^ crc_reg[28] ^ d[7] ^ crc_reg[29] ^ crc_reg[30] ^ d[0] ^ d[1] ^ crc_reg[31] ^ d[2] ^ crc_reg[24] ^ d[3] ^ crc_reg[25];

assign next_crc[6] = crc_reg[26] ^ d[5] ^ d[6] ^ crc_reg[28] ^ crc_reg[29] ^ d[0] ^ crc_reg[30] ^ crc_reg[31] ^ d[1] ^ d[2] ^ d[3] ^ crc_reg[25];

assign next_crc[7] = d[4] ^ crc_reg[26] ^ d[5] ^ crc_reg[27] ^ d[7] ^ crc_reg[29] ^ d[0] ^ crc_reg[31] ^ d[2] ^ crc_reg[24];

assign next_crc[8] = d[4] ^ crc_reg[27] ^ d[6] ^ crc_reg[28] ^ d[7] ^ crc_reg[24] ^ crc_reg[0] ^ d[3] ^ crc_reg[25];

assign next_crc[9] = crc_reg[26] ^ d[5] ^ d[6] ^ crc_reg[28] ^ crc_reg[29] ^ d[2] ^ d[3] ^ crc_reg[25] ^ crc_reg[1];

assign next_crc[10] = d[4] ^ crc_reg[26] ^ crc_reg[2] ^ d[5] ^ crc_reg[27] ^ d[7] ^ crc_reg[29] ^ d[2] ^ crc_reg[24];

assign next_crc[11] = d[4] ^ crc_reg[27] ^ d[6] ^ crc_reg[3] ^ crc_reg[28] ^ d[7] ^ crc_reg[24] ^ d[3] ^ crc_reg[25];

assign next_crc[12] = crc_reg[26] ^ d[5] ^ d[6] ^ crc_reg[28] ^ d[7] ^ crc_reg[4] ^ crc_reg[29] ^ crc_reg[30] ^ d[1] ^ d[2] ^ crc_reg[24] ^ d[3] ^ crc_reg[25];

assign next_crc[13] = d[4] ^ crc_reg[26] ^ d[5] ^ crc_reg[27] ^ d[6] ^ crc_reg[29] ^ d[0] ^ crc_reg[30] ^ crc_reg[5] ^ crc_reg[31] ^ d[1] ^ d[2] ^ crc_reg[25];

assign next_crc[14] = d[4] ^ crc_reg[26] ^ d[5] ^ crc_reg[27] ^ crc_reg[28] ^ crc_reg[30] ^ d[0] ^ d[1] ^ crc_reg[31] ^ crc_reg[6] ^ d[3];

assign next_crc[15] = d[4] ^ crc_reg[27] ^ crc_reg[28] ^ crc_reg[29] ^ d[0] ^ crc_reg[31] ^ d[2] ^ crc_reg[7] ^ d[3];

assign next_crc[16] = crc_reg[28] ^ d[7] ^ crc_reg[29] ^ d[2] ^ crc_reg[24] ^ d[3] ^ crc_reg[8];

assign next_crc[17] = crc_reg[9] ^ d[6] ^ crc_reg[29] ^ crc_reg[30] ^ d[1] ^ d[2] ^ crc_reg[25];

assign next_crc[18] = crc_reg[26] ^ d[5] ^ crc_reg[10] ^ crc_reg[30] ^ d[0] ^ d[1] ^ crc_reg[31];

assign next_crc[19] = d[4] ^ crc_reg[27] ^ crc_reg[11] ^ d[0] ^ crc_reg[31];

assign next_crc[20] = crc_reg[28] ^ crc_reg[12] ^ d[3];

assign next_crc[21] = crc_reg[29] ^ crc_reg[13] ^ d[2];

assign next_crc[22] = d[7] ^ crc_reg[14] ^ crc_reg[24];

assign next_crc[23] = d[6] ^ d[7] ^ crc_reg[30] ^ d[1] ^ crc_reg[15] ^ crc_reg[24] ^ crc_reg[25];

assign next_crc[24] = crc_reg[26] ^ d[5] ^ d[6] ^ d[0] ^ crc_reg[31] ^ crc_reg[16] ^ crc_reg[25];

assign next_crc[25] = d[4] ^ crc_reg[17] ^ crc_reg[26] ^ d[5] ^ crc_reg[27];

assign next_crc[26] = d[4] ^ crc_reg[18] ^ crc_reg[27] ^ crc_reg[28] ^ d[7] ^ crc_reg[30] ^ d[1] ^ crc_reg[24] ^ d[3];

assign next_crc[27] = d[6] ^ crc_reg[19] ^ crc_reg[28] ^ crc_reg[29] ^ d[0] ^ crc_reg[31] ^ d[2] ^ d[3] ^ crc_reg[25];

assign next_crc[28] = crc_reg[26] ^ d[5] ^ crc_reg[20] ^ crc_reg[29] ^ crc_reg[30] ^ d[1] ^ d[2];

assign next_crc[29] = d[4] ^ crc_reg[27] ^ crc_reg[21] ^ crc_reg[30] ^ d[0] ^ d[1] ^ crc_reg[31];

assign next_crc[30] = crc_reg[28] ^ d[0] ^ crc_reg[22] ^ crc_reg[31] ^ d[3];

assign next_crc[31] = crc_reg[29] ^ crc_reg[23] ^ d[2];

    管脚如下所示:

crc_reg

输出校验信息

crc

输出校验码

d

输入数据信息

calc

CRC使能信号

init

参数初始化使能信号

d_valid

数据输出使能信号

clk

时钟

reset

系统复位信号

4.4 仿真和仿真说明

    其仿真结果如下所示:

注意,这里直接根据理论知识验算一下结果就行了。具体就不用说明

这个模块的主要结构为:

 

按照系统的基本结构,偏向软件的方案,这个模块的功能在MB中使用软件进行设计,偏向硬件的方案,这个模块的功能主要在FPGA中进行设计。

经过研究,这个功能模块在FPGA中使用verilog进行设计更加方便。此模块的主要针对接收数据包时进行使用,而在数据发送时,主要屏蔽该模块就行了。

给每个VL分配固定带宽,相当于把端与端之间的一次数据传输限制在某个固定的时间段(即BAG),即在这个时间段之内只允许发起一次数据传输;即使有多个帧要发送(例如数据包过大,需要分多个帧发送),也必须分配到各自的时间段进行发送。在整个网络设计中,必须把一个时间段合理地分配给不同的终端系统使用,保证任意时间段使用的带宽都是可以被确定的。

 

 

从上面的图可以看出,两个数据帧之间的长度大于BAG,那么正常接收,当两个数据帧之间的长度小于一个BAG,那么将后一个数据帧移动到第二个BAG的起始位置。

 

 

5.2 系统框图和框图说明

   这里不涉及到具体的框图,略。

5.3 模块管脚说明

i_clk

输入时钟

i_rst

系统复位

i_frame_enable

输入帧使能信号

i_afdx_data

输入AFDX数据

rd_en

数据读使能信号

o_afdx_data

输出规整AFDX数据

o_frame_enable

输出规整后的帧使能信号

5.4 仿真和仿真说明

    规整模块的主要工作流程如下所示:

将这个数据输入到FIFO,根据实际的帧使能信号作为FIFO的写入信号,那么在FIFO中,输入的数据包将以如下的格式排列:假设数据包:4’bA,0,0,0,4’b B,0,0,4’b C,0,0,0,0,4’b D,0,0,4’b E,0,0,0,4’b F,。。。。。。。。其时序信号为:

 

 

本文地址:https://blog.csdn.net/ccsss22/article/details/109274060

《基于FPGA的EMAC模块和FIFO模块.doc》

下载本文的Word格式文档,以方便收藏与打印。