日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

FPGA设计心得(5)Aurora 例子工程分析与仿真实例分析(streaming版)

發(fā)布時間:2023/12/3 综合教程 36 生活家
生活随笔 收集整理的這篇文章主要介紹了 FPGA设计心得(5)Aurora 例子工程分析与仿真实例分析(streaming版) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 背景
  • 例子工程預(yù)覽
  • 例子程序用戶模塊邏輯分析
    • 收(CHECK)
    • 發(fā)(GEN)
  • 例子程序仿真文件分析
  • 寫在最后
  • 工程分享
  • 參考資料
  • 交個朋友

背景

熬夜寫完了上兩篇博客:
Aurora IP core 的理論學(xué)習(xí)記錄
Aurora IP core 的定制詳情記錄
到這一篇應(yīng)該就是分析例子程序了,最重要地還是通過仿真來認識Aurora通信。
Aurora IP核的定制,基本都是默認的,為了簡單起見,GT Selection中選擇了一個通道(lane)。
文章末尾會分享工程文件!

例子工程預(yù)覽

由于本IP核定制選擇了:
因此,程序加入了一些debug的IP核例化。
如下:

而對于我們要仿真而言,這些都是沒有必要的。
對于我們用戶應(yīng)用來說,最最重要的模塊為:

一個check,一個gen。

gen代表發(fā)數(shù)據(jù)的模塊,而check則為收數(shù)據(jù)的模塊。
如數(shù)據(jù)手冊:
而如何對二者進行仿真呢?
形成一個回環(huán),示意圖如下:
一方發(fā),另一方收,反之亦然!
而testbench的作用就是將二者聯(lián)系起來:
下圖清晰說明:
例子程序中帶有仿真文件:

可見,例化了兩次例子程序,就是為了將一方的tx送給另一方的rx,同時,另一方的tx送入一方的rx,形成一個閉環(huán)。

例子程序用戶模塊邏輯分析

收(CHECK)

我們知道收模塊與aurora IP streaming用戶接口之間的關(guān)系是:


因此,用戶接口很簡單,就兩個信號進來就好,m_axi_rx_data以及m_axi_rx_valid即可,valid有效,則data數(shù)據(jù)為有效數(shù)據(jù),至于收到的數(shù)據(jù)做什么處理,隨你!例子程序的處理,我也不想深究,收過來按照自己的需求搞就完事了。

給出源碼:


`timescale 1 ns / 1 ps
`define DLY #1module aurora_8b10b_streaming_FRAME_CHECK
(// User InterfaceRX_D, RX_SRC_RDY_N,// System InterfaceUSER_CLK,      RESET,CHANNEL_UP,ERR_COUNT
);//***********************************Port Declarations*******************************// User Interface
input   [0:15]     RX_D;
input              RX_SRC_RDY_N;// System Interface
input              USER_CLK;
input              RESET; 
input              CHANNEL_UP;output  [0:7]      ERR_COUNT;
//***************************Internal Register Declarations***************************
// Slack registersreg   [0:15]     RX_D_SLACK;
reg              RX_SRC_RDY_N_SLACK;reg     [0:8]      err_count_r = 9'd0;// RX Data registers
reg     [0:15]     data_lfsr_r;//*********************************Wire Declarations**********************************wire               reset_c;
wire    [0:15]     data_lfsr_concat_w;
wire               data_valid_c;wire               data_err_detected_c;
reg                data_err_detected_r;//*********************************Main Body of Code**********************************//Generate RESET signal when Aurora channel is not readyassign reset_c = RESET;// SLACK registersalways @ (posedge USER_CLK)
beginRX_D_SLACK          <= `DLY RX_D;RX_SRC_RDY_N_SLACK  <= `DLY RX_SRC_RDY_N;
end//______________________________ Capture incoming data ___________________________   //Data is valid when RX_SRC_RDY_N is assertedassign  data_valid_c    =   !RX_SRC_RDY_N_SLACK;//generate expected RX_D using LFSRalways @(posedge USER_CLK)if(reset_c)begindata_lfsr_r          <=  `DLY    16'hD5E6;  //random seed valueendelse if(CHANNEL_UP)beginif(data_valid_c)data_lfsr_r          <=  `DLY    {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},data_lfsr_r[0:14]};endelse begindata_lfsr_r          <=  `DLY    16'hD5E6;  //random seed valueend assign data_lfsr_concat_w = {1{data_lfsr_r}};//___________________________ Check incoming data for errors __________________________//An error is detected when LFSR generated RX data from the data_lfsr_concat_w register,//does not match valid data from the RX_D portassign  data_err_detected_c    = (data_valid_c && (RX_D_SLACK != data_lfsr_concat_w));//We register the data_err_detected_c signal for use with the error counter logicalways @(posedge USER_CLK)data_err_detected_r    <=  `DLY    data_err_detected_c; //Compare the incoming data with calculated expected data.//Increment the ERROR COUNTER if mismatch occurs.//Stop the ERROR COUNTER once it reaches its max value (i.e. 255)always @(posedge USER_CLK)if(CHANNEL_UP)beginif(&err_count_r)err_count_r       <=  `DLY    err_count_r;else if(data_err_detected_r)err_count_r       <=  `DLY    err_count_r + 1;endelsebegin	       	err_count_r       <=  `DLY    9'd0;end   //Here we connect the lower 8 bits of the count (the MSbit is used only to check when the counter reaches//max value) to the module outputassign  ERR_COUNT =   err_count_r[1:8];endmodule          

仿真預(yù)告:


這便是收到的數(shù)據(jù)。

對了,程序中的這個輸入變量:
RX_SRC_RDY_N
就是valid的反而已:

    //______________________________ Capture incoming data ___________________________   //Data is valid when RX_SRC_RDY_N is assertedassign  data_valid_c    =   !RX_SRC_RDY_N_SLACK;

其他的不言而喻!

發(fā)(GEN)

發(fā)要比收需要的信號多一個,那就是ready信號,具體為:

   // User Interface
output  [0:15]     TX_D;
output             TX_SRC_RDY_N;
input              TX_DST_RDY_N;

根據(jù)streaming格式的關(guān)系:
我們用戶邏輯需要得到一個ready有效信號,然后置位valid的同時,發(fā)送有效數(shù)據(jù)data。

例子發(fā)送程序根據(jù)lsfr產(chǎn)生隨機數(shù)據(jù)發(fā)送:

    //______________________________ Transmit Data  __________________________________   //Transmit data when TX_DST_RDY_N is asserted.//Random data is generated using XNOR feedback LFSR//TX_SRC_RDY_N is asserted on every cycle with dataalways @(posedge USER_CLK)if(reset_c)begindata_lfsr_r          <=  `DLY    16'hABCD;  //random seed valueTX_SRC_RDY_N    <=  `DLY    1'b1;   endelse if(!TX_DST_RDY_N)begindata_lfsr_r          <=  `DLY    {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},data_lfsr_r[0:14]};TX_SRC_RDY_N    <=  `DLY    1'b0;end//Connect TX_D to the DATA LFSR registerassign  TX_D    =   {1{data_lfsr_r}};

不需要多言!
下面給出完整發(fā)送程序:


`timescale 1 ns / 1 ps
`define DLY #1module aurora_8b10b_streaming_FRAME_GEN
(// User InterfaceTX_D, TX_SRC_RDY_N,TX_DST_RDY_N,// System InterfaceUSER_CLK,      RESET,CHANNEL_UP
);
//*****************************Parameter Declarations****************************//***********************************Port Declarations*******************************// User Interface
output  [0:15]     TX_D;
output             TX_SRC_RDY_N;
input              TX_DST_RDY_N;// System Interface
input              USER_CLK;
input              RESET; 
input              CHANNEL_UP;//***************************External Register Declarations***************************reg                TX_SRC_RDY_N;//***************************Internal Register Declarations***************************reg     [0:15]     data_lfsr_r;    wire               reset_c;wire       dly_data_xfer;reg [4:0]  channel_up_cnt;//*********************************Main Body of Code**********************************always @ (posedge USER_CLK)beginif(RESET)channel_up_cnt <= `DLY 5'd0;else if(CHANNEL_UP)if(&channel_up_cnt)channel_up_cnt <= `DLY channel_up_cnt;else channel_up_cnt <= `DLY channel_up_cnt + 1'b1;elsechannel_up_cnt <= `DLY 5'd0;endassign dly_data_xfer = (&channel_up_cnt);//Generate RESET signal when Aurora channel is not readyassign reset_c = RESET || !dly_data_xfer;//______________________________ Transmit Data  __________________________________   //Transmit data when TX_DST_RDY_N is asserted.//Random data is generated using XNOR feedback LFSR//TX_SRC_RDY_N is asserted on every cycle with dataalways @(posedge USER_CLK)if(reset_c)begindata_lfsr_r          <=  `DLY    16'hABCD;  //random seed valueTX_SRC_RDY_N    <=  `DLY    1'b1;   endelse if(!TX_DST_RDY_N)begindata_lfsr_r          <=  `DLY    {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},data_lfsr_r[0:14]};TX_SRC_RDY_N    <=  `DLY    1'b0;end//Connect TX_D to the DATA LFSR registerassign  TX_D    =   {1{data_lfsr_r}};endmodule

仿真預(yù)警:

這邊是發(fā)送數(shù)據(jù)。

例子程序仿真文件分析

先給出仿真文件(然后在簡單分析仿真文件):


`timescale 1 ns / 1 psmodule aurora_8b10b_streaming_TB;//*************************Parameter Declarations**************************parameter       SIM_MAX_TIME  = 9500000; //To quit the simulation//125.0MHz GT Reference clock
parameter       CLOCKPERIOD_1 = 8.0	;
parameter       CLOCKPERIOD_2 = 8.0	;
//parameter       CLOCKPERIOD_1 = 8.0;
//parameter       CLOCKPERIOD_2 = 8.0;
parameter       DRP_CLOCKPERIOD = 20.000	 ; //GT DRP Clock
parameter       INIT_CLOCKPERIOD = 20.0 ; // Board/System Clock//************************Internal Register Declarations*****************************//Freerunning Clock
reg                reference_clk_1_n_r;
reg                reference_clk_2_n_r;
reg     drp_clk_r;
reg     init_clk_p;//Global signals
reg                gt_reset_in;
reg                gsr_r;
reg                gts_r;
reg                reset_i;//********************************Wire Declarations**********************************//Freerunning Clock        
wire               reference_clk_1_p_r;
wire               reference_clk_2_p_r;         wire    init_clk_n;
//Dut1//Error Detection Interface
wire               hard_err_1_i;        
wire               soft_err_1_i;        //Status
wire               channel_up_1_i;        
wire               lane_up_1_i;//GT Serial I/O
wire               rxp_1_i; 
wire               rxn_1_i; wire               txp_1_i; 
wire               txn_1_i; // Error signals from the Local Link packet checker
wire    [0:7]      err_count_1_i; //Dut2//Error Detection Interface
wire               hard_err_2_i;        
wire               soft_err_2_i;        //Status
wire               channel_up_2_i;        
wire               lane_up_2_i;//GT Serial I/O
wire               rxp_2_i; 
wire               rxn_2_i; wire               txp_2_i; 
wire               txn_2_i; // Error signals from the Local Link packet checker
wire    [0:7]      err_count_2_i; //*********************************Main Body of Code**********************************//_________________________Serial Connections________________assign   rxn_1_i      =    txn_2_i;assign   rxp_1_i      =    txp_2_i;assign   rxn_2_i      =    txn_1_i;assign   rxp_2_i      =    txp_1_i;//__________________________Global Signals_____________________________//Simultate the global reset that occurs after configuration at the beginning//of the simulation. Note that both GT smart models use the same global signals.assign glbl.GSR = gsr_r;assign glbl.GTS = gts_r;initialbegingts_r    = 1'b0;       gsr_r    = 1'b1;gt_reset_in = 1'b1;#5000;gsr_r    = 1'b0;gt_reset_in = 1'b0;repeat(10) @(posedge init_clk_p);gt_reset_in = 1'b1;repeat(10) @(posedge init_clk_p);gt_reset_in = 1'b0;end//____________________________Clocks____________________________initialreference_clk_1_n_r = 1'b0;always #(CLOCKPERIOD_1 / 2) reference_clk_1_n_r = !reference_clk_1_n_r;assign reference_clk_1_p_r = !reference_clk_1_n_r;initialreference_clk_2_n_r = 1'b0;always #(CLOCKPERIOD_2 / 2) reference_clk_2_n_r = !reference_clk_2_n_r;assign reference_clk_2_p_r = !reference_clk_2_n_r;initialdrp_clk_r = 1'b0;always #(DRP_CLOCKPERIOD / 2) drp_clk_r = !drp_clk_r;initialinit_clk_p = 1'b0;always #(INIT_CLOCKPERIOD / 2) init_clk_p = !init_clk_p;assign init_clk_n =  !init_clk_p;//____________________________Resets____________________________initialbeginreset_i = 1'b1;#1000 reset_i = 1'b0;end//________________________Instantiate Dut 1 ________________aurora_8b10b_streaming_exdes example_design_1_i
(// User IO.RESET(reset_i),// Error signals from Aurora   .HARD_ERR(hard_err_1_i),.SOFT_ERR(soft_err_1_i),// Status Signals.LANE_UP(lane_up_1_i),.CHANNEL_UP(channel_up_1_i),.INIT_CLK_P(init_clk_p),.INIT_CLK_N(init_clk_n),.DRP_CLK_IN(drp_clk_r), .GT_RESET_IN(gt_reset_in),// Clock Signals.GTXQ0_P(reference_clk_1_p_r),.GTXQ0_N(reference_clk_1_n_r),// GT I/O.RXP(rxp_1_i),.RXN(rxn_1_i),.TXP(txp_1_i),.TXN(txn_1_i),// Error signals from the Local Link packet checker.ERR_COUNT(err_count_1_i)
);//________________________Instantiate Dut 2 ________________aurora_8b10b_streaming_exdes example_design_2_i
(// User IO.RESET(reset_i),// Error signals from Aurora   .HARD_ERR(hard_err_2_i),.SOFT_ERR(soft_err_2_i),// Status Signals.LANE_UP(lane_up_2_i),.CHANNEL_UP(channel_up_2_i),.INIT_CLK_P(init_clk_p),.INIT_CLK_N(init_clk_n),.DRP_CLK_IN(drp_clk_r), .GT_RESET_IN(gt_reset_in),// Clock Signals.GTXQ0_P(reference_clk_2_p_r),.GTXQ0_N(reference_clk_2_n_r),// GT I/O.RXP(rxp_2_i),.RXN(rxn_2_i),.TXP(txp_2_i),.TXN(txn_2_i),// Error signals from the Local Link packet checker.ERR_COUNT(err_count_2_i)
);

分為幾個部分,

  • 端口聲明:
    一般而言,輸入聲明為reg類型,輸出為wire。
    例如:
    //GT Serial I/O
wire               rxp_1_i; 
wire               rxn_1_i; wire               txp_1_i; 
wire               txn_1_i; 

但也不盡然如此,例如輸入的差分時鐘,我們就可以將其中一個聲明為reg,至于差分的另一半,聲明為wire,之后通過取反操作來實現(xiàn):

    //Freerunning Clock
reg                reference_clk_1_n_r;
reg                reference_clk_2_n_r;
reg     drp_clk_r;
reg     init_clk_p;//********************************Wire Declarations**********************************//Freerunning Clock        
wire               reference_clk_1_p_r;
wire               reference_clk_2_p_r;         wire    init_clk_n;
assign reference_clk_1_p_r = !reference_clk_1_n_r;
assign reference_clk_2_p_r = !reference_clk_2_n_r;
assign init_clk_n =  !init_clk_p;
  • 產(chǎn)生時鐘
    時鐘較多,差分時鐘產(chǎn)生方法是先生成p時鐘或者n時鐘,之后取反得到另一方:
//____________________________Clocks____________________________initialreference_clk_1_n_r = 1'b0;always #(CLOCKPERIOD_1 / 2) reference_clk_1_n_r = !reference_clk_1_n_r;assign reference_clk_1_p_r = !reference_clk_1_n_r;initialreference_clk_2_n_r = 1'b0;always #(CLOCKPERIOD_2 / 2) reference_clk_2_n_r = !reference_clk_2_n_r;assign reference_clk_2_p_r = !reference_clk_2_n_r;initialdrp_clk_r = 1'b0;always #(DRP_CLOCKPERIOD / 2) drp_clk_r = !drp_clk_r;initialinit_clk_p = 1'b0;always #(INIT_CLOCKPERIOD / 2) init_clk_p = !init_clk_p;assign init_clk_n =  !init_clk_p;//____________________________Resets____________________________initialbeginreset_i = 1'b1;#1000 reset_i = 1'b0;end
  • 例化待測試模塊
    例化兩次aurora例子程序,作為通信的雙方:
//________________________Instantiate Dut 1 ________________aurora_8b10b_streaming_exdes example_design_1_i
(// User IO.RESET(reset_i),// Error signals from Aurora   .HARD_ERR(hard_err_1_i),.SOFT_ERR(soft_err_1_i),// Status Signals.LANE_UP(lane_up_1_i),.CHANNEL_UP(channel_up_1_i),.INIT_CLK_P(init_clk_p),.INIT_CLK_N(init_clk_n),.DRP_CLK_IN(drp_clk_r), .GT_RESET_IN(gt_reset_in),// Clock Signals.GTXQ0_P(reference_clk_1_p_r),.GTXQ0_N(reference_clk_1_n_r),// GT I/O.RXP(rxp_1_i),.RXN(rxn_1_i),.TXP(txp_1_i),.TXN(txn_1_i),// Error signals from the Local Link packet checker.ERR_COUNT(err_count_1_i)
);//________________________Instantiate Dut 2 ________________aurora_8b10b_streaming_exdes example_design_2_i
(// User IO.RESET(reset_i),// Error signals from Aurora   .HARD_ERR(hard_err_2_i),.SOFT_ERR(soft_err_2_i),// Status Signals.LANE_UP(lane_up_2_i),.CHANNEL_UP(channel_up_2_i),.INIT_CLK_P(init_clk_p),.INIT_CLK_N(init_clk_n),.DRP_CLK_IN(drp_clk_r), .GT_RESET_IN(gt_reset_in),// Clock Signals.GTXQ0_P(reference_clk_2_p_r),.GTXQ0_N(reference_clk_2_n_r),// GT I/O.RXP(rxp_2_i),.RXN(rxn_2_i),.TXP(txp_2_i),.TXN(txn_2_i),// Error signals from the Local Link packet checker.ERR_COUNT(err_count_2_i)
);

雙方如何形成一個通路的呢?
1發(fā)接到2的收,2發(fā)接到1的收:

   //_________________________Serial Connections________________assign   rxn_1_i      =    txn_2_i;assign   rxp_1_i      =    txp_2_i;assign   rxn_2_i      =    txn_1_i;assign   rxp_2_i      =    txp_1_i;

由于數(shù)據(jù)是自己的gen模塊以及產(chǎn)生的,故在設(shè)計文件中設(shè)計即可。
下面仿真實踐,看看仿真圖吧!

先宏觀地看第一個仿真圖:

可見,一方(簡稱partner1)和另一方(簡稱partner2)串行數(shù)據(jù)完全一致,理所當(dāng)然如此,因為二者是直接相連的回環(huán)。
當(dāng)然,這種串行數(shù)據(jù)我們是看不懂的,我們要看的是用戶邏輯,模塊check以及gen的數(shù)據(jù),繼續(xù)把二者拉出來仿真:

從partner1的gen中提取出valid,data,ready信號;
再從partner2的check中提取出valid和data信號。
二者構(gòu)成一個通路。

上圖中,TX_D就是s_axi_tx_data,而TX_DST_RDY_N取反就是s_axi_tx_tready,同理,TX_SRC_RDY_N取反是s_axi_tx_valid,故而,當(dāng)TX_SRC_RDY_N和TX_DST_RDY_N都有效的時候,代表發(fā)送的數(shù)據(jù)TX_D為有效數(shù)據(jù)。
這一點從代碼的端口定義可見等價關(guān)系:

同理,接收情況也是如此!
按照streaming用戶接口的時序圖:

當(dāng)valid有效的時候,接收的數(shù)據(jù)才有效,因此,我們查看接收數(shù)據(jù)時刻應(yīng)該在:

我們通過放大,來看看,這兩個時刻上的數(shù)據(jù)是否一致?


可見,都是d5e6,而且后續(xù)數(shù)據(jù)也一致,可見,發(fā)送與接收的通道是沒有問題的,至少從仿真上看是沒有問題的。(這里提醒一句,這里對齊的時鐘肯定是用戶時鐘,這里沒有拉出來。)
從s_axi_tx_valid到s_axi_rx_valid有效的延遲時間,大家也可以算下,延遲了多久?(大概40多個user_clk 時鐘周期了)。

寫在最后

熬了個夜,學(xué)習(xí)了下aurora的理論以及到現(xiàn)在仿真了下streaming數(shù)據(jù)格式的aurora例子程序,由于疫情原因,還沒有能到學(xué)校,因此上板是不可能了,也許再也不可能了,只能等到公司了。
下面會給出本例子程序的整個工程。

工程分享

提取碼:03ii
aurora streaming工程例子工程分享

參考資料

Aurora IP核例子程序

Aurora數(shù)據(jù)手冊

交個朋友

交個朋友,共同進步

總結(jié)

以上是生活随笔為你收集整理的FPGA设计心得(5)Aurora 例子工程分析与仿真实例分析(streaming版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。