資料介紹
在數(shù)據(jù)的傳輸過程中,我們經(jīng)常可以碰見雙沿傳輸數(shù)據(jù)到FPGA,或者FPGA傳輸雙沿?cái)?shù)據(jù)給外部芯片,最常見的例子就是DDR芯片。這里說明一下,F(xiàn)PGA內(nèi)部處理的數(shù)據(jù)都是單沿?cái)?shù)據(jù),那么雙沿?cái)?shù)據(jù)的變換只能發(fā)生在FPGA的IOB上面,這里有特定的硬件結(jié)構(gòu)可以實(shí)驗(yàn)上面單沿變雙沿的方法,也就是使用原語進(jìn)行一些列的操作。本次實(shí)驗(yàn)的主要內(nèi)容如下:
以千兆網(wǎng)RGMII為例實(shí)現(xiàn)單沿變雙沿、雙沿變單沿的操作。經(jīng)過之前博客的理解,我們可以知道RGMII的協(xié)議是雙沿傳輸,那么我們將以此為例實(shí)現(xiàn)雙沿4bit數(shù)據(jù)變單沿8bit數(shù)據(jù)——FPGA接收,單沿8bit數(shù)據(jù)變雙沿4bit數(shù)據(jù)——FPGA發(fā)送。
IDDR與ODDR的簡(jiǎn)述
這里的表述,我們主要依靠技術(shù)手冊(cè)來給大家進(jìn)行講解。
簡(jiǎn)單的框圖顯示如下:
其中IDDR的原語如下:
IDDR#( .DDR_CLK_EDGE("OPPOSITE_EDGE"),//"OPPOSITE_EDGE","SAME_EDGE" //or"SAME_EDGE_PIPELINED" .INIT_Q1(1'b0),//InitialvalueofQ1:1'b0or1'b1 .INIT_Q2(1'b0),//InitialvalueofQ2:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )IDDR_ctrl( .Q1(data_en),//1-bitoutputforpositiveedgeofclock .Q2(data_err),//1-bitoutputfornegativeedgeofclock .C(rx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D(rx_ctrl),//1-bitDDRdatainput .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset );
其中IDDR主要有三種工作模式,分別是:“OPPOSITE_EDGE”,“SAME_EDGE”,“SAME_EDGE_PIPELINED”。上面每一位的介紹在原語的注釋中都得到了比較詳細(xì)的解釋,這里不再贅述。這三種工作模式的不同其實(shí)就是時(shí)序的不同,下面分別進(jìn)行介紹:
1、OPPOSITE_EDGE模式
這里主要注意,一個(gè)時(shí)鐘的上升沿與下降沿?cái)?shù)據(jù)正好可以在下一個(gè)時(shí)鐘上升沿的Q1、Q2輸出,這也是最常見的使用方式。我們千兆網(wǎng)的接收信號(hào)使用的就是該模式。
2、SAME_EDGE模式
這里特別注意,一個(gè)時(shí)鐘的上升沿和下降沿的兩個(gè)數(shù)據(jù)在Q1、Q2的表示分別在下一個(gè)時(shí)鐘與下下一個(gè)時(shí)鐘體現(xiàn)出來,原來的兩個(gè)數(shù)據(jù)被分裂成兩個(gè)時(shí)鐘表示。
3、SAME_EDGE_PIPELINED模式
其中這種模式與第一種的模式是Q1、Q2是同步的,前者是異步的,這種模式數(shù)據(jù)的讀取比第一種模式晚了一個(gè)節(jié)拍。當(dāng)然千兆網(wǎng)的數(shù)據(jù)接收也可以使用該模式,以為控制端也是使用該模式進(jìn)行解碼。
與IDDR相對(duì)應(yīng)的是ODDR。同樣,ODDR的框圖如下:
其中ODDR的原語如下:
ODDR#( .DDR_CLK_EDGE("SAME_EDGE"),//"OPPOSITE_EDGE"or"SAME_EDGE" .INIT(1'b0),//InitialvalueofQ:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )ODDR_ctrl( .Q(tx_data_ctrl),//1-bitDDRoutput .C(gb_tx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D1(gb_tx_data_en),//1-bitdatainput(positiveedge) .D2(gb_tx_data_err),//1-bitdatainput(negativeedge) .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset );
同樣,上面每一位的介紹在原語的注釋中都得到了比較詳細(xì)的解釋,這里不再贅述。其中ODDR有兩種不同的工作模式。我們將進(jìn)行如下介紹:
1、OPPOSITE_EDGE模式
從上面我們可以看出,該模式是將兩個(gè)時(shí)鐘的D1、D2拼成了一個(gè)時(shí)鐘的上升沿與下降沿對(duì)應(yīng)的數(shù)據(jù)。我們本次千兆網(wǎng)的輸出項(xiàng)目中不會(huì)使用該模式,因?yàn)镈1與D2會(huì)錯(cuò)開一個(gè)時(shí)鐘。
2、SAME_EDGE模式
從上面的時(shí)序圖中我們可以看出,同一個(gè)時(shí)鐘的D1、D2轉(zhuǎn)換成了同一個(gè)時(shí)鐘的上升沿與下降沿。我們本次項(xiàng)目中使用的就是這個(gè)模式。
RGMII時(shí)序簡(jiǎn)述
前面已經(jīng)講解了常見的以太網(wǎng)物理層協(xié)議接口,其中RGMII是雙沿?cái)?shù)據(jù),需要使用原語進(jìn)行相應(yīng)單雙沿變化的操作。其中,RGMII協(xié)議的具體時(shí)序圖如下:
這里有幾點(diǎn)注意整理如下:
1、TXD的0位上升沿與下降沿分別對(duì)應(yīng)8位數(shù)據(jù)的0位與4位,TXD其他的位數(shù)以此相互遞增。
2、RXD的0位上升沿與下降沿分別對(duì)應(yīng)8位數(shù)據(jù)的0位與4位,RXD其他的位數(shù)以此相互遞增。
3、TX_CLK是輸入時(shí)鐘,RX_CLK是輸出時(shí)鐘。
4、XX_CTL線上升沿對(duì)應(yīng)的是數(shù)據(jù)使能位,下降沿對(duì)應(yīng)的是數(shù)據(jù)錯(cuò)誤位。
千兆網(wǎng)輸入與輸出模塊的設(shè)計(jì)
gbit_top模塊:
`timescale1ns/1ps //********************************************************************************* //ProjectName:OSXXXX //Author:zhangningning //Email:nnzhang1996@foxmail.com //Website: //ModuleName:gbit_top.v //CreateTime:2020-03-1709:43:00 //Editor:sublimetext3,tabsize(4) //CopyRight(c):AllRightsReserved // //********************************************************************************* //ModificationHistory: //DateByVersionChangeDescription //----------------------------------------------------------------------- //XXXXzhangningning1.0Original // //********************************************************************************* modulegbit_top( //SystemInterfaces inputsclk, inputrst_n, //GigbitInterfaces outputregphy_rst_n, input[3:0]rx_data, inputrx_ctrl, inputrx_clk ); //========================================================================================/ //**************DefineParameterandInternalSignals********************************** //========================================================================================/ reg[20:0]phy_rst_cnt; wirerx_clk_90; //iddr_ctrl_inst wire[7:0]gb_rx_data; wiregb_rx_data_en; wiregb_rx_data_err; //========================================================================================/ //**************MainCode********************************** //========================================================================================/ clk_wiz_0clk_wiz_0_inst( //Clockoutports .clk_out1(rx_clk_90),//outputclk_out1 //Clockinports .clk_in1(rx_clk) ); iddr_ctrliddr_ctrl_inst( //SystemInterfaces .rst_n(rst_n), //GigabitInterfaces .rx_data(rx_data), .rx_ctrl(rx_ctrl), .rx_clk(rx_clk_90), //CommunicationInterfaces .gb_rx_data(gb_rx_data), .gb_rx_data_en(gb_rx_data_en), .gb_rx_data_err(gb_rx_data_err) ); always@(posedgesclkornegedgerst_n) if(rst_n==1'b0) phy_rst_cnt<=21'd0; elseif(phy_rst_cnt[20]==1'b0) phy_rst_cnt<=phy_rst_cnt+1'b1; else phy_rst_cnt<=phy_rst_cnt; always@(posedgesclkornegedgerst_n) if(rst_n==1'b0) phy_rst_n<=1'b0; elseif(phy_rst_cnt[20]==1'b1) phy_rst_n<=1'b1; else phy_rst_n<=phy_rst_n; endmodule
iddr_ctrl模塊
`timescale1ns/1ps //********************************************************************************* //ProjectName:OSXXXX //Author:zhangningning //Email:nnzhang1996@foxmail.com //Website: //ModuleName:iddr_ctrl.v //CreateTime:2020-03-1709:21:20 //Editor:sublimetext3,tabsize(4) //CopyRight(c):AllRightsReserved // //********************************************************************************* //ModificationHistory: //DateByVersionChangeDescription //----------------------------------------------------------------------- //XXXXzhangningning1.0Original // //********************************************************************************* moduleiddr_ctrl( //SystemInterfaces inputrst_n, //GigabitInterfaces input[3:0]rx_data, inputrx_ctrl, inputrx_clk, //CommunicationInterfaces outputreg[7:0]gb_rx_data, outputreggb_rx_data_en, outputreggb_rx_data_err ); //========================================================================================/ //**************DefineParameterandInternalSignals********************************** //========================================================================================/ wire[7:0]data; wiredata_en; wiredata_err; //========================================================================================/ //**************MainCode********************************** //========================================================================================/ IDDR#( .DDR_CLK_EDGE("OPPOSITE_EDGE"),//"OPPOSITE_EDGE","SAME_EDGE" //or"SAME_EDGE_PIPELINED" .INIT_Q1(1'b0),//InitialvalueofQ1:1'b0or1'b1 .INIT_Q2(1'b0),//InitialvalueofQ2:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )IDDR_ctrl( .Q1(data_en),//1-bitoutputforpositiveedgeofclock .Q2(data_err),//1-bitoutputfornegativeedgeofclock .C(rx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D(rx_ctrl),//1-bitDDRdatainput .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset ); genvari; generate for(i=0;i<4;i=i+1)begin IDDR#( .DDR_CLK_EDGE("OPPOSITE_EDGE"),//"OPPOSITE_EDGE","SAME_EDGE" //or"SAME_EDGE_PIPELINED" .INIT_Q1(1'b0),//InitialvalueofQ1:1'b0or1'b1 .INIT_Q2(1'b0),//InitialvalueofQ2:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )IDDR_ctrl( .Q1(data[i]),//1-bitoutputforpositiveedgeofclock .Q2(data[4+i]),//1-bitoutputfornegativeedgeofclock .C(rx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D(rx_data[i]),//1-bitDDRdatainput .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset ); end endgenerate always@(posedgerx_clkornegedgerst_n) if(rst_n==1'b0) gb_rx_data<=8'd0; else gb_rx_data<=data; always@(posedgerx_clkornegedgerst_n) if(rst_n==1'b0) gb_rx_data_err<=1'b0; else gb_rx_data_err<=data_err; always@(posedgerx_clkornegedgerst_n) if(rst_n==1'b0) gb_rx_data_en<=1'b0; else gb_rx_data_en<=data_en; endmodule
oddr_ctrl模塊
`timescale1ns/1ps //********************************************************************************* //ProjectName:OSXXXX //Author:zhangningning //Email:nnzhang1996@foxmail.com //Website: //ModuleName:oddr_ctrl.v //CreateTime:2020-03-1709:56:53 //Editor:sublimetext3,tabsize(4) //CopyRight(c):AllRightsReserved // //********************************************************************************* //ModificationHistory: //DateByVersionChangeDescription //----------------------------------------------------------------------- //XXXXzhangningning1.0Original // //********************************************************************************* moduleoddr_ctrl( //SystemInterfaces inputrst_n, //GigbitInterfaces outputwire[3:0]tx_data, outputwiretx_data_ctrl, outputwiretx_clk, //CommunicationInterfaces input[7:0]gb_tx_data, inputgb_tx_data_en, inputgb_tx_data_err, inputgb_tx_clk ); //========================================================================================/ //**************DefineParameterandInternalSignals********************************** //========================================================================================/ //========================================================================================/ //**************MainCode********************************** //========================================================================================/ ODDR#( .DDR_CLK_EDGE("SAME_EDGE"),//"OPPOSITE_EDGE"or"SAME_EDGE" .INIT(1'b0),//InitialvalueofQ:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )ODDR_ctrl( .Q(tx_data_ctrl),//1-bitDDRoutput .C(gb_tx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D1(gb_tx_data_en),//1-bitdatainput(positiveedge) .D2(gb_tx_data_err),//1-bitdatainput(negativeedge) .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset ); ODDR#( .DDR_CLK_EDGE("SAME_EDGE"),//"OPPOSITE_EDGE"or"SAME_EDGE" .INIT(1'b0),//InitialvalueofQ:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )ODDR_clk( .Q(tx_clk),//1-bitDDRoutput .C(gb_tx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D1(1'b1),//1-bitdatainput(positiveedge) .D2(1'b0),//1-bitdatainput(negativeedge) .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset ); genvari; generate for(i=0;i<4;i=i+1)begin ODDR#( .DDR_CLK_EDGE("SAME_EDGE"),//"OPPOSITE_EDGE"or"SAME_EDGE" .INIT(1'b0),//InitialvalueofQ:1'b0or1'b1 .SRTYPE("SYNC")//Set/Resettype:"SYNC"or"ASYNC" )ODDR_data( .Q(tx_data[i]),//1-bitDDRoutput .C(gb_tx_clk),//1-bitclockinput .CE(1'b1),//1-bitclockenableinput .D1(gb_tx_data[i]),//1-bitdatainput(positiveedge) .D2(gb_tx_data[4+i]),//1-bitdatainput(negativeedge) .R(~rst_n),//1-bitreset .S(1'b0)//1-bitset ); end endgenerate endmodule
測(cè)試模塊的設(shè)計(jì)
tb_gigbit模塊
`timescale1ns/1ps `defineCLOCK8 //********************************************************************************* //ProjectName:OSXXXX //Author:zhangningning //Email:nnzhang1996@foxmail.com //Website: //ModuleName:tb_gigbit.v //CreateTime:2020-03-1710:25:11 //Editor:sublimetext3,tabsize(4) //CopyRight(c):AllRightsReserved // //********************************************************************************* //ModificationHistory: //DateByVersionChangeDescription //----------------------------------------------------------------------- //XXXXzhangningning1.0Original // //********************************************************************************* moduletb_gigbit; regsclk; regrst_n; reg[7:0]gb_tx_data; reggb_tx_data_en; reggb_tx_clk; wire[3:0]tx_data; wiretx_data_ctrl; wiretx_clk; wirephy_rst_n; initialbegin rst_n<=1'b0; gb_tx_clk=1'b0; sclk=1'b0; #(100*`CLOCK) rst_n<=1'b1; end always#(`CLOCK/2)gb_tx_clk=~gb_tx_clk; always#(10)sclk=~sclk; initialbegin gb_tx_data<=8'd0; gb_tx_data_en<=1'b0; @(posedgephy_rst_n) #(1000*`CLOCK) gen_data(); #(1000*`CLOCK) gen_data(); end taskgen_data; integeri; begin i=0; for(i=0;i<100;i=i+1)begin @(posedgegb_tx_clk); gb_tx_data_en<=1'b1; if(i<7) gb_tx_data<=8'h55; elseif(i==7) gb_tx_data<=8'hd5; else gb_tx_data<=i; end @(posedgegb_tx_clk); gb_tx_data<=8'h0; gb_tx_data_en<=1'b0; end endtask oddr_ctrloddr_ctrl_inst( //SystemInterfaces .rst_n(rst_n), //GigbitInterfaces .tx_data(tx_data), .tx_data_ctrl(tx_data_ctrl), .tx_clk(tx_clk), //CommunicationInterfaces .gb_tx_data(gb_tx_data), .gb_tx_data_en(gb_tx_data_en), .gb_tx_data_err(1'b0), .gb_tx_clk(gb_tx_clk) ); gbit_topgbit_top_inat( //SystemInterfaces .sclk(sclk), .rst_n(rst_n), //GigbitInterfaces .phy_rst_n(phy_rst_n), .rx_data(tx_data), .rx_ctrl(tx_data_ctrl), .rx_clk(tx_clk) ); endmodule
仿真測(cè)試結(jié)果
程序的仿真測(cè)試結(jié)果如下:
上面的實(shí)驗(yàn)我們將ODDR與IDDR聯(lián)合起來進(jìn)行相應(yīng)的仿真,仿真結(jié)果也證明了我們千兆網(wǎng)發(fā)送與接收模塊單雙沿變化的正確性。
評(píng)論
查看更多