基于FPGA的EMAC模块和FIFO模块
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
推荐阅读
-
广和通Fibocom基于高通X55平台的5G模块FM150在英伟达Jetson Nano上的应用
-
基于FPGA的EMAC模块和FIFO模块
-
基于stm32和RDA5851S蓝牙模块的歌名歌手同步显示
-
基于FPGA的USB2.0数据传输(通过本文可以自己设计USB2.0模块)
-
基于RequireJS和JQuery的模块化编程日常问题解析_javascript技巧
-
基于RequireJS和JQuery的模块化编程日常问题解析_javascript技巧
-
解析Node.js基于模块和包的代码部署方式_node.js
-
基于FPGA的EMAC模块和FIFO模块
-
广和通Fibocom基于高通X55平台的5G模块FM150在英伟达Jetson Nano上的应用
-
基于stm32和RDA5851S蓝牙模块的歌名歌手同步显示