基于GTX的64B66B编码的自定义接收模块(高速收发器二十二)

news2024/11/14 19:08:04

  点击进入高速收发器系列文章导航界面


1、自定义PHY顶层模块

  前文设计了64B66B自定义PHY的发送模块,本文完成自定义PHY剩余的模块的设计,整体设计框图如下所示。

  其中phy_tx是自定义PHY的发送数据模块,scrambler是加扰模块,rx_slipbit是接收端手动对齐模块,descrambler是解扰模块,phy_rx是自定义PHY的接收数据模块。其中加扰和解扰直接使用官方示例工程的模块。

在这里插入图片描述

图1 整体设计框图

  当接收数据同步完成之后,接收数据模块才会解码接收的数据,转换成axi_stream流数据输出给用户。

  PHY顶层模块的参考代码如下所示:

    //例化PHY接收对齐模块
    phy_rx_slipbit u_phy_rx_slipbit(
        .rx_clk     ( rx_clk        ),//系统时钟信号;
        .rx_rst	    ( rst           ),//系统复位信号,高电平有效;
        .header     ( rx_header     ),//头部2位数据,等于2'b01或者2'b10时有效;
        .header_vld ( rx_header_vld ),//头部数据有效指示信号,高电平有效;
        .slipbit    ( rx_slipbit    ),//滑块信号,高电平有效;
        .sync       ( sync          ) //同步成功指示信号,高电平有效;
    );

    //解扰模块;
    descrambler u_descrambler_0(
        .clk		        ( rx_clk            ),//系统时钟信号;
        .rst 	            ( rx_rst            ),//系统复位信号,高电平有效;
        .rx_header_i        ( rx_header         ),//2位的同步头数据,不需要进行解扰;
        .rx_header_vld_i    ( rx_header_vld     ),//同步头有效指示信号,高电平有效;
        .rx_data_i          ( rx_data           ),//需要解码的接收数据;
        .rx_data_vld_i      ( rx_data_vld       ),//接收数据有效指示信号;
        .rx_header_o        ( rx_header_de      ),//2位的同步头数据,不需要进行解扰;
        .rx_header_vld_o    ( rx_header_vld_de  ),//同步头有效指示信号,高电平有效;
        .rx_data_o          ( rx_data_de        ),//解扰后的输出数据;
        .rx_data_vld_o      ( rx_data_vld_de    ) //解扰后的输出数据有效指示信号;
    );

    //例化PHY接收模块;
    phy_rx  u_phy_rx(
        .rx_clk		    ( rx_clk	        ),//系统时钟信号;
        .rx_rst	        ( rx_rst	        ),//系统复位信号,高电平有效;
        .sync           ( sync              ),//同步成功指示信号,高电平有效;
        .rx_data        ( rx_data_de        ),//GTX的接收数据信号;
        .rx_data_vld    ( rx_data_vld_de    ),//GTX的接收数据有效指示信号;
        .rx_header      ( rx_header_de      ),//GTX的接收头部数据信号;
        .rx_header_vld  ( rx_header_vld_de  ),//GTX的接收头部数据有效指示信号;
        .m_axi_data     ( m_axi_data        ),//数据信号;
        .m_axi_keep     ( m_axi_keep        ),//数据掩码信号;
        .m_axi_last     ( m_axi_last        ),//一帧数据的结束数据;
        .m_axi_valid    ( m_axi_valid       ) //数据有效指示信号;
    );

    //例化PHY发送模块;
    phy_tx u_phy_tx(
        .tx_clk         ( tx_clk        ),//系统时钟信号;
        .tx_rst         ( tx_rst        ),//系统复位信号,高电平有效;
        .s_axi_valid    ( s_axi_valid   ),//数据有效指示信号,高电平有效;
        .s_axi_last     ( s_axi_last    ),//帧结束指示信号,高电平有效;
        .s_axi_data     ( s_axi_data    ),//数据信号;
        .s_axi_keep     ( s_axi_keep    ),//数据掩码信号;
        .s_axi_ready    ( s_axi_ready   ),//接收数据应答信号;
        .tx_data        ( tx_data_0       ),//GTX需要发送的数据;
        .tx_header      ( tx_header_0     ),//GTX需要发送的头部数据;
        .tx_sequence    ( tx_sequence_0   ) //GTX外部计数器;
    );

    //通道0的加扰模块;
    scrambler u_scrambler_0(
        .clk		        ( tx_clk            ),//系统时钟信号;
        .rst 	            ( tx_rst            ),//系统复位信号,高电平有效;
        .tx_header_i        ( tx_header_0       ),//2位的同步头数据,不需要进行加扰;
        .tx_sequence_i      ( tx_sequence_0     ),//外部计数器;
        .tx_data_i          ( tx_data_0         ),//需要加码的接收数据;
        .tx_header_o        ( tx_header         ),//2位的同步头数据,不需要进行接扰;
        .tx_sequence_o      ( tx_sequence       ),//外部计数器;
        .tx_data_o          ( tx_data           ) //加扰后的输出数据;
    );

2、接收端同步模块设计

  该模块通过接收到的同步头(rx_headr)的状态去拉高slipbit,调节串并转换的起始位置,达到接收数据对齐的目的。

  当接收通道复位完成之后,开始检测接收到的同步头(rx_headr)的状态,如果rx_headr不等于2’b01或者2’b10,则表示接收的数据没有对齐,把slipbit信号拉高一个时钟,等待32个时钟周期后,再次检测rx_headr的状态,直到连续64个时钟rx_headr均为2’b01或者2’b10时,表示同步完成。

  上述是官方示例工程接收端同步数据的思路,以这个方式设计模块或者直接使用官方示例工程的同步模块,在实际上板测试时,可能会存在一些问题。

  我在设计该模块时,还增加了一个条件,正常情况下,一帧数据应该只有在帧头和帧尾才会存在控制位,其余时间全是数据位。

  因此rx_headr应该不会连续三个时钟为2‘b10,因此如果检测到连续三个时钟均为2’b10,则认为同步失败,需要继续拉高slipbit来调整串并转换的起始位置。

  下面是该模块的具体设计,首先是端口信号,sync为高电平表示接收的数据同步完成,之后接收数据模块才能正常工作。计数器cnt用于计数连续检测正确数据的个数,计数器计数到最大值时,表示同步完成。

    //该计数器用于记录连续检测正确数据的个数,达到指定个数时表示同步成功;
    always@(posedge rx_clk)begin
        if(rx_rst)begin//
            cnt <= 'd0;
        end
        else if(slipbit)begin//通过滑块信号进行同步时,表示检测到错误数据,计数器清零。
            cnt <= 'd0;
        end
        else if(add_cnt)begin
            if(end_cnt)
                cnt <= 'd0;
            else
                cnt <= cnt + 'd1;
        end
    end
    
    //头部数据有效且是控制帧或者数据帧且不处于同步过程中;
    assign add_cnt = (header_vld && ((header == 2'b01) || (header == 2'b10)) && (~slipbit_flag));
    assign end_cnt = add_cnt && cnt == SH_CNT_MAX - 1;//连续采集指定个正确的数据;

  当不处于同步调整状态,且接收的有效同步头是错误时,表示同步失败,拉高slipbit调整串并转换的起始位置。

    //当头部数据有效指示信号位高电平且头部是错误数据并且不处于同步过程中时,表示检测的数据有误。
    assign header_invld = (header_vld && (header != 2'b01) && (header != 2'b10) && (~slipbit_flag));
    
    //当采集数据有误时,将滑块信号拉高,进行校准;
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            slipbit <= 1'b0;
        end
        else begin//当检测的信号有错误且此时并没有进行校正时有效;
            slipbit <= ((~slipbit) && (header_invld || syc_error));
        end
    end

  每次slipbit拉高之后,需要等待32个时钟之后,才能进行下次检测,因此需要一个计数器slipbit_cnt来计数这个状态slipbit_flag。

    //正在校准的指示信号,初始值位0,当滑块信号位高电平时开始计数,当计数器计数结束时拉低;
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            slipbit_flag <= 1'b0;
        end
        else if(end_slipbit_cnt)begin//当计数器拉高时有效;
            slipbit_flag <= 1'b0;
        end
        else if(slipbit)begin//滑块信号有效时拉高;
            slipbit_flag <= 1'b1;
        end
    end
    
    //记录滑块信号拉高后的一段时间,这段时间内IP会对采集位置进行调整,期间不需要判断输出头部数据的正确性;
    always@(posedge rx_clk)begin
        if(rx_rst)begin//
            slipbit_cnt <= 'd0;
        end
        else if(add_slipbit_cnt)begin
            if(end_slipbit_cnt)
                slipbit_cnt <= 'd0;
            else
                slipbit_cnt <= slipbit_cnt + 'd1;
        end
    end
    
    assign add_slipbit_cnt = (slipbit || slipbit_flag);//当滑块信号或者指示信号有效时计数;
    assign end_slipbit_cnt = add_slipbit_cnt && slipbit_cnt == SLIPBIT_GAP - 1;//当计数到指定时钟个数时清零;

  生成同步完成指示信号sync,当slipbit为高电平时,表示在调节同步的位置,此时sync为低电平。当计数器cnt计数结束时,表示同步完成,此时sync拉高。

    //生成同步完成指示信号。
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            sync <= 1'b0;
        end
        else if(slipbit)begin//当滑块信号位高电平时,表示检测到错误数据,表示当前数据没有同步成功;
            sync <= 1'b0;
        end
        else if(end_cnt)begin//当连续检测到指定个正确数据时,表示同步成功;
            sync <= 1'b1;
        end
    end

  最后将输入信号通过两组移位寄存器暂存,如果同步后的有效同步头rx_headr连续三个时钟均为2’b10,则表示同步失败,将sync_error拉高,会重新调整同步位置。

    //将头部数据和头部数据有效指示信号延迟两个时钟。
    always@(posedge rx_clk)begin
        {header_r[1],header_r[0]} <= {header_r[0],header};
        header_vld_r <= {header_vld_r[0],header_vld};
    end

    //检测头部数据,防止出现连续的2'b10,从而导致同步错误。
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            syc_error <= 1'b0;
        end
        else begin//当不处于同步调整状态下时,连续三个时钟检测到头部数据为2'b10时拉高,表示接收的同步数据错误,需要继续调整同步。
            syc_error <= (~slipbit_flag) && (header == 2'b10) && (header_r[0] == 2'b10) && (header_r[1] == 2'b10) && header_vld && (&header_vld_r);
        end
    end

3、接收数据模块设计

  64B66B编码的接收模块设计逻辑很简单,只需要从指定起始位和停止位之间解析出数据输出到用户的axi_stream端口即可。

  首先是端口信号列表,包含解扰后的输入数据、同步头、同步完成指示信号SYNC,还有输出给用户的axi_stream主机端口信号,因为模块内部不包含FIFO等缓冲结果,因此不需要从机提供应答信号,直接将解析的数据输出。

  通过一组移位寄存器将输入信号暂存,便于后续逻辑使用。当接收端的数据同步完成,同步头为2’b10且接收第一个数据的第一个字节数据为8’h78时,sof_flag拉高表示检测到帧头。

    //当检测到帧头时拉高,其余时间为低电平。
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            sof_flag <= 1'b0;
        end
        else if(sync)begin//检测到帧头时拉高;
            sof_flag <= (rx_header_vld && (rx_header == 2'b10) && rx_data_vld && (rx_data[7:0] == 8'h78));
        end
    end

  而帧尾有8种情况,当eof_flag拉高时,表示检测到帧尾,同时需要记录帧尾包含几个字节的有效数据,与输出给用户的尾端数据掩码信号有关。

  Rx_flag为高电平表示正在接收一帧数据,当检测到帧头时拉高,输出用户最后一帧的最后一个数据时拉低,其余时间保持不变。

    //接收数据标志信号,初始值为0,当检测到起始帧时拉高,检测到结束帧时拉低;
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            rx_flag <= 1'b0;
        end
        else if(m_axi_last)begin//当一帧数据接收完成时拉低;
            rx_flag <= 1'b0;
        end
        else if(sof_flag)begin//当检测到帧头时拉高;
            rx_flag <= 1'b1;
        end
    end

  然后是生成用户数据,由于停止位的最低字节不是数据,因此在拼接时需要舍弃。因为GTX的数据是小端对齐的,而输出给用户的数据采用大端对齐,因此输出的数据需要将高低字节数据转换。

//生成用户数据信号;
    always@(posedge rx_clk)begin
        if(rx_rst)begin//初始值为0;
            m_axi_data_r <= 'd0;
        end
        else if(eof_flag)begin
            m_axi_data_r <= {rx_data_r[0][15:8],rx_data_r[1][63:8]};
        end
        else if(eof_flag_r)begin
            m_axi_data_r <= {rx_data_r[0][15:0],rx_data_r[1][63:16]};
        end
        else if(rx_flag)begin
            m_axi_data_r <= {rx_data_r[0][7:0],rx_data_r[1][63:8]};
        end
    end

    //将输出数据大小端翻转;
    assign m_axi_data = {m_axi_data_r[7:0],m_axi_data_r[15:8],m_axi_data_r[23:16],m_axi_data_r[31:24],m_axi_data_r[39:32],m_axi_data_r[47:40],m_axi_data_r[55:48],m_axi_data_r[63:56]};

  之后生成用户数据掩码,初始值8’hff,表示所有数据均有效。根据帧尾的有效字节数确定尾端掩码的数值,比如帧尾有1字节有效数据时,则用户数据的尾端所有字节的数据均有效,为8’hff,其余七种情况需要全部考虑。

  该模块的设计到此结束,用户在设计时只需要注意帧尾有效字节数,与尾端掩码的对应关系即可,其余设计都比较简单。

4、仿真PHY顶层模块

  加扰和解扰模块使用官方示例工程相关模块,但在模块内部添加了对其他信号的延时设计,确保数据对齐,加扰和解扰模块参考代码如下所示。

  加扰模块参考代码:

//--###############################################################################################
//--#
//--# File Name		: scrambler
//--# Designer		: 数字站
//--# Tool			: Vivado 2021.1
//--# Design Date	: 2024.4.3
//--# Description	: 通过x^58+x^39+1对接收数据进行加扰。
//--# Version		: 0.0
//--# Coding scheme	: GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module scrambler #(
    parameter   TX_DATA_WIDTH           =   64		         //需要加扰的数据位宽;
)(
    input									clk		        ,//系统时钟信号;
    input									rst 	        ,//系统复位信号,高电平有效;

    input       [1 : 0]                     tx_header_i     ,//2位的同步头数据,不需要进行加扰;
    input       [6 : 0]                     tx_sequence_i   ,//外部计数器;
    input       [TX_DATA_WIDTH - 1 : 0]     tx_data_i       ,//需要加码的接收数据;

    output  reg [1 : 0]                     tx_header_o     ,//2位的同步头数据,不需要进行接扰;
    output  reg [6 : 0]                     tx_sequence_o   ,//外部计数器;
    output  reg [TX_DATA_WIDTH - 1 : 0]     tx_data_o        //加扰后的输出数据;
);
    integer                                 i               ;
    reg         [57 : 0]                    poly            ;
    reg         [57 : 0]                    scrambler       ;
    reg         [TX_DATA_WIDTH - 1 : 0]     tempData        ;
    reg                                     xorBit          ;
    
    always@(scrambler,tx_data_i)begin
        poly = scrambler;
        for(i=0 ; i<=(TX_DATA_WIDTH-1) ; i=i+1)begin
            xorBit = tx_data_i[i] ^ poly[38] ^ poly[57];
            poly = {poly[56:0],xorBit};
            tempData[i] = xorBit;
        end
    end

    //加扰输出数据;
    always@(posedge clk)begin
        if (rst)begin
            tx_data_o <= 'h0;
            scrambler <= 58'h155_5555_5555_5555;
        end
        else if(tx_sequence_i)begin
            tx_data_o <= tempData;
            scrambler <= poly;
        end
    end

    //加码数据相对于其他信号延迟一个时钟,为了对齐,把其他信号延迟一个时钟后输出。
    always@(posedge clk)begin
        tx_header_o <= tx_header_i;
        tx_sequence_o <= tx_sequence_i;
    end

endmodule

  解扰模块参考代码:

//--###############################################################################################
//--#
//--# File Name		: descrambler
//--# Designer		: 数字站
//--# Tool			: Vivado 2021.1
//--# Design Date	: 2024.4.3
//--# Description	: 通过x^58+x^39+1对接收数据进行解扰。
//--# Version		: 0.0
//--# Coding scheme	: GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module descrambler #(
    parameter   RX_DATA_WIDTH           =   64		         //需要解扰的数据位宽;
)(
    input									clk		        ,//系统时钟信号;
    input									rst 	        ,//系统复位信号,高电平有效;

    input       [1 : 0]                     rx_header_i     ,//2位的同步头数据,不需要进行解扰;
    input                                   rx_header_vld_i ,//同步头有效指示信号,高电平有效;
    input       [RX_DATA_WIDTH - 1 : 0]     rx_data_i       ,//需要解码的接收数据;
    input                                   rx_data_vld_i   ,//接收数据有效指示信号;

    output  reg [1 : 0]                     rx_header_o     ,//2位的同步头数据,不需要进行解扰;
    output  reg                             rx_header_vld_o ,//同步头有效指示信号,高电平有效;
    output  reg [RX_DATA_WIDTH - 1 : 0]     rx_data_o       ,//解扰后的输出数据;
    output  reg                             rx_data_vld_o    //解扰后的输出数据有效指示信号;
);
    integer                                 i               ;
    reg         [57 : 0]                    descrambler     ;
    reg         [57 : 0]                    poly            ;
    reg         [RX_DATA_WIDTH - 1 : 0]     tempData        ;
    reg                                     xorBit          ;

    //解扰运算;
    always@(descrambler,rx_data_i)begin
        poly = descrambler;
        for(i=0;i<=(RX_DATA_WIDTH-1);i=i+1)begin
            xorBit = rx_data_i[i] ^ poly[38] ^ poly[57];
            poly = {poly[56:0],rx_data_i[i]};
            tempData[i] = xorBit;
        end
    end

    //解扰将数据输出;
    always@(posedge clk)begin
        if(rst)begin
            rx_data_o <= 'h0;
            descrambler <= 58'h155_5555_5555_5555;
        end
        else if(rx_data_vld_i)begin
            rx_data_o <= tempData;
            descrambler <= poly;
        end
    end

    //解码数据相对于其他信号延迟一个时钟,为了对齐,把其他信号延迟一个时钟后输出。
    always@(posedge clk)begin
        rx_header_o <= rx_header_i;
        rx_header_vld_o <= rx_header_vld_i;
        rx_data_vld_o <= rx_data_vld_i;
    end

endmodule

  自定义PHY顶层模块的仿真激励代码如下所示:

//--###############################################################################################
//--#
//--# File Name		: tb_phy_module
//--# Designer		: 数字站
//--# Tool			: Vivado 2021.1
//--# Design Date	: 2024.4.07
//--# Description	: TestBench
//--# Version		: 0.0
//--# Coding scheme	: GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
`timescale 1 ns/1 ns
module tb_phy_module();
    localparam	CYCLE		= 	10		        ;//系统时钟周期,单位ns,默认10ns;
    localparam	RST_TIME	= 	10		        ;//系统复位持续时间,默认10个系统时钟周期;
    localparam  TX_KEEP     =   8'b1111_1100    ;//发送最后一个数据的有效位数,大端对齐;
    
    reg			                clk             ;//系统时钟,默认100MHz;
    reg			                rst_n           ;//系统复位,默认低电平有效;
    reg         [4 : 0]         send_value      ;

    reg                         s_axi_valid     ;//数据有效指示信号,高电平有效;
    reg                         s_axi_last      ;//帧结束指示信号,高电平有效;
    reg         [63 : 0]        s_axi_data      ;//数据信号;
    reg         [7 : 0]         s_axi_keep      ;//数据掩码信号;

    wire                        rx_data_vld     ;//GTX的接收数据有效指示信号;
    wire                        rx_header_vld   ;//GTX的接收头部数据有效指示信号;
    wire                        rx_slipbit      ;//滑块信号,高电平有效;
    wire        [63 : 0]        tx_data         ;//GTX需要发送的数据;
    wire        [1 : 0]         tx_header       ;//GTX需要发送的头部数据;
    wire        [6 : 0]         tx_sequence     ;//GTX外部计数器;
    wire                        s_axi_ready     ;//接收数据应答信号;

    assign rx_data_vld = (tx_sequence != 32);
    assign rx_header_vld = rx_data_vld;

    phy_module u_phy_module(
        .rst            ( ~rst_n        ),
        .rx_clk		    ( clk		    ),//系统时钟信号;
        .rx_rst	        ( ~rst_n	    ),//系统复位信号,高电平有效;
        .rx_data        ( tx_data       ),//GTX的接收数据信号;
        .rx_data_vld    ( rx_data_vld   ),//GTX的接收数据有效指示信号;
        .rx_header      ( tx_header     ),//GTX的接收头部数据信号;
        .rx_header_vld  ( rx_header_vld ),//GTX的接收头部数据有效指示信号;
        .rx_slipbit     ( rx_slipbit    ),//滑块信号,高电平有效;
        .tx_clk         ( clk           ),//系统时钟信号;
        .tx_rst         ( ~rst_n        ),//系统复位信号,高电平有效;
        .tx_data        ( tx_data       ),//GTX需要发送的数据;
        .tx_header      ( tx_header     ),//GTX需要发送的头部数据;
        .tx_sequence    ( tx_sequence   ),//GTX外部计数器;
        .s_axi_valid    ( s_axi_valid   ),//数据有效指示信号,高电平有效;
        .s_axi_last     ( s_axi_last    ),//帧结束指示信号,高电平有效;
        .s_axi_data     ( s_axi_data    ),//数据信号;
        .s_axi_keep     ( s_axi_keep    ),//数据掩码信号;
        .s_axi_ready    ( s_axi_ready   ),//接收数据应答信号;
        .m_axi_data     (               ),//数据信号;
        .m_axi_keep     (               ),//数据掩码信号;
        .m_axi_last     (               ),//一帧数据的结束数据;
        .m_axi_valid    (               ) //数据有效指示信号;
    );

    //生成周期为CYCLE数值的系统时钟;
    initial begin
        clk = 0;
        forever #(CYCLE/2) clk = ~clk;
    end

    //生成复位信号;
    initial begin
        rst_n = 1;
        #2;
        rst_n = 0;//开始时复位10个时钟;
        #(RST_TIME*CYCLE);
        rst_n = 1;
    end

    //生成输入信号din;
    initial begin
        s_axi_data  = 64'd0;
        s_axi_keep  = 8'd0;
        s_axi_last  = 1'd0;
        s_axi_valid = 1'd0;
        wait(rst_n);//等待复位完成;
        repeat(10) @(posedge clk);
        phy_tx_task(5);
        repeat(100) @(posedge clk);
        repeat(5) begin
            phy_tx_task(5);
        end
        @(posedge s_axi_ready);
    end

    //发送数据的任务;
    task phy_tx_task(
        input	[7 : 0]		len
    );
        begin : phy_tx_task_0
            integer i;
            s_axi_data  <= 64'd0;
            s_axi_keep  <= 8'hff;
            s_axi_last  <= 1'd0;
            s_axi_valid <= 1'd0;
            send_value <= 5'd1;
            @(posedge clk);
            wait(s_axi_ready);
            @(posedge clk);
            for(i=0 ; i<len ; i=i+1)begin
                s_axi_data <= {{send_value[4:0],3'd0},{send_value[4:0],3'd1},{send_value[4:0],3'd2},{send_value[4:0],3'd3},{send_value[4:0],3'd4},{send_value[4:0],3'd5},{send_value[4:0],3'd6},{send_value[4:0],3'd7}};
                if(i == len - 1)begin
                    s_axi_last <= 1'b1;
                    s_axi_keep <= TX_KEEP;
                end
                else begin
                    s_axi_last <= 1'b0;
                    s_axi_keep <= 8'hff;
                end
                s_axi_valid <= 1'b1;
                send_value <= send_value + 1;
                @(posedge clk);
            end
            s_axi_data  <= 64'd0;
            s_axi_keep  <= 8'hff;
            s_axi_last  <= 1'd0;
            s_axi_valid <= 1'd0;
            @(posedge clk);
        end
    endtask

endmodule

  将用户发送数据的尾端掩码设置为8’hc0,抓到发送数据和接收数据的时序如下图所示,一帧数据最后一个有效数据是8’h29,收发一致,证明发送数据、接收数据、加扰、解扰的逻辑设计均没有问题。

在这里插入图片描述

图2 自定义PHY的仿真时序

  将尾端数据掩码信号修改为8’hf0,对应的仿真时序如下图所示。接收和发送的最后一个有效字节数据均为8’h2b,表示收发数据均正确。

在这里插入图片描述

图3 自定义PHY仿真时序

  将发送数据的尾端掩码修改为8’hfc,对应的仿真时序如下图所示,接收和发送数据帧的最后一个有效字节数据均为2’h2d,表示收发数据时序均正确。

在这里插入图片描述

图4 自定义phy仿真时序

  其余情况有兴趣的可以自行仿真,在设计时对所有情况都做过仿真。因为本文并没有加入高速收发器进行联调,所以其余情况就不全部列出了。下文将所有模块联合并上板,到时候在将全部情况进行仿真。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939807.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云OS Copilot:解锁操作系统运维与编程的智能助手

目录 引言 OS Copilot简介 OS Copilot的环境准备 创建实验资源 安全设置 设置安全组端口 创建阿里云AccessKey 准备系统环境 OS Copilot的实操 场景一、用OS Copilot写脚本和注释代码 场景二、使用OS Copilot进行对话问答 场景三、使用OS Copilot辅助编程学习 清理…

P15-P18-随机梯度下降-自适应学习率-超参数筛选-正则化

文章目录 随机梯度下降和自适应学习率超参数筛选交叉验证 正则化权重衰减Dropout 简介 本文主要讨论了机器学习中随机梯度下降&#xff08;SGD&#xff09;和自适应学习率算法的原理及应用。SGD通过随机选择小批量样本计算损失值&#xff0c;减少了计算量&#xff0c;加快了训练…

国内访问Docker Hub慢问题解决方法

在国内访问Docker Hub时可能会遇到一些困难&#xff0c;但幸运的是&#xff0c;有多种解决方案可以帮助你顺利下载Docker镜像。以下是一些有效的解决方案&#xff1a; 配置Docker镜像源&#xff1a;你可以通过配置Docker的daemon.json文件来使用国内镜像源&#xff0c;比如DaoC…

Spring Web MVC(一篇带你了解并入门,附带常用注解)

一&#xff0c;什么是Spring Web MVC 先看一下官网怎么说&#xff1a; 也就是Spring Web MVC一开始就是包含在Spring框架里面的&#xff0c;但通常叫做Spring MVC。 也可以总结出一个信息&#xff0c;这是一个Web框架。后面我就简称为Spring MVC了。 1.1MVC MVC也就是Mode…

202496读书笔记|《飞花令·菊(中国文化·古典诗词品鉴)》——荷尽已无擎雨盖,菊残犹有傲霜枝

202496读书笔记|《飞花令菊&#xff08;中国文化古典诗词品鉴&#xff09;》——荷尽已无擎雨盖&#xff0c;菊残犹有傲霜枝 《飞花令菊&#xff08;中国文化古典诗词品鉴&#xff09;》素心落雪 编著。飞花令得名于唐代诗人韩翃《寒食》中的名句“春城无处不飞花”&#xff0c…

食南之徒~马伯庸

◆ 第一章 >> 老赵&#xff0c;这你就不懂了。过大于功&#xff0c;要受罚挨打&#xff0c;不合算&#xff1b;功大于过&#xff0c;下回上司有什么脏活累活&#xff0c;第一时间会想到你&#xff0c;也是麻烦多多。只有功过相抵&#xff0c;上司既挑不出你的错&#xf…

Unity 调试死循环程序

如果游戏出现死循环如何调试呢。 测试脚本 我们来做一个测试。 首先写一个死循环代码&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;public class dead : MonoBehaviour {void Start(){while (true){int a 1;}}}Unity对象设…

Flowable-SpringBoot项目集成

在前面的介绍中&#xff0c;虽然实现了绘制流程图&#xff0c;然后将流程图存储到数据库中&#xff0c;然后从数据库中获取流程信息&#xff0c;并部署和启动流程&#xff0c;但是部署的流程绘制器是在tomcat中部署的&#xff0c;可能在部分的项目中&#xff0c;需要我们将流程…

微信小程序数组绑定使用案例(一)

微信小程序数组绑定案例&#xff0c;修改数组中的值 1.Wxml 代码 <view class"list"><view class"item {{item.ischeck?active:}}" wx:for"{{list}}"><view class"title">{{item.name}} <text>({{item.id}…

武忠祥李永乐强化笔记

高等数学 函数 极限 连续 函数 复合函数奇偶性 f[φ(x)]内偶则偶&#xff0c;内奇则同外 奇函数 ln ⁡ ( x 1 x 2 ) \ln(x \sqrt{1 x^{2}}) ln(x1x2 ​) 单调性 一点导数>0不能得出邻域单调增&#xff0c;加上导函数连续则可以得出邻域单调增 极限 等价无穷小…

达梦数据库的系统视图v$utsk_info

达梦数据库的系统视图v$utsk_info 查询守护进程向服务器发送请求的执行情况。 升级到 V3.0 版本后&#xff0c;此视图仅用于查看当前服务器的命令执行情况&#xff0c;在 CMD 字段值不为 0 时&#xff0c;说明是有效的命令信息&#xff1b;此时如果 CODE 字段值是 100&#xf…

202495读书笔记|《红楼梦(插图本)(童年书系·书架上的经典)》——荣辱自古周而复始,岂是人力所能保的?

202495读书笔记|《红楼梦&#xff08;插图本&#xff09;&#xff08;童年书系书架上的经典&#xff09;》——荣辱自古周而复始&#xff0c;岂是人力所能保的&#xff1f; 摘录人物关系&#xff1a; 《红楼梦&#xff08;插图本&#xff09;&#xff08;童年书系书架上的经典&…

02互联网行业的产品方向(2)

数字与策略产品 大数据时代&#xff0c;数据的价值越来越重要。大多数公司开始对内外全部数据进行管理与挖掘&#xff0c;将业务数据化&#xff0c;数据资产化&#xff0c;资产业务化&#xff0c;将数据产品赋能业务&#xff0c;通过数据驱动公司业务发展&#xff0c;支撑公司战…

学习周报:文献阅读+Fluent案例+水动力学方程推导

目录 摘要 Abstract 文献阅读&#xff1a;物理信息神经网络学习自由表面流 文献摘要 讨论|结论 预备知识 浅水方程SWE&#xff08;Shallow Water Equations&#xff09; 质量守恒方程&#xff1a; 动量守恒方程&#xff1a; Godunov通量法&#xff1a; 基本原理&…

嵌入式Linux学习: platform 设备驱动实验

在Linux中&#xff0c;Platform&#xff08;平台&#xff09;机制是一个重要的设备驱动管理框架&#xff0c;它主要在Linux 2.6内核及以后的版本中引入。Platform机制的主要目的是提供一种统一的方式来管理那些不直接挂靠在传统物理总线&#xff08;如USB、PCI、I2C、SPI等&…

单链表的应用(3)

返回倒数第k个结点 实现一种算法&#xff0c;找出单向链表中倒数第 k 个节点。返回该节点的值。 思路&#xff1a; 利用快慢指针&#xff0c;先让快指针走k步快慢指针一起往后遍历&#xff0c;直到快指针到达链表的末端此时的慢指针就是链表的倒数第k个结点 int kthToLast(…

昇思MindSpore学习总结十六 —— 基于MindSpore的GPT2文本摘要

1、mindnlp 版本要求 !pip install tokenizers0.15.0 -i https://pypi.tuna.tsinghua.edu.cn/simple # 该案例在 mindnlp 0.3.1 版本完成适配&#xff0c;如果发现案例跑不通&#xff0c;可以指定mindnlp版本&#xff0c;执行!pip install mindnlp0.3.1 !pip install mindnlp …

提供代码!直接可以运行,Chatgpt代码分享

效果演示 安装依赖库 pip install openai粘贴如下代码 # 设置 API Key import openaiopenai.api_key "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"# 设置请求参数model_engine "text-davinci-002"prompt "python的应用领域"comp…

Bonree ONE赋能汽车行业 重塑可观测性体验

随着数字化、智能化浪潮的汹涌而至&#xff0c;全球汽车产业正站在一个崭新的历史起点上。新能源汽车&#xff0c;作为这场科技革命和产业变革的领跑者&#xff0c;其数智化发展正呈现出前所未有的蓬勃态势。7月18-19日&#xff0c;第四届中国新能源汽车产业数智峰会于上海举办…

《0基础》学习Python——第二十三讲__网络爬虫/<6>爬取哔哩哔哩视频

一、在B站上爬取一段视频&#xff08;B站视频有音频和视频两个部分&#xff09; 1、获取URL 注意&#xff1a;很多平台都有反爬取的机制&#xff0c;B站也不例外 首先按下F12找到第一条复制URL 2、UA伪装&#xff0c;下列图片中&#xff08;注意代码书写格式&#xff09; 3、Co…