筆者使用的開發(fā)板是米聯(lián)客zynq UitraScale+ xczu4ev-sfvc784-2-i開發(fā)板進(jìn)行測(cè)試
由于米聯(lián)客協(xié)議族源碼不開源,自己寫了一個(gè)簡(jiǎn)易的以太網(wǎng)接口轉(zhuǎn)換模塊只支持1000M速率。
一、接口框圖:(引用原子哥)

二、RGMII接口時(shí)序簡(jiǎn)介:
(1)接收時(shí)序(PHY>FPGA)
RXC 的上下邊沿與 RXD 和 RX_CTL 信號(hào)對(duì)齊,相位相同。(非延時(shí)模式)

RXC 的上下邊沿與 RXD 和 RX_CTL 信號(hào)的中間位置對(duì)齊,相位相差90度(延時(shí)模式)
RXC 的時(shí)鐘周期為 8ns,單個(gè)高電平或者低電平為 4ns, RXC 相對(duì)于 RXD 和 RX_CTL 延時(shí)約 2ns。

(2)發(fā)送時(shí)序(FPGA>PHY)
TXC 的上下邊沿與 TXD 和 TX_CTL 信號(hào)對(duì)齊,相位相同。 (非延時(shí)模式)

RGMII 發(fā)送端口在 TXC 時(shí)鐘的上升沿傳輸 TXD 的低 4 位和 TX_CTL 的使能信號(hào);
下降沿傳輸 TXD 的高 4 位和 TX_CTL 的錯(cuò)誤信號(hào)(實(shí)際上是使能信號(hào)和錯(cuò)誤信號(hào)的異或值); RGMII 接收端口在RXC 時(shí)鐘的上升沿傳輸 RXD 的低 4 位和 RX_CTL 的使能信號(hào);
下降沿傳輸RXD 的高 4 位和RX_CTL 的錯(cuò)誤信號(hào)(實(shí)際上是使能信號(hào)和錯(cuò)誤信號(hào)的異或值)。(延時(shí)模式)

注意:筆者芯片接收時(shí)序?yàn)檠訒r(shí)模式,發(fā)送時(shí)序?yàn)檎DJ?,具體模式需參考相應(yīng)原理圖引腳上下拉判斷,也可通過MDIO配置。
三、原語使用
UitraScale+系列的開發(fā)板原語使用和7系列大不相同,需要了解IDDRE1、ODDRE1、BUFG、BUFIO、IDELAYE3 、 ODELAYE3。在本次測(cè)試中并未使用IDELAYE3 、 ODELAYE3不做研究,原因是其phy芯片rxd端采用延時(shí)模式txd采用非延時(shí)模式(輸出我們采用pll的方法相位偏移90度)。
//全局緩沖, BUFG 的輸出到達(dá) FPGA 內(nèi)部的 IOB、 CLB、塊 RAM 的時(shí)鐘延遲和抖動(dòng)最小。
BUFG BUFG_inst (
.I (rgmii_rxc), // 1-bit input: Clock input
.O (rgmii_clk_buf) // 1-bit output: Clock output
);
//BUFIO 是 IO 時(shí)鐘網(wǎng)絡(luò),其獨(dú)立于全局時(shí)鐘資源,適合采集源同步數(shù)據(jù)。它只能驅(qū)動(dòng) IO Block 里面的邏輯,不能驅(qū)動(dòng) CLB 里面的 LUT, REG 等邏輯。
BUFIO BUFIO_inst (
.I (rgmii_rxc), // 1-bit input: Clock input
.O (rgmii_rxc_bufio) // 1-bit output: Clock output
);
//將輸入的上下邊沿 DDR 信號(hào),轉(zhuǎn)換成兩位單邊沿 SDR 信號(hào)。
IDDRE1 #(
.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)模式選擇一般選擇SAME_EDGE_PIPELINED模式
.IS_CB_INVERTED(1'b1), // Optional inversion for CB,高速時(shí)鐘CB反向使能
.IS_C_INVERTED(1'b0) // Optional inversion for C,高速時(shí)鐘C反向不使能
)
IDDRE1_inst (
.Q1(w_gmii_rx_dv), // 1-bit output: Registered parallel output 1輸出低4位
.Q2(w_rgmii_rx_ctl), // 1-bit output: Registered parallel output 2輸出高4位
.C(rgmii_rxc_bufio), // 1-bit input: High-speed clock高速時(shí)鐘輸入
.CB(rgmii_rxc_bufio), // 1-bit input: Inversion of High-speed clock C高速時(shí)鐘c的反轉(zhuǎn)
與這個(gè)IS_CB_INVERTED參數(shù)互斥
.D(rgmii_rx_ctl), // 1-bit input: Serial Data Input8位數(shù)據(jù)輸入
.R(1'b0) // 1-bit input: Active-High Async Reset置位/復(fù)位信號(hào),高有效
);
//把兩路單端的數(shù)據(jù)合并到一路上輸出,上下沿同時(shí)輸出數(shù)據(jù),上升沿輸出 a路,下降沿輸出 b 路
ODDRE1 #(
.IS_C_INVERTED (1'b0 ), // Optional inversion for C c的反轉(zhuǎn)
.IS_D1_INVERTED (1'b0 ), // Unsupported, do not use無用默認(rèn)
.IS_D2_INVERTED (1'b0 ), // Unsupported, do not use無用默認(rèn)
.SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,設(shè)備版本選擇
.SRVAL (1'b0 ) // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)初始化ODDRE1觸發(fā)器到指定值(1'bo, 1'b1)
)
u_rgmii_tx_ctl
(
.Q (rgmii_tx_ctl ), // 1-bit output: Data output to IOB 8位數(shù)據(jù)輸出
.C (gmii_tx_clk ), // 1-bit input: High-speed clock input高速時(shí)鐘輸入
.D1 (gmii_tx_en ), // 1-bit input: Parallel data input 1輸入數(shù)據(jù)低4位
.D2 (gmii_tx_er ), // 1-bit input: Parallel data input 2輸入數(shù)據(jù)高4位
.SR (0 ) // 1-bit input: Active High Async Reset置位/復(fù)位信號(hào),高有效
);
四、源碼
代碼寫法有很多筆者也參考了很多廠商dmo有誤請(qǐng)?jiān)谠u(píng)論區(qū)指正
module gmii_rgmii(
input wire rgmii_rxc ,//輸入時(shí)鐘
input wire [3:0] rgmii_rxd ,//輸入數(shù)據(jù)
input wire rgmii_rx_ctl ,//輸入控制
output wire [3:0] rgmii_txd ,//輸出數(shù)據(jù)
output wire rgmii_tx_ctl ,//輸出控制
output wire rgmii_txc ,//發(fā)送時(shí)鐘
output wire gmii_rx_clk ,//輸出接收時(shí)鐘
output wire [7:0] gmii_rxd ,//輸入8位數(shù)據(jù)
output wire gmii_rx_dv ,//輸出數(shù)據(jù)有效
input wire [7:0] gmii_txd ,//輸入8位數(shù)據(jù)
input wire gmii_tx_en ,//輸入發(fā)送使能高有效
input wire gmii_tx_er ,//輸入數(shù)據(jù)是否有誤高有效
output wire gmii_tx_clk //輸出發(fā)送時(shí)鐘
);
wire w_gmii_rx_dv ;
wire w_rgmii_rx_ctl ;
wire rgmii_rxc_bufio;
wire rgmii_clk_buf ;
/* Rgmii rx */
BUFG BUFG_inst (
.I (rgmii_rxc), // 1-bit input: Clock input
.O (rgmii_clk_buf) // 1-bit output: Clock output
);
BUFIO BUFIO_inst (
.I (rgmii_rxc), // 1-bit input: Clock input
.O (rgmii_rxc_bufio) // 1-bit output: Clock output
);
assign gmii_rx_clk = rgmii_clk_buf;
assign gmii_tx_clk = rgmii_clk_buf;
assign gmii_rx_dv = (w_gmii_rx_dv & w_rgmii_rx_ctl);
IDDRE1 #(
.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
.IS_CB_INVERTED(1'b1), // Optional inversion for CB
.IS_C_INVERTED(1'b0) // Optional inversion for C
)
IDDRE1_inst (
.Q1(w_gmii_rx_dv), // 1-bit output: Registered parallel output 1
.Q2(w_rgmii_rx_ctl), // 1-bit output: Registered parallel output 2
.C(rgmii_rxc_bufio), // 1-bit input: High-speed clock
.CB(rgmii_rxc_bufio), // 1-bit input: Inversion of High-speed clock C
.D(rgmii_rx_ctl), // 1-bit input: Serial Data Input
.R(1'b0) // 1-bit input: Active-High Async Reset
);
genvar i;
generate
for (i = 0; i < 4; i = i + 1)
begin : rxdata_bus
IDDRE1 #(
.DDR_CLK_EDGE ("SAME_EDGE_PIPELINED" ), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
.IS_CB_INVERTED (1'b1 ), // Optional inversion for CB
.IS_C_INVERTED (1'b0 ) // Optional inversion for C
)
u_rgmii_rxd
(
.Q1 (gmii_rxd[i] ), // 1-bit output: Registered parallel output 1
.Q2 (gmii_rxd[i+4] ), // 1-bit output: Registered parallel output 2
.C (rgmii_rxc_bufio ), // 1-bit input: High-speed clock
.CB (rgmii_rxc_bufio ), // 1-bit input: Inversion of High-speed clock C
.D (rgmii_rxd[i] ), // 1-bit input: Serial Data Input
.R (0 ) // 1-bit input: Active High Async Reset
);
end
endgenerate
/* Rgmii tx */
assign rgmii_txc=gmii_tx_clk;
ODDRE1 #(
.IS_C_INVERTED (1'b0 ), // Optional inversion for C
.IS_D1_INVERTED (1'b0 ), // Unsupported, do not use
.IS_D2_INVERTED (1'b0 ), // Unsupported, do not use
.SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,
.SRVAL (1'b0 ) // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
)
u_rgmii_tx_ctl
(
.Q (rgmii_tx_ctl ), // 1-bit output: Data output to IOB
.C (gmii_tx_clk ), // 1-bit input: High-speed clock input
.D1 (gmii_tx_en ), // 1-bit input: Parallel data input 1
.D2 (gmii_tx_er ), // 1-bit input: Parallel data input 2
.SR (0 ) // 1-bit input: Active High Async Reset
);
genvar j;
generate
for (j = 0; j < 4; j = j + 1)
begin: txdata_bus
ODDRE1 #(
.IS_C_INVERTED (1'b0 ), // Optional inversion for C
.IS_D1_INVERTED (1'b0 ), // Unsupported, do not use
.IS_D2_INVERTED (1'b0 ), // Unsupported, do not use
.SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,
.SRVAL (1'b0 ) // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
)
u_rgmii_txd
(
.Q (rgmii_txd[j] ), // 1-bit output: Data output to IOB
.C (gmii_tx_clk ), // 1-bit input: High-speed clock input
.D1 (gmii_txd[j] ), // 1-bit input: Parallel data input 1
.D2 (gmii_txd[4+j] ), // 1-bit input: Parallel data input 2
.SR (0 ) // 1-bit input: Active High Async Reset
);
end
endgenerate
endmodule
pll資源配置:


頂層例化使用
//MMCM/PLL偏移90度
clk_wiz_0 u_clk_wiz(
// Clock out ports
.clk_out1 (clk_125m_deg), // output clk_out1
// Status and control signals
//.reset (~sys_rst_n ), // input reset
.locked (locked ), // output locked
// Clock in ports
.clk_in1 (rgmii_txc ) // input clk_in1
);
五、仿真
有點(diǎn)亂碼不影響查看文章來源:http://www.zghlxwxcb.cn/news/detail-461206.html
`timescale 1ns / 1ps
module gmii_rgmii_tb();
reg rgmii_rxc ;//閹恒儲(chǔ)鏁歸弮鍫曟??
reg clk ;//婢跺秳錕??
wire [3:0] rgmii_txd ;//閸欐埊錕???閿熻姤鏆熼敓??
wire rgmii_tx_ctl ;//閺佺増宓??幒褍????
wire rgmii_txc ;//閸欐埊錕???閿熻姤妞傞敓??
reg [3:0] rgmii_rxd ;//閹恒儲(chǔ)鏁歸弫鐗堝??
reg rgmii_rx_ctl ;//閹恒儲(chǔ)鏁歸弫鐗堝祦閹貉冨??
wire gmii_rx_clk ;//閺佺増宓佺憴锝嗭???錕介幒銉?chǔ)鏁归弮鍫曞K??
reg [7:0] gmii_txd ;//鏉堟挸鍙嗛弫鐗堝??
reg gmii_tx_en ;//閺佺増宓佹擔(dān)鑳??
reg gmii_tx_er ;//閺佺増宓??柨嬈掝嚖
wire gmii_tx_clk ;//閺佺増宓??崣鎴嫹?閿熻姤妞傞敓??
wire [7:0] gmii_rxd ;//閹恒儲(chǔ)鏁歸弫鐗堝??
wire gmii_rx_dv ;//閹恒儲(chǔ)鏁歸弫鐗堝祦閺堝????
initial begin
clk=0;
rgmii_rxc=0;rgmii_rxd=4'd1;gmii_txd=8'b1;
end
always #8 rgmii_rxc=!rgmii_rxc;
always #4 clk=!clk;
initial begin
rgmii_rx_ctl=1;gmii_tx_en=1'b1;gmii_tx_er=1'b1;
#100;
end
always@(posedge rgmii_rxc)begin
#1
if(gmii_txd==15)gmii_txd=0;
else
gmii_txd=gmii_txd+1'b1;
end
always@(posedge clk )begin
#1
if(rgmii_rxd==40)rgmii_rxd=0;
else
rgmii_rxd=rgmii_rxd+1'b1;
end
gmii_rgmii gmii_rgmii(
/*input wire */. rgmii_rxc (rgmii_rxc) ,//閹恒儲(chǔ)鏁歸弮鍫曟??
/*output wire [3:0] */. rgmii_txd (rgmii_txd) ,//閸欐埊錕???閿熻姤鏆熼敓??
/*output wire */. rgmii_tx_ctl (rgmii_tx_ctl) ,//閺佺増宓??幒褍????
/*output wire */. rgmii_txc (rgmii_txc) ,//閸欐埊錕???閿熻姤妞傞敓??
/*input wire [3:0] */. rgmii_rxd (rgmii_rxd) ,//閹恒儲(chǔ)鏁歸弫鐗堝??
/*input wire */. rgmii_rx_ctl (rgmii_rx_ctl) ,//閹恒儲(chǔ)鏁歸弫鐗堝祦閹貉冨??
/*output wire */. gmii_rx_clk (gmii_rx_clk) ,//閺佺増宓佺憴锝嗭???錕介幒銉?chǔ)鏁归弮鍫曞K??
/*input wire [7:0] */. gmii_txd (gmii_txd) ,//鏉堟挸鍙嗛弫鐗堝??
/*input wire */. gmii_tx_en (gmii_tx_en) ,//閺佺増宓佹擔(dān)鑳??
/*input wire */. gmii_tx_er (gmii_tx_er) ,//閺佺増宓??柨嬈掝嚖
/*output wire */. gmii_tx_clk (gmii_tx_clk) ,//閺佺増宓??崣鎴嫹?閿熻姤妞傞敓??
/*output reg [7:0] */. gmii_rxd (gmii_rxd) ,//閹恒儲(chǔ)鏁歸弫鐗堝??
/*output reg */. gmii_rx_dv (gmii_rx_dv) //閹恒儲(chǔ)鏁歸弫鐗堝祦閺堝????
);
endmodule

注意:發(fā)送時(shí)鐘并未體現(xiàn)數(shù)據(jù)中間采樣是因?yàn)闀r(shí)鐘輸出采用pll使相位偏移90度在頂層實(shí)現(xiàn)
對(duì)了由于是高速接口需添加時(shí)序約束。時(shí)鐘是由PHY芯片產(chǎn)生的125Mhz時(shí)鐘需要添加引腳輸入的主時(shí)鐘約束到.xdc文件中(注意放在引腳約束前)如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-461206.html
create_clock -period 8.000 -name rgmii_rxc [get_ports rgmii_rxc]
六、板級(jí)驗(yàn)證

到了這里,關(guān)于基于FPGA 以太網(wǎng)gmii_to_rgmii模塊編寫 附源碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!