FPGA实现千兆/百兆自适应以太网UDP传输
0、前言
筆者最近在項(xiàng)目中需要使用到ZYNQ中PL端做以太網(wǎng)UDP傳輸并且需要支持100M/1000M自適應(yīng)切換。使用的PHY型號(hào)為RTL8211。以下分享的主要為利用已有的1000M協(xié)議棧修改為100M并且實(shí)現(xiàn)二者自適應(yīng)切換,IP核主要實(shí)現(xiàn)以下功能
1、實(shí)現(xiàn)100M/1000M自適應(yīng)
2、回環(huán)測(cè)試
PS:完整的IP核文件下載地址:https://download.csdn.net/download/qq_24025329/87019436
1、軟硬件環(huán)境和前置條件
筆者采用的接口是RGMII接口,即100M模式下單邊沿采樣,時(shí)鐘頻率為25M。在1000M模式下使用雙邊沿采樣,時(shí)鐘頻率為125M。所以在千兆模式下需要使用原語(yǔ)對(duì)數(shù)據(jù)采樣,這里就不過(guò)多贅述了,這里默認(rèn)已經(jīng)擁有了可以實(shí)現(xiàn)1000M通訊的協(xié)議棧了。
2、實(shí)現(xiàn)步驟
第一步:千兆-百兆接收數(shù)據(jù)轉(zhuǎn)換模塊
這里筆者偷了個(gè)懶,既然已經(jīng)有了千兆模式下讀取的數(shù)據(jù),那么我們只需要根據(jù)千兆與百兆之間的采樣模式進(jìn)行轉(zhuǎn)換就可以讀出來(lái)正確的數(shù)據(jù)了。具體思想如下
1、千兆為雙邊沿采樣,百兆為單邊沿采樣。所以在千兆模式RGMII轉(zhuǎn)換為GMII接口下跑百兆的速度讀出來(lái)的8bit數(shù)據(jù)中高四位=低四位的。所以我們將讀出來(lái)的數(shù)據(jù)只保留四位即可。下圖為千兆模式下的采樣
?2、時(shí)鐘采用PHY提供的時(shí)鐘,即百兆模式下25M千兆模式下為125M即可。具體實(shí)現(xiàn)代碼如下
`timescale 1ns / 1ps module eth_speed(input Rst_n, //系統(tǒng)復(fù)位//以太網(wǎng)GMII接口input gmii_rx_clk , //GMII接收時(shí)鐘input gmii_rx_dv , //GMII接收數(shù)據(jù)有效信號(hào)input [7:0] gmii_rxd , //GMII接收數(shù)據(jù)//速度轉(zhuǎn)換后以太網(wǎng)GMII接口output gmii_rx_clk_s , //GMII接收時(shí)鐘output gmii_rx_dv_s , //GMII接收數(shù)據(jù)有效信號(hào)output reg[7:0] gmii_rxd_s //GMII接收數(shù)據(jù)); //==========參數(shù)定義=============// parameter SPEED = 1000;//1000Mbps//==========寄存器定義===========// reg out_clk; //輸出時(shí)鐘 reg count_s; //二分?jǐn)?shù)據(jù)計(jì)數(shù) reg data0_en; reg data1_en; //數(shù)據(jù)有效位//==========組合邏輯運(yùn)算=============// assign gmii_rx_clk_s = out_clk;//輸出時(shí)鐘二分頻 assign gmii_rx_dv_s = data0_en && data1_en;//接收數(shù)據(jù)有效//==========時(shí)序邏輯============// //輸入時(shí)鐘二分頻 always @(posedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)out_clk <= 1'd0; elseout_clk <= ~out_clk;//二分?jǐn)?shù)據(jù)計(jì)數(shù) //第一個(gè)數(shù)據(jù)來(lái)臨后的第一個(gè)下降沿=1 // always @(negedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)count_s <= 1'd0; else if(!gmii_rx_dv)//數(shù)據(jù)無(wú)效 清零count_s <= 1'd0; elsecount_s = ~count_s;//反轉(zhuǎn)//采集數(shù)據(jù)1 下降沿采集數(shù)據(jù) always @(negedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)gmii_rxd_s[3:0] <= 4'd0; else if(gmii_rx_dv && (!count_s))//接收數(shù)據(jù)有效并且二分頻時(shí)鐘位低電平gmii_rxd_s[3:0] <= gmii_rxd[3:0];//采集數(shù)據(jù)2 下降沿采集數(shù)據(jù) always @(negedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)gmii_rxd_s[7:4] <= 4'd0; else if(gmii_rx_dv && (count_s))//接收數(shù)據(jù)有效并且二分頻時(shí)鐘位低電平gmii_rxd_s[7:4] <= gmii_rxd[3:0];//采集數(shù)據(jù)1有效位 always @(posedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)data0_en <= 1'd0; else if(!count_s) //第一個(gè)數(shù)據(jù)采樣的周期if(gmii_rx_dv) //有效data0_en <= 1'd1;elsedata0_en <= 1'd0; elsedata0_en <= data0_en;//采集數(shù)據(jù)2有效位 always @(posedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)data1_en <= 1'd0; else if(count_s) //第二個(gè)數(shù)據(jù)采樣的周期if(gmii_rx_dv) //有效data1_en <= 1'd1;elsedata1_en <= 1'd0; elsedata1_en <= data1_en;endmodule第二步:千兆-百兆接收數(shù)據(jù)轉(zhuǎn)換模塊
發(fā)送方面就不能偷懶了,只能自己寫了一個(gè)百兆模式下的發(fā)送,代碼如下
`timescale 1ns / 1psmodule eth_speed_tx(input Rst_n,input gmii_rx_clk, //來(lái)自PHY的時(shí)鐘//獲得數(shù)據(jù)接口input [7:0] data_in, //GMII數(shù)據(jù)input data_en, //GMII使能output data_clk, //GMII時(shí)鐘,用于獲取發(fā)送數(shù)據(jù),是RGMII的1/2//RGMII接口output rgmii_txc, //RGMII的時(shí)鐘output reg[3:0]rgmii_txd, //RGMII發(fā)送的數(shù)據(jù)output rgmii_tx_ctl //RGMII發(fā)送控制 );//========寄存器定義===========// reg rgmii_txc_2_s;//發(fā)送時(shí)鐘的二分頻 并滯后90° reg en_delay;//輸入使能延遲//==========邏輯==============// assign data_clk = rgmii_txc_2_s; assign rgmii_tx_ctl = data_en|en_delay; assign rgmii_txc = gmii_rx_clk;//==========時(shí)序邏輯==========// //時(shí)鐘二分頻 用于獲得數(shù)據(jù) 并滯后90° always@(negedge rgmii_txc or negedge Rst_n) if(!Rst_n)rgmii_txc_2_s <= 1'd0; elsergmii_txc_2_s <= ~rgmii_txc_2_s;//發(fā)送數(shù)據(jù)賦值 always @(negedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)rgmii_txd <= 4'd0; else if(data_en && rgmii_txc_2_s)//要發(fā)送第一個(gè)4bit數(shù)據(jù) 低位rgmii_txd <= data_in[3:0]; else if(data_en && (!rgmii_txc_2_s))//要發(fā)送第二個(gè)4bit數(shù)據(jù) 高位rgmii_txd <= data_in[7:4]; elsergmii_txd <= rgmii_txd;//使能延遲 always @(negedge gmii_rx_clk or negedge Rst_n) if(!Rst_n)en_delay <= 1'd0; else if(data_en && (!rgmii_txc_2_s))en_delay <= 1'd1; elseen_delay <= 1'd0;endmodule第三步:百兆千兆切換邏輯
百兆和千兆模式下切換本質(zhì)上就是切換RGMII的接口信號(hào)源,具體的邏輯較為簡(jiǎn)單如圖所示
?其中SPEED為選擇開關(guān),該值可以是定義的參數(shù),也可以當(dāng)作接口有外部提供。
最后
該IP核是筆者在項(xiàng)目中解決自己的問(wèn)題所編寫,水平有限如有疏漏敬請(qǐng)指正。
總結(jié)
以上是生活随笔為你收集整理的FPGA实现千兆/百兆自适应以太网UDP传输的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: VUE 拦截浏览器后退弹窗,弹窗一闪立刻
- 下一篇: 大数据环境中资源优化配置策略研究(非原创