由于各种原因,如旧式电脑的网卡不支持千兆网等,导致PHY在自协商时速率达不到1000Mbps。而目前主流的FPGA的以太网实验均基于千兆网络编写测试代码,因此根据千兆网络降速编写百兆网的测试实验样例是有必要的,后续可再进一步编写自适应网速切换百兆或千兆的测试例程。
本文将基于正点原子开拓者V2开发板进行适配百兆网络的FPGA中的ARP测试代码编写,主要由正点原子千兆网实验教程改编,千兆网与百兆网的区别并不是很大,因此,主要将记录不同的代码,百兆网下其余与千兆网相同的代码将不再赘述。
实验环境:
Quartus II 13.1 Altera FPGA EP4CE10F17C8N
若是Xilinx环境,则将相关的IP核在基于Xilinx进行更改重新生成,其余RTL级代码基本相同。
代码更改:
正点原子开拓者V2开发板的以太网接口为RGMII接口,数据位宽为4位,在千兆网络下,在时钟上下沿采样,在百兆与十兆网络下,为单个时钟沿采样。
相比GMII接口与MII接口,RGMII至少可以节省8根数据线,因此,现多数PHY侧芯片连接FPGA时多采用RGMII接口。
在RGMII下,百兆网通信时,主要有几根数据线需要注意。
ETH_RXC:
接收数据参考时钟,100Mbps 速率下,时钟频率为 25MHz ETH_RXC 由 PHY 侧提供。
ETH_RXCTL(ETH_RX_DV):
接收数据控制信号。
ETH_TXC:
发送参考时钟,100Mbps 速率下,时钟频率为 25MHz, ETH_TXC 由 MAC 侧提供。
ETH_TXCTL(ETH_TXEN):
发送数据控制信号。
rgmii
接收模块
由于ARP模块中的arp_rx.v
,即 arp
接收模块下的输入数据gmii_rxd
为为8位,因此arp
接收模块的输入时钟应该为12.5Mhz,而为了保持arp
接收模块与前一级的rgmii
接收模块时钟一致,保证时钟尽量同步。rgmii
接收模块的输入时钟也为12.5Mhz。rgmii
接收模块百兆时序如下:
但rgmii
接收模块的输入如果为12.5Mhz,且根据百兆网协议单边沿采样传输数据,则网络速率将只为12.5MhzX4bit=50Mbps
,因此为了保证100Mbps的速率,rgmii
接收模块将以12.5Mhz的时钟,以双边沿采样的方式,采样RGMII接收数据,将速率提升至100Mbps,具体代码如下:
/************************************************************************
* 项目名称 : $FPGA实验箱$
* 类 名 称 : $ARP测试实验$
* 版 本 号 : 1.0
* 作 者 : kxq
* 邮 箱 : [email protected]
* 网 站 : https://www.cnblogs.com/kxqblog/
* 创建时间 : $2022/8/9$
* 项目描述 : RGMII接收模块
************************************************************************/
module rgmii_rx(
//以太网RGMII接口
input rgmii_rxc , //RGMII接收时钟
input sys_rst_n,
input rgmii_rx_ctl, //RGMII接收数据控制信号
input [3:0] rgmii_rxd , //RGMII接收数据
//以太网GMII接口
output gmii_rx_clk , //GMII接收时钟
output gmii_rx_dv , //GMII接收数据有效信号
output [7:0] gmii_rxd //GMII接收数据
);
reg cnt;
wire [1:0] gmii_rxdv_t; //两位GMII接收有效信号
//*****************************************************
//** main code
//*****************************************************
assign gmii_rx_clk = rgmii_rxc;
assign gmii_rx_dv = gmii_rxdv_t[0] & gmii_rxdv_t[1];
ddi_x4 ddi_x4_inst(
.datain (rgmii_rxd ),
.inclock (rgmii_rxc ),
.dataout_h (gmii_rxd[7:4]),
.dataout_l (gmii_rxd[3:0])
);
ddi_x1 ddi_x1_inst(
.datain (rgmii_rx_ctl),
.inclock (rgmii_rxc ),
.dataout_h (gmii_rxdv_t[1]),
.dataout_l (gmii_rxdv_t[0])
);
endmodule
这里的ddi
IP核是Altera下的ALTDDIO_IN
IP,实现双沿数据和单沿数据之间的转换,相关介绍可以参考网络上的一些教程与一些参考书籍。
这里的ddi_x4
是在12.5Mhz下将输入的4bit rgmii_rxd
转换为8bit gmii_rxd
输入给arp
接收模块。ddi_x1
是将接收数据中的使能信号
与使能信号异或错误信号的结果
输入给arp
接收模块。
从之前的rgmii
接收模块百兆时序图来看,时钟边沿与数据传输边沿对齐,这样将在采样时发生错误,因此,有必要对于输入时钟进行偏移,对于千兆网来说,可以通过硬件引脚上拉电阻的方式,硬件延时2ns来偏移1/4个周期。而对百兆网,千兆网硬件延时的时间较短,不适用于百兆网的rgmii
接收模块,这里,在生成输入时钟的PLL的IP核中对于12.5Mhz进行偏移45度,如下图所示。
rgmii
发送模块
相比较正点原子中的千兆速率下的rgmii发送模块
,改动幅度较大。在百兆rgmii
发送模块中,数据发送时钟ETH_TXC
为25Mhz,且为上边沿采样方式。因此rgmii
发送模块百兆时序如下:
从图中可以看出,数据发送时钟为25Mhz时,时钟采样发送数据将为25MhzX4bit=100Mbps
,恰好为百兆的发送速率,具体代码如下,需要有一定的Verilog代码基础。
/************************************************************************
* 项目名称 : $FPGA实验箱$
* 类 名 称 : $ARP测试实验$
* 版 本 号 : 1.0
* 作 者 : kxq
* 邮 箱 : [email protected]
* 网 站 : https://www.cnblogs.com/kxqblog/
* 创建时间 : $2022/8/9$
* 项目描述 : RGMII发送模块
************************************************************************/
module rgmii_tx(
//GMII发送端口
input gmii_tx_clk , //GMII发送时钟
input sys_rst_n,
input gmii_tx_en , //GMII输出数据有效信号
input [7:0] gmii_txd , //GMII输出数据
//RGMII发送端口
output rgmii_txc , //RGMII发送数据时钟
output reg rgmii_tx_ctl, //RGMII输出数据有效信号
output reg [3:0] rgmii_txd //RGMII输出数据
);
reg cnt;
//*****************************************************
//** main code
//*****************************************************
always@(posedge gmii_tx_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 1'b0;
else
cnt <= cnt + 1'b1;
end
always@(posedge gmii_tx_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
rgmii_txd <= 4'd0;
else if(cnt == 1'b1)
rgmii_txd <= gmii_txd[3:0];
else
rgmii_txd <= gmii_txd[7:4];
end
always@(posedge gmii_tx_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
rgmii_tx_ctl <= 1'b0;
else if(cnt == 1'b1)
rgmii_tx_ctl <= gmii_tx_en;
else
rgmii_tx_ctl <= gmii_tx_en;
end
assign rgmii_txc = gmii_tx_clk;
endmodule
这里,GMII发送时钟与RGMII发送数据时钟速率设置保持一致。同样地,rgmii
发送模块百兆时序中可以看出,时钟边沿与数据传输边沿对齐,这样将在采样时发生错误。因此需要在生成输入时钟的PLL的IP核中对于25Mhz进行偏移45度,如下图所示。
arp
测试顶层模块
相比较于正点原子手册中的arp
测试顶层模块,在本改进的百兆网模块下,主要是对rgmii
转gmii
模块与时钟锁相环进行了更改,具体可以参考以下代码。
/************************************************************************
* 项目名称 : $FPGA实验箱$
* 类 名 称 : $ARP测试实验$
* 版 本 号 : 1.0
* 作 者 : kxq
* 邮 箱 : [email protected]
* 网 站 : https://www.cnblogs.com/kxqblog/
* 创建时间 : $2022/8/9$
* 项目描述 : 顶层模块,实现ARP协议
************************************************************************/
module eth_arp_top(
input sys_rst_n , //系统复位信号,低电平有效
input touch_key , //KEY0按键开关
//以太网RGMII接口
input eth_rxc , //RGMII接收数据时钟
input eth_rx_ctl, //RGMII输入数据有效信号
input [3:0] eth_rxd , //RGMII输入数据
output eth_txc , //RGMII发送数据时钟
output eth_tx_ctl, //RGMII输出数据有效信号
output [3:0] eth_txd , //RGMII输出数据
output eth_rst_n , //以太网芯片复位信号,低电平有效
output sample_clk
);
//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.137.10
parameter BOARD_IP = {8'd192,8'd168,8'd137,8'd10};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.137.11
parameter DES_IP = {8'd192,8'd168,8'd137,8'd11};
//wire define
wire eth_rxc_deg ; //eth_rxc时钟相位偏移
wire gmii_rx_clk ; //GMII接收时钟
wire gmii_rx_dv ; //GMII接收数据有效信号
wire [7:0] gmii_rxd ; //GMII接收数据
wire gmii_tx_clk ; //GMII发送时钟
wire gmii_tx_en ; //GMII发送数据使能信号
wire [7:0] gmii_txd ; //GMII发送数据
wire arp_gmii_tx_en; //ARP GMII输出数据有效信号
wire [7:0] arp_gmii_txd ; //ARP GMII输出数据
wire arp_rx_done ; //ARP接收完成信号
wire arp_rx_type ; //ARP接收类型 0:请求 1:应答
wire [47:0] src_mac ; //接收到目的MAC地址
wire [31:0] src_ip ; //接收到目的IP地址
wire arp_tx_en ; //ARP发送使能信号
wire arp_tx_type ; //ARP发送类型 0:请求 1:应答
wire [47:0] des_mac ; //发送的目标MAC地址
wire [31:0] des_ip ; //发送的目标IP地址
wire arp_tx_done ; //ARP发送完成信号
wire clk_25Mhz;
//*****************************************************
//** main code
//*****************************************************
assign des_mac = src_mac;
assign des_ip = src_ip;
assign eth_rst_n = sys_rst_n;
//PLL
pll my_pll(
.inclk0 (eth_rxc),
.c0 (eth_rxc_deg),
.c1 (sample_clk),
.c2 (clk_25Mhz),
.locked ()
);
//GMII接口转RGMII接口
gmii_to_rgmii my_gmii_to_rgmii(
.gmii_rx_clk (gmii_rx_clk ),
.gmii_rx_dv (gmii_rx_dv ),
.gmii_rxd (gmii_rxd ),
.gmii_tx_clk (clk_25Mhz ), //gmii_tx_clk
.gmii_tx_en (gmii_tx_en ),
.gmii_txd (gmii_txd ),
.rgmii_rxc (eth_rxc_deg ),
.rgmii_rx_ctl (eth_rx_ctl ),
.rgmii_rxd (eth_rxd ),
.rgmii_txc (eth_txc ),
.rgmii_tx_ctl (eth_tx_ctl ),
.rgmii_txd (eth_txd ),
.sys_rst_n (sys_rst_n)
);
//ARP通信
arp
#(
.BOARD_MAC (BOARD_MAC), //参数例化
.BOARD_IP (BOARD_IP ),
.DES_MAC (DES_MAC ),
.DES_IP (DES_IP )
)
my_arp(
.rst_n (sys_rst_n ),
.gmii_rx_clk (gmii_rx_clk),
.gmii_rx_dv (gmii_rx_dv ),
.gmii_rxd (gmii_rxd ),
.gmii_tx_clk (eth_rxc_deg),
.gmii_tx_en (gmii_tx_en ),
.gmii_txd (gmii_txd ),
.arp_rx_done (arp_rx_done),
.arp_rx_type (arp_rx_type),
.src_mac (src_mac ),
.src_ip (src_ip ),
.arp_tx_en (arp_tx_en ),
.arp_tx_type (arp_tx_type),
.des_mac (des_mac ),
.des_ip (des_ip ),
.tx_done (tx_done )
);
//ARP控制
arp_ctrl my_arp_ctrl(
.clk (gmii_rx_clk),
.rst_n (sys_rst_n),
.touch_key (~touch_key),
.arp_rx_done (arp_rx_done),
.arp_rx_type (arp_rx_type),
.arp_tx_en (arp_tx_en),
.arp_tx_type (arp_tx_type)
);
endmodule
其中,PLL中的C1时钟100Mhz,是SignalTapII
测试抓波时的采样时钟,可以不用。C0时钟eth_rxc_deg
为之前所说的偏移后的25Mhz时钟。GMII接口转RGMII接口中对gmii_tx_clk
进行了更改,同时再添加一路复位信号。ARP通信中对gmii_tx_clk
进行了更改,上层的arp
模块下的子发送模块的参考时钟同样要与GMII接口转RGMII接口中的发送时钟同步。
测试结果
最终经过测试,修改后的代码无论是在板子发送ARP消息给电脑,或是电脑给FPGA发送ping消息下,电脑均能正确解析,并动态加载板子的Mac地址。
板子发送消息给电脑并正确识别:
电脑ping板子,其中ARP消息被正确解析。
代码链接 : https://pan.baidu.com/s/1kQ24aYFQdKwEA1BUmWDgzA?pwd=vgue
参考博客:
https://blog.csdn.net/weixin_55796564/article/details/122459134
https://www.likecs.com/show-204584212.html
https://www.jianshu.com/p/46b762fee7ad
http://t.zoukankan.com/571328401--p-12686528.html
https://blog.csdn.net/weixin_42464967/article/details/112781420
https://www.cnblogs.com/amxiang/p/16288835.html
以及小梅哥,野火等一些论坛中查找的资料,这里就不一一详细列举。
标签:ARP,arp,tx,FPGA,rx,gmii,rgmii,以太网,时钟 From: https://www.cnblogs.com/kxqblog/p/16972403.html