Get started with Aurora 8B/10B IP core in one day (4) ---- learn from the official routine of the Streaming interface

        Xilinx's technical ecology is very good. Basically, all the commonly used IP cores have official routines (example design) for developers to learn. The routine begins to learn how to use this IP core specifically.

        Series Summary: Getting Started with Aurora 8B/10B IP Core in One Day----Summary (Direct Link)


1. IP core customization and generation of official routines

        First create a new project that does nothing except generate the Aurora 8B/10B IP core.

        The customization process of the IP core is as follows:

1.1. The first page configuration: physical layer and link layer information selection

        

Physical Layer Physical Layer:

        Lane Width: Link bit width, optional 2 or 4, in Bytes (here we choose 4bytes in order to lower the user clock to facilitate subsequent clock constraints)

        Line Rate: Line rate, the range is 0.5~6.25Gbps, this is just according to the project needs, choose 3.125Gbps

        GT Refclk: The reference clock of the serial transceiver GT, according to the actual situation of the board, we choose 125M here

        INIT clk: Initialize the clock. When the GT is reset, user_clk stops working. It is recommended that the INIT CLK clock frequency is lower than the GT reference clock, and the default 50M is directly selected.

        DRP clk: dynamic reconfiguration clock, this function is not used much, just press the default 50M

Link Layer Link Layer:

        Dataflow Mode: data flow mode, optional full-duplex/receive only/send only, we choose full-duplex mode here

        Interface: Framing/streaming optional. This article is the streaming interface

        Flow Control: flow control, not optional in streaming interface mode

        Back Channel: can only be selected in simplex mode (sidebands/timer optional)

        Scrambler/Descrambler: Code wrapping/unwrapping, not selected here

        Little Endian Support: Check the little endian mode, the small segment mode corresponds to the writing habit of [31:0], and the big endian mode corresponds to the writing habit of [0:31]

Debug and Control: Debug And Control:

        Provides debugging IO cores such as ILA and VIO and some other status indicators to monitor the running status of the IP. For the convenience of testing, we do not select such debugging interfaces for the time being.

1.2. The second page configuration: corresponding to the physical location selection of the GT transceiver

        Here, you can choose according to the actual situation of GT on your FPGA chip. We just choose a channel for simulation testing:

1.3. The third page configuration: the location of shared logic

        For example, logic such as clock and reset, whether it is in the core or in the example project (most IP core Xilinx will provide routines for reference). It is recommended to set the shared logic in the official routine, so that our subsequent use of the IP core can be directly modified on the basis of the official routine.

1.4. Generation of the official routine Example Design

        After the IP core is customized and synthesized, the official routine Example Design can be generated:

2. Official routine analysis

        The analysis of the official routine mainly refers to the generated source code and "PG046: Aurora 8B/10B v11.1 LogiCORE IP Product Guide". Through the above information, we can grasp the use of IP core and understand the general composition of the routine.

2.1, the composition of the official routine

        Let's first look at the logical hierarchy of generated routine resources:

        The level of design resources is not very obvious. Let's call out the block diagram and take a look:

       

        This basically makes it clear:

  • support module: core, including a series of operations such as instantiation of IP, GT, etc.; this part does not need to be modified in our application later
  • frame_gen: data generation module, which uses LFSR to generate pseudo-random sequences; this part can be replaced by our data input module in our application later (it is recommended to add FIFO, so that the code is more reusable)
  • frame_check: data verification module, which checks the received data to verify the correctness of the transmission; this part can be replaced with our data check module or deleted in our application later
  • LL_AXI: LL bus to AXI bus (it is said that the original interface of this routine is the LL interface. Later, in order to promote the AXI bus, this routine adds a bus conversion module directly on the basis of the original code)
  • AXI_LL: AXI bus to LL bus, the reason is the same as above

        The content of the simulation part is easy to understand according to the hierarchy - the routine is called twice. Based on Xilinx's consistent urine, it's easy to guess that this is another loopback test.

        In fact, you can also see one or two from the manual:

  • Testbench instantiates two routines 
  • After routine 1 generates data, it is sent to the detection module of routine 2 through Aurora, and the results are fed back to Testbench
  • After routine 2 generates data, it is sent to the detection module of routine 1 through Aurora, and the results are fed back to Testbench

2.2, Support module (IP core instantiation core module)

        Without further ado, let's take a look at the composition of the Support module: 

         It is not difficult to see from the composition that the main function of the Support module is to instantiate the aurora IP core and package the clock, reset and other signals together. So we don't need to have a detailed understanding of the internal structure of the Support module, just look at its external interface and it can almost be used.

        Submodules under the Support module:

  • clock_module: clock processing generation module
  • support_reset_logic_i: reset logic generation block
  • gt_common_support: Clocks related to GT transceivers generate other

2.3. Data generation module (send)

        As mentioned above, as long as the data generation module is replaced with our own file (it may also be necessary to change the data inspection module (receive)), the secondary creation of the official routine can be realized, thus completing the utilization of Aurora IP. Then we naturally need to explore its source code.

        The complete code is as follows:

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

module aurora_8b10b_0_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:31]     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    =   {2{data_lfsr_r}};
   
endmodule

       

        There is not much code, let's disassemble it piece by piece:

2.3.1. Port

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

// System Interface
input              USER_CLK;
input              RESET; 
input              CHANNEL_UP;

        

  •         TX_DST_RDY_N: Equivalent to s_axi_tx_tready, when set, indicates that the IP core is ready to send data at this time
  •         TX_SRC_RDY_N: Equivalent to s_axi_tx_tvalid, when set, indicates that the user is ready to send data through the IP core
  •         TX_D: Equivalent to s_axi_tx_data, the data to be sent
  •         USER_CLK: User clock, all user operations on the IP core need to be under this clock
  •         RESET: reset signal, generated by the support module, it may be a hard reset of the GT, or a soft reset caused by a transmission error
  •         CHANNEL_UP: Set to indicate that the corresponding channel initialization is completed at this time, and it is in a normal working state

        Let's take a look at the picture comparison and understanding:

 2.3.2, waiting for initialization

  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;

        If CHANNEL_UP has not yet been up, then channel_up_cnt will be all 0, and dly_data_xfer will be 0, so the statement assign reset_c = RESET || ! dly_data_xfer is always established, reset_c is always 1, so it is always in the reset state.

        When CHANNEL_UP is up, channel_up_cnt takes a certain amount of time to count to 5'b11111, and then dly_data_xfer is 1, so at this time assign reset_c = RESET || !dly_data_xfer is equivalent to assign reset_c = RESET, that is, RESET controls the reset_c signal. And RESET is generally in an invalid reset state before CHANNEL_UP is up, so the channel enters the normal working mode at this time.

2.3.3, the use of LFSR

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    =   {2{data_lfsr_r}};

        For LFSR, please refer to: FPGA-implemented linear feedback shift register LFSR

        The seed loaded at this time is 16'hABCD.

2.4. Data Check Module (Accept and Check)

        Since the data is sent, it will be received. At the same time, since it is a routine, then I have to inspect the goods after receiving your goods, right? (Check the correctness of the sending and receiving process)?

        The complete code of the check module is as follows:

module aurora_8b10b_0_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:31]     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:31]     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:31]     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 = {2{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 

       

        Code continues to split, go!

2.4.1, ports and intermediate variables

// User Interface
input   [0:31]     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:31]     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:31]     data_lfsr_concat_w;
wire               data_valid_c;   
wire               data_err_detected_c;
reg                data_err_detected_r;
  •         RX_SRC_RDY_N: Equivalent to m_axi_rx_tvalid, when set, indicates that the data on the bus is a valid signal
  •         RX_D: equivalent to m_axi_rx_tdata, data received from the bus
  •         USER_CLK: User clock, all user operations on the IP core need to be under this clock
  •         RESET: reset signal, generated by the support module, it may be a hard reset of the GT, or a soft reset caused by a transmission error
  •         CHANNEL_UP: Set to indicate that the corresponding channel initialization is completed at this time, and it is in a normal working state
  •         ERR_COUNT: Count errors during reception

       

        Let's take a look at the picture comparison and understanding:

2.4.2, port registration and LFSR data generation

//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 = {2{data_lfsr_r}};

        assign reset_c = RESET. The reset signal is directly linked to RESET which is not much to say.

always @ (posedge USER_CLK)
        begin
                RX_D_SLACK          <= `DLY RX_D;
                  RX_SRC_RDY_N_SLACK  <= `DLY RX_SRC_RDY_N;
        end

        Here, the input data and valid signals are registered for a beat to improve the timing. In fact, most of the routines of Xilinx are processed in this way.

//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 = {2{data_lfsr_r}};

        This section is to generate the LFSR data corresponding to the sending module after the channel is normal, so that the subsequent comparison can verify whether the communication process is correct.

2.4.3. Data correctness verification

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

        When the received receipt is inconsistent with the data generated by itself through the LFSR, the error indication signal is pulled high to indicate that a transmission error has occurred at this time. In order to eliminate the burr, this signal is also registered for a beat.

        If the error indication signal is high, the error indication counter is +1.

3. Simulation results

        Perform functional simulation directly until it stops automatically, first look at the overall block diagram:

        It can be seen that when more than 50 us, the channels of the two instantiated modules have established a normal connection (red box), and then the simulation ends after a period of time. As for other things, all kinds of clock signals are up and reset is normal, so there should be no problem with simulation.

        Next, let's look at the first loopback: the first module sends + the second module checks, just look at the waveforms of the following two modules (one send and one receive):

        There are too many signals, we cut out some, and only keep the key clock and the data sent and checked.

        Data sent by the sender:

        Due to space limitations, only the first three are intercepted: d5e6d5e6----eaf3eaf3----f579f579.

        The data received by the receiver:

        Due to space limitations, only the first three are intercepted: d5e6d5e6----eaf3eaf3----f579f579.

        It can be seen that the received data is consistent with the sent data, which proves that the first loopback of the data channel is successful.

        The configuration of the second loopback channel - the second module sends + the first module check, only look at the waveforms of the following two modules (one send and one receive):

         Referring to the above, look directly at the data of the sender and receiver:

         It can be seen that the situation is consistent with the above, which proves that the second loopback is also successful.

4. Other

4.1, some problems

4.1.1. Simulation speed

        The simulator that comes with vivado is really slow for simulation. And the simulation speed of the Aurora IP core seems to be related to the selected device. At the beginning, I directly generated the official routine by pressing the FPGA model (A7) of the development board in my hand. As a result, the channel_up signal was not pulled high all the time. I waited, waited, waited, and almost crashed for me.

        Finally, it is found that the simulation time actually takes 1ms, as follows:

        In order to verify whether it is the influence of the device simulation model, a K7 device and a V7 device were selected to regenerate and simulate the IP core, and the channel_up time is as follows.

        K7 (more than 50 us):

         V7 (also more than 50 us):

        Therefore, if your simulation time is too long, it is recommended to try another device first (it is possible that the simulation model gap is really so big).

4.1.2. Relationship between line rate and user clock

        The user clock is the clock fed back to us by the IP core, and all our data operations should be in this clock domain.

        User clock * data bit width / 0.8 = line rate. Dividing by 0.8 is because there is a 20% encoding overhead in the 8B/10B encoding method, and the number of lanes has nothing to do with the line rate, because in fact a lane is a line, that is to say, the line rate is actually the lane rate.

        Substituting the data we tested above, the line rate is 3.125Gbps, and the data bit width is 32 bits, the user data should be calculated as: 3.125Gbps * 0.8 / 32 = 78.125MHz, that is, the clock cycle should be 1/78.125 = 12.8ns.

        Let's measure it in the simulation interface, the period of the user clock, the result is as follows: 12.8ns, which is consistent with the theory.

 4.2. Summary

  • It can be seen that the Aurora 8B/10B IP core is relatively easy to use. On the basis of the official routine, the sending and receiving modules are slightly modified, and they can be used directly for simple use.

  • In the next section, let's learn the example design (Framing interface) of the Aurora IP core together.

  • It is not easy to create. If this article is helpful to you, please like, comment and bookmark more . Your support is the biggest motivation for me to keep updating!

        

        

Guess you like

Origin blog.csdn.net/wuzhikaidetb/article/details/123814910