資料介紹
在數據的傳輸過程中,我們經常可以碰見雙沿傳輸數據到FPGA,或者FPGA傳輸雙沿數據給外部芯片,最常見的例子就是DDR芯片。這里說明一下,FPGA內部處理的數據都是單沿數據,那么雙沿數據的變換只能發生在FPGA的IOB上面,這里有特定的硬件結構可以實驗上面單沿變雙沿的方法,也就是使用原語進行一些列的操作。本次實驗的主要內容如下:
以千兆網RGMII為例實現單沿變雙沿、雙沿變單沿的操作。經過之前博客的理解,我們可以知道RGMII的協議是雙沿傳輸,那么我們將以此為例實現雙沿4bit數據變單沿8bit數據——FPGA接收,單沿8bit數據變雙沿4bit數據——FPGA發送。
IDDR與ODDR的簡述
這里的表述,我們主要依靠技術手冊來給大家進行講解。
簡單的框圖顯示如下:
其中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”。上面每一位的介紹在原語的注釋中都得到了比較詳細的解釋,這里不再贅述。這三種工作模式的不同其實就是時序的不同,下面分別進行介紹:
1、OPPOSITE_EDGE模式
這里主要注意,一個時鐘的上升沿與下降沿數據正好可以在下一個時鐘上升沿的Q1、Q2輸出,這也是最常見的使用方式。我們千兆網的接收信號使用的就是該模式。
2、SAME_EDGE模式
這里特別注意,一個時鐘的上升沿和下降沿的兩個數據在Q1、Q2的表示分別在下一個時鐘與下下一個時鐘體現出來,原來的兩個數據被分裂成兩個時鐘表示。
3、SAME_EDGE_PIPELINED模式
其中這種模式與第一種的模式是Q1、Q2是同步的,前者是異步的,這種模式數據的讀取比第一種模式晚了一個節拍。當然千兆網的數據接收也可以使用該模式,以為控制端也是使用該模式進行解碼。
與IDDR相對應的是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 );
同樣,上面每一位的介紹在原語的注釋中都得到了比較詳細的解釋,這里不再贅述。其中ODDR有兩種不同的工作模式。我們將進行如下介紹:
1、OPPOSITE_EDGE模式
從上面我們可以看出,該模式是將兩個時鐘的D1、D2拼成了一個時鐘的上升沿與下降沿對應的數據。我們本次千兆網的輸出項目中不會使用該模式,因為D1與D2會錯開一個時鐘。
2、SAME_EDGE模式
從上面的時序圖中我們可以看出,同一個時鐘的D1、D2轉換成了同一個時鐘的上升沿與下降沿。我們本次項目中使用的就是這個模式。
RGMII時序簡述
前面已經講解了常見的以太網物理層協議接口,其中RGMII是雙沿數據,需要使用原語進行相應單雙沿變化的操作。其中,RGMII協議的具體時序圖如下:
這里有幾點注意整理如下:
1、TXD的0位上升沿與下降沿分別對應8位數據的0位與4位,TXD其他的位數以此相互遞增。
2、RXD的0位上升沿與下降沿分別對應8位數據的0位與4位,RXD其他的位數以此相互遞增。
3、TX_CLK是輸入時鐘,RX_CLK是輸出時鐘。
4、XX_CTL線上升沿對應的是數據使能位,下降沿對應的是數據錯誤位。
千兆網輸入與輸出模塊的設計
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
測試模塊的設計
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
仿真測試結果
程序的仿真測試結果如下:
上面的實驗我們將ODDR與IDDR聯合起來進行相應的仿真,仿真結果也證明了我們千兆網發送與接收模塊單雙沿變化的正確性。
來源:電子創新網
評論
查看更多