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

举报
李锐博恩 发表于 2021/07/15 02:24:23 2021/07/15
【摘要】 文章目录 背景例子工程预览例子程序用户模块逻辑分析收(CHECK)发(GEN) 例子程序仿真文件分析写在最后工程分享参考资料交个朋友 背景 熬夜写完了上两篇博客: Aurora IP core 的理论学习记录 Aurora IP core 的定制详情记录 到这一篇应该就是分析例子程序了,最重要地还是通过仿真来认识Aurora通信。 Aurora IP...

背景

熬夜写完了上两篇博客:
Aurora IP core 的理论学习记录
Aurora IP core 的定制详情记录
到这一篇应该就是分析例子程序了,最重要地还是通过仿真来认识Aurora通信。
Aurora IP核的定制,基本都是默认的,为了简单起见,GT Selection中选择了一个通道(lane)。
文章末尾会分享工程文件!

例子工程预览

由于本IP核定制选择了:
在这里插入图片描述在这里插入图片描述因此,程序加入了一些debug的IP核例化。
如下:
在这里插入图片描述
而对于我们要仿真而言,这些都是没有必要的。
对于我们用户应用来说,最最重要的模块为:
在这里插入图片描述
一个check,一个gen。
在这里插入图片描述
gen代表发数据的模块,而check则为收数据的模块。
如数据手册:
在这里插入图片描述而如何对二者进行仿真呢?
形成一个回环,示意图如下:
在这里插入图片描述一方发,另一方收,反之亦然!
而testbench的作用就是将二者联系起来:
下图清晰说明:
在这里插入图片描述例子程序中带有仿真文件:
在这里插入图片描述
可见,例化了两次例子程序,就是为了将一方的tx送给另一方的rx,同时,另一方的tx送入一方的rx,形成一个闭环。

例子程序用户模块逻辑分析

收(CHECK)

我们知道收模块与aurora IP streaming用户接口之间的关系是:

在这里插入图片描述
因此,用户接口很简单,就两个信号进来就好,m_axi_rx_data以及m_axi_rx_valid即可,valid有效,则data数据为有效数据,至于收到的数据做什么处理,随你!例子程序的处理,我也不想深究,收过来按照自己的需求搞就完事了。

给出源码:


`timescale 1 ns / 1 ps
`define DLY #1

module aurora_8b10b_streaming_FRAME_CHECK
( // User Interface RX_D, RX_SRC_RDY_N, // System Interface USER_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 registers

reg   [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 ready
  assign reset_c = RESET;

// SLACK registers

always @ (posedge USER_CLK)
begin
  RX_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 asserted assign  data_valid_c =   !RX_SRC_RDY_N_SLACK; //generate expected RX_D using LFSR always @(posedge USER_CLK) if(reset_c) begin data_lfsr_r <=  `DLY 16'hD5E6;  //random seed value end else if(CHANNEL_UP) begin if(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]}; end else begin data_lfsr_r <=  `DLY 16'hD5E6;  //random seed value end 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 port assign  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 logic always @(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) begin if(&err_count_r) err_count_r <=  `DLY err_count_r; else if(data_err_detected_r) err_count_r <=  `DLY err_count_r + 1; end
	else begin 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 output assign  ERR_COUNT =   err_count_r[1:8];

endmodule 
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

仿真预告:

在这里插入图片描述
这便是收到的数据。

对了,程序中的这个输入变量:
RX_SRC_RDY_N
就是valid的反而已:

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

  
 
  • 1
  • 2
  • 3

其他的不言而喻!

发(GEN)

发要比收需要的信号多一个,那就是ready信号,具体为:

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

  
 
  • 1
  • 2
  • 3
  • 4

根据streaming格式的关系:
在这里插入图片描述我们用户逻辑需要得到一个ready有效信号,然后置位valid的同时,发送有效数据data。
在这里插入图片描述
例子发送程序根据lsfr产生随机数据发送:

 //______________________________ 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 data always @(posedge USER_CLK) if(reset_c) begin data_lfsr_r <=  `DLY 16'hABCD;  //random seed value TX_SRC_RDY_N <=  `DLY 1'b1; end else if(!TX_DST_RDY_N) begin 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]}; TX_SRC_RDY_N <=  `DLY 1'b0; end //Connect TX_D to the DATA LFSR register assign  TX_D =   {1{data_lfsr_r}};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

不需要多言!
下面给出完整发送程序:


`timescale 1 ns / 1 ps
`define DLY #1

module aurora_8b10b_streaming_FRAME_GEN
( // User Interface TX_D, TX_SRC_RDY_N, TX_DST_RDY_N, // System Interface USER_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)
  begin if(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; else channel_up_cnt <= `DLY 5'd0;
  end assign dly_data_xfer = (&channel_up_cnt); //Generate RESET signal when Aurora channel is not ready
  assign 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 data always @(posedge USER_CLK) if(reset_c) begin data_lfsr_r <=  `DLY 16'hABCD;  //random seed value TX_SRC_RDY_N <=  `DLY 1'b1; end else if(!TX_DST_RDY_N) begin 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]}; TX_SRC_RDY_N <=  `DLY 1'b0; end //Connect TX_D to the DATA LFSR register assign  TX_D =   {1{data_lfsr_r}}; endmodule


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

仿真预警:

在这里插入图片描述这边是发送数据。

例子程序仿真文件分析

先给出仿真文件(然后在简单分析仿真文件):


`timescale 1 ns / 1 ps

module 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; initial begin gts_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____________________________ initial reference_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; initial reference_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; initial drp_clk_r = 1'b0; always #(DRP_CLOCKPERIOD / 2) drp_clk_r = !drp_clk_r; initial init_clk_p = 1'b0; always #(INIT_CLOCKPERIOD / 2) init_clk_p = !init_clk_p; assign init_clk_n =  !init_clk_p; //____________________________Resets____________________________ initial begin reset_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)
);



  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237

分为几个部分,

  • 端口声明:
    一般而言,输入声明为reg类型,输出为wire。
    例如:
 //GT Serial I/O
wire rxp_1_i; 
wire rxn_1_i; wire txp_1_i; 
wire txn_1_i; 

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

但也不尽然如此,例如输入的差分时钟,我们就可以将其中一个声明为reg,至于差分的另一半,声明为wire,之后通过取反操作来实现:

 //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;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 产生时钟
    时钟较多,差分时钟产生方法是先生成p时钟或者n时钟,之后取反得到另一方:
//____________________________Clocks____________________________ initial reference_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; initial reference_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; initial drp_clk_r = 1'b0; always #(DRP_CLOCKPERIOD / 2) drp_clk_r = !drp_clk_r; initial init_clk_p = 1'b0; always #(INIT_CLOCKPERIOD / 2) init_clk_p = !init_clk_p; assign init_clk_n =  !init_clk_p; //____________________________Resets____________________________ initial begin reset_i = 1'b1; #1000 reset_i = 1'b0; end

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 例化待测试模块
    例化两次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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

双方如何形成一个通路的呢?
1发接到2的收,2发接到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;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

由于数据是自己的gen模块以及产生的,故在设计文件中设计即可。
下面仿真实践,看看仿真图吧!

先宏观地看第一个仿真图:
在这里插入图片描述
可见,一方(简称partner1)和另一方(简称partner2)串行数据完全一致,理所当然如此,因为二者是直接相连的回环。
当然,这种串行数据我们是看不懂的,我们要看的是用户逻辑,模块check以及gen的数据,继续把二者拉出来仿真:
在这里插入图片描述
从partner1的gen中提取出valid,data,ready信号;
再从partner2的check中提取出valid和data信号。
二者构成一个通路。
在这里插入图片描述
上图中,TX_D就是s_axi_tx_data,而TX_DST_RDY_N取反就是s_axi_tx_tready,同理,TX_SRC_RDY_N取反是s_axi_tx_valid,故而,当TX_SRC_RDY_N和TX_DST_RDY_N都有效的时候,代表发送的数据TX_D为有效数据。
这一点从代码的端口定义可见等价关系:
在这里插入图片描述
同理,接收情况也是如此!
按照streaming用户接口的时序图:
在这里插入图片描述
当valid有效的时候,接收的数据才有效,因此,我们查看接收数据时刻应该在:
在这里插入图片描述
我们通过放大,来看看,这两个时刻上的数据是否一致?
在这里插入图片描述
在这里插入图片描述
可见,都是d5e6,而且后续数据也一致,可见,发送与接收的通道是没有问题的,至少从仿真上看是没有问题的。(这里提醒一句,这里对齐的时钟肯定是用户时钟,这里没有拉出来。)
从s_axi_tx_valid到s_axi_rx_valid有效的延迟时间,大家也可以算下,延迟了多久?(大概40多个user_clk 时钟周期了)。

写在最后

熬了个夜,学习了下aurora的理论以及到现在仿真了下streaming数据格式的aurora例子程序,由于疫情原因,还没有能到学校,因此上板是不可能了,也许再也不可能了,只能等到公司了。
下面会给出本例子程序的整个工程。

工程分享

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

参考资料

Aurora IP核例子程序

Aurora数据手册

交个朋友

交个朋友,共同进步

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/106067827

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。