Verilog编写UDP协议-发送端TX

上期讲解到udp协议的基本要素https://blog.csdn.net/bingbang0703/article/details/134859060icon-default.png?t=N7T8https://blog.csdn.net/bingbang0703/article/details/134859060

本文主要是根据接口GMII进行编写的代码,如有需要的可以根据此代码进行更改成其他接口即可,大致都是一样的,因为写的都是些一部分的东西,只需要改变引脚。

废话不多说,直接上代码

发送端顶层:

`timescale 1ns / 1ps
//
// Engineer: 兵棒
// Create Date: 2023/12/05 16:29:20 
// Module Name: UDP_out
// Description: UDP输出顶层控制 接口位GMII千兆网通信
// Attention:字节输出是按照每个部分的最高位开始输出,bit传输时按照最低位开始传输
//


module UDP_out#(
    parameter 			FPGA_MAC_ADDR				=				48'h01_00_00_00_00_01,      // FPGA MAC地址
    parameter 			FPGA_IP_ADDR				=				32'hc0_a8_01_7b,            // FPGA IP地址
    parameter 			FPGA_UDP_PORT				=				16'd0, 				        // FPGA UDP端口号
    
    parameter 			PS_MAC_ADDR				    =				48'h02_00_00_00_00_02,      // 目的侧 MAC地址
    parameter 			PS_IP_ADDR				    =				32'hc0_a8_01_66,            // 目的侧 IP地址
    parameter 			PS_UDP_PORT				    =				16'd0 				        // 目的侧 UDP端口号
)(
    input           clk,            //125M 1000Mbps
    input           rst_n,          //复位
    input           tx_start,       //传输开始信号

    input  [7:0]    data_i,         //数据
    input           data_valid_i,   //有效
    input  [15:0]   data_length_i,  //一帧数据长度

    output [7:0]    tx_data,        //发送端口
    output          tx_en,          //有效
    output          tx_er,          //错误提示
    output          gtx_clk,        //参考时钟

    output reg      tx_data_start,  //数据传输开始
    output reg      tx_done         //一帧传输结束信号
);
    // 前导码
    localparam 			ETH_PREAMBLE 			=				8'h55;
    localparam 			ETH_SFD 				=				8'hd5;
    //帧类型
    localparam 			ETH_TYPE 				= 				16'h0800;//以太网 IP数据报 类型
    // IP首部参数
    localparam 			IP_HEAD_VER				=				4'h4;//版本
    localparam 			IP_HEAD_LEN 			=				4'h5;//首部长度
    localparam 			IP_HEAD_TOS      		=				8'h00;//区分服务
    localparam 			IP_HEAD_ID 				=				16'h0000;//标识
    localparam 			IP_HEAD_FLAG 			=				3'b0_0_0;//标志
    localparam 			IP_HEAD_OFFSET 			=				13'd0;//片偏移
    localparam 			IP_HEAD_TTL 			=				8'h40;//生存时间
    localparam 			IP_HEAD_PROT 			=				8'd17;//协议
    localparam          IP_Optional             =               16'd0;//可选字段
    localparam          IP_fill                 =               16'd0;//填充

    reg [7:0]   tx_data_o;
    reg         tx_en_o;

    reg [3:0]   state;
    reg [3:0]   lead_code_cnt;//前导码计数
    reg [3:0]   ps_mac_cnt;//接收端物理地址计数
    reg [3:0]   fpga_mac_cnt;//发送端物理地址计数
    reg         type_flag;
    reg         type_done;
    reg [5:0]   ip_head_cnt;//IP头部长度计数
    reg [5:0]   udp_head_cnt;//udp头部长度计数
    reg [15:0]  tx_data_cnt;//数据传输长度计数
    reg [3:0]   crc_cnt;//FCS
    reg [3:0]   delay_cnt;//帧间隔
    reg         crc_done;

    wire        ip_check_valid;//校验和有效信号
    wire [15:0] ip_checknum;//校验和
    wire [15:0] IP_CHECK;

    wire [7:0]  PS_MAC[5:0];//接收端物理地址寄存
    wire [7:0]  FPGA_MAC[5:0];//发送端物理地址寄存
    wire [15:0] IP_LENGTH;//IP总长度
    wire [15:0] UDP_LENGTH;//udp总长度
    wire [15:0] UDP_CHECK;//udp校验值
    wire [31:0] CRC32_DATA_O;//FCS校验
    wire        I_CRC_EN;

    assign  tx_data=tx_data_o;
    assign  tx_en=tx_en_o;
    assign  tx_er=1'd0;
    assign  gtx_clk=clk;

    assign  IP_LENGTH=data_length_i+16'd8+16'd20;//总长度
    assign  UDP_LENGTH=data_length_i+16'd8;//UDP长度
    assign  UDP_CHECK=16'd0;//UDP校验值
    assign  IP_CHECK=(ip_check_valid) ? ip_checknum : IP_CHECK;
    assign  PS_MAC  [0] = PS_MAC_ADDR[47:40];//接收端物理地址高位
    assign  PS_MAC  [1] = PS_MAC_ADDR[39:32];
    assign  PS_MAC  [2] = PS_MAC_ADDR[31:24];
    assign  PS_MAC  [3] = PS_MAC_ADDR[23:16];
    assign  PS_MAC  [4] = PS_MAC_ADDR[15:8 ];
    assign  PS_MAC  [5] = PS_MAC_ADDR[7 :0 ];//接收端物理地址低位
    assign  FPGA_MAC[0] = FPGA_MAC_ADDR[47:40];//发送端物理地址高位
    assign  FPGA_MAC[1] = FPGA_MAC_ADDR[39:32];
    assign  FPGA_MAC[2] = FPGA_MAC_ADDR[31:24];
    assign  FPGA_MAC[3] = FPGA_MAC_ADDR[23:16];
    assign  FPGA_MAC[4] = FPGA_MAC_ADDR[15:8 ];
    assign  FPGA_MAC[5] = FPGA_MAC_ADDR[7 :0 ];//发送端物理地址低位

    assign  I_CRC_EN    = (state>0&&state<9&&tx_en&&(!crc_done)) ? 1 : 0;
    assign  I_CRC_INIT  = (state==0&&tx_start) ? 1 : 0;

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state           <= 0;
            lead_code_cnt   <= 0;
            tx_data_o       <= 0;
            ps_mac_cnt      <= 0;
            fpga_mac_cnt    <= 0;
            type_flag       <= 0;
            type_done       <= 0;
            ip_head_cnt     <= 0;
            udp_head_cnt    <= 0;
            tx_data_cnt     <= 0;
            crc_cnt         <= 0;
            delay_cnt       <= 0;
            tx_data_start   <= 0;
            tx_done         <= 0;
            crc_done        <= 0;
        end
        else case (state)
            0:begin
                lead_code_cnt   <= 0;
                tx_data_o       <= 0;
                ps_mac_cnt      <= 0;
                fpga_mac_cnt    <= 0;
                type_flag       <= 0;
                type_done       <= 0;
                ip_head_cnt     <= 0;
                udp_head_cnt    <= 0;
                tx_data_cnt     <= 0;
                crc_cnt         <= 0;
                delay_cnt       <= 0;
                tx_data_start   <= 0;
                tx_done         <= 0;
                crc_done        <= 0;
                if(tx_start)
                    state       <= 1;
                else
                    state       <= 0;
            end
            //前导码+帧开始
            1:begin
                if(lead_code_cnt<=4'd6)begin
                    lead_code_cnt <= lead_code_cnt + 1;
                    tx_data_o     <= ETH_PREAMBLE;
                end
                else begin
                    lead_code_cnt <= lead_code_cnt;
                    tx_data_o     <= ETH_SFD;
                end
                if(lead_code_cnt > 4'd6)
                    state <= 2;
                else
                    state <= 1;
            end
            //目的物理地址
            2:begin
                lead_code_cnt   <= 0;
                tx_data_o       <= PS_MAC[ps_mac_cnt];
                if(ps_mac_cnt < 4'd5)begin
                    ps_mac_cnt  <= ps_mac_cnt + 1;
                end
                else begin
                    ps_mac_cnt  <= ps_mac_cnt;
                end
                if(ps_mac_cnt >= 4'd5)
                    state   <= 3;
                else
                    state   <= 2;
            end
            //源物理地址
            3:begin
                ps_mac_cnt  <= 0;
                tx_data_o   <= FPGA_MAC[fpga_mac_cnt];
                type_flag       <= 1;
                if(fpga_mac_cnt < 4'd5)begin
                    fpga_mac_cnt<= fpga_mac_cnt + 1;
                end
                else begin
                    fpga_mac_cnt<= fpga_mac_cnt;
                end
                if(fpga_mac_cnt >= 4'd5)
                    state   <= 4;
                else
                    state   <= 3;
            end
            //帧类型
            4:begin
                fpga_mac_cnt    <= 0;
                if(type_flag)begin
                    tx_data_o       <= ETH_TYPE[15:8];
                    type_done       <= 1;
                end
                if(type_done)begin
                    tx_data_o       <= ETH_TYPE[7:0];
                    type_flag       <= 0;
                    type_done       <= 0;
                    state           <= 5;
                end
                else
                    state           <= 4;
            end
            //IP报头
            5:begin
                ip_head_cnt <= ip_head_cnt + 1;
                case (ip_head_cnt)
                    0:tx_data_o     <= {IP_HEAD_VER,IP_HEAD_LEN};
                    1:tx_data_o     <= IP_HEAD_TOS;
                    2:tx_data_o     <= IP_LENGTH[15:8];
                    3:tx_data_o     <= IP_LENGTH[7:0];
                    4:tx_data_o     <= IP_HEAD_ID[15:8];
                    5:tx_data_o     <= IP_HEAD_ID[7:0];
                    6:tx_data_o     <= {IP_HEAD_FLAG,IP_HEAD_OFFSET[12:8]};
                    7:tx_data_o     <= IP_HEAD_OFFSET[7:0];
                    8:tx_data_o     <= IP_HEAD_TTL;
                    9:tx_data_o     <= IP_HEAD_PROT;
                    10:tx_data_o    <= IP_CHECK[15:8];
                    11:tx_data_o    <= IP_CHECK[7:0];
                    12:tx_data_o    <= FPGA_IP_ADDR[31:24];
                    13:tx_data_o    <= FPGA_IP_ADDR[23:16];
                    14:tx_data_o    <= FPGA_IP_ADDR[15:8];
                    15:tx_data_o    <= FPGA_IP_ADDR[7:0];
                    16:tx_data_o    <= PS_IP_ADDR[31:24];
                    17:tx_data_o    <= PS_IP_ADDR[23:16];
                    18:tx_data_o    <= PS_IP_ADDR[15:8];
                    19:begin
                        tx_data_o   <= PS_IP_ADDR[7:0];
                        state       <= 6;
                    end
                    default:tx_data_o    <= 8'd0;
                endcase
            end
            //udp报头
            6:begin
                ip_head_cnt     <= 0;
                udp_head_cnt    <= udp_head_cnt + 1;
                case (udp_head_cnt)
                    0:tx_data_o <= FPGA_UDP_PORT[15:8];
                    1:tx_data_o <= FPGA_UDP_PORT[7:0];
                    2:tx_data_o <= PS_UDP_PORT[15:8];
                    3:tx_data_o <= PS_UDP_PORT[7:0];
                    4:tx_data_o <= UDP_LENGTH[15:8];
                    5:tx_data_o <= UDP_LENGTH[7:0];
                    6:tx_data_o <= UDP_CHECK[15:8];
                    7:begin
                        tx_data_o <= UDP_CHECK[7:0];
                        tx_data_start<= 1;
                        state     <= 7;
                    end
                    default:tx_data_o <= 0;
                endcase
            end
            //udp报文(数据)
            7:begin
                udp_head_cnt    <= 0;
                tx_data_start   <= 0;
                tx_data_o       <= data_i;
                if(tx_data_cnt==data_length_i-1)begin
                    tx_data_cnt <= 0;
                    state       <= 8;
                end
                else begin
                    tx_data_cnt <= tx_data_cnt + 1;
                    state       <= 7;
                end
            end
            //FCS检错
            8:begin
                crc_done    <=1;
                crc_cnt     <= crc_cnt + 1;
                case (crc_cnt)
                    0:tx_data_o   <= CRC32_DATA_O[31:24];
                    1:tx_data_o   <= CRC32_DATA_O[23:16];
                    2:tx_data_o   <= CRC32_DATA_O[15:8];
                    3:begin
                        tx_data_o   <= CRC32_DATA_O[7:0];
                        state       <=  9;
                    end
                    default:tx_data_o   <= 0;
                endcase
            end
            //帧间隔12个字节长
            9:begin
                crc_done    <= 0;
                crc_cnt     <= 0;
                tx_data_o   <= 0;
                if(delay_cnt==4'd11)begin
                    delay_cnt   <= 0;
                    tx_done     <= 1;
                    state       <= 0;
                end
                else begin
                    delay_cnt   <= delay_cnt + 1;
                    state       <= 9;
                end
            end
            default:begin
                state           <= 0;
                lead_code_cnt   <= 0;
                tx_data_o       <= 0;
                ps_mac_cnt      <= 0;
                fpga_mac_cnt    <= 0;
                type_flag       <= 0;
                type_done       <= 0;
                ip_head_cnt     <= 0;
                udp_head_cnt    <= 0;
                tx_data_cnt     <= 0;
                crc_cnt         <= 0;
                delay_cnt       <= 0;
                tx_done         <= 0;
                tx_data_start   <= 0;
                crc_done        <= 0;
            end
        endcase
    end

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            tx_en_o <= 0;
        end
        else case (state)
            1,2,3,4,5,6,7,8:tx_en_o <= 1; 
            0,9:tx_en_o <= 0; 
            default: tx_en_o <= 0; 
        endcase
    end
    
    CRC32_D8    CRC32_D8_out(
                    .I_OPR_CLK      (clk            ),
                    .I_OPR_RSTN     (rst_n          ),
                    .I_CRC_INIT     (I_CRC_INIT     ),
                    .I_CRC_EN       (I_CRC_EN       ),
                    .I_DATA         (tx_data_o      ),
                    .O_CRC_RES      (CRC32_DATA_O   )
                );

    check_num   chek_num_out(
                    .IP_SA          (FPGA_IP_ADDR   ),
                    .IP_DA          (PS_IP_ADDR     ),
                    .clk            (clk            ),
                    .rst_n          (rst_n          ),
                    .check_start    (tx_start       ),
	
                    .ip_versions    (IP_HEAD_VER    ),    
                    .ip_head_length (IP_HEAD_LEN    ), 
                    .ip_diffserv    (IP_HEAD_TOS    ),    
                    .ip_all_length  (IP_LENGTH      ),  
                    .ip_tag         (IP_HEAD_ID     ),         
                    .ip_logo        (IP_HEAD_FLAG   ),        
                    .ip_sheet       (IP_HEAD_OFFSET ),       
                    .ip_live        (IP_HEAD_TTL    ),        
                    .ip_agreement   (IP_HEAD_PROT   ),   
                    .ip_Optional    (IP_Optional    ),    
                    .ip_fill        (IP_fill        ),        

                    .ip_check_valid (ip_check_valid ), 
                    .ip_checknum    (ip_checknum    ) 
                );
endmodule

FCS检错代码:


// Engineer: 兵棒
// Create Date: 2023/12/04 16:29:20 
// Module Name: CRC32_D8
// Description: FCS检错值
// Attention:代码生成网址http://crctool.easics.be/,然后进行一定的更改

module CRC32_D8(
// 输入输出端口
    input               I_OPR_CLK,
    input               I_OPR_RSTN,
    input               I_CRC_INIT,
    input               I_CRC_EN,
    input     [7:0]     I_DATA,
    output    [31:0]    O_CRC_RES
);
// 内部信号
    wire [7:0]  W_DATA;
    reg  [31:0] R_CRC_RES;
    
    genvar GV_8;
    generate
        for(GV_8 = 0;GV_8 < 8;GV_8 = GV_8 + 1)begin
            assign W_DATA[GV_8] = I_DATA[7-GV_8];
        end
    endgenerate
    
    always @ (posedge I_OPR_CLK)begin
        if(!I_OPR_RSTN)begin
            R_CRC_RES <= {32{1'b1}};
        end
        else if(I_CRC_INIT)begin
           R_CRC_RES <= {32{1'b1}}; 
        end
        else if(I_CRC_EN)begin
            R_CRC_RES <= nextCRC32_D8(W_DATA,R_CRC_RES);
        end
    end
    
    genvar GV_32;
    generate
        for(GV_32 = 0;GV_32 < 32;GV_32 = GV_32 + 1)begin
            assign O_CRC_RES[GV_32] = ~R_CRC_RES[31-GV_32];
        end
    endgenerate

    // polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
    // data width: 8
    // convention: the first serial bit is D[7]
    function [31:0] nextCRC32_D8;
        input   [7:0]   Data;
        input   [31:0]  crc;

        reg     [7:0]   d;
        reg     [31:0]  c;
        reg     [31:0]  newcrc;
        begin
        d = Data;
        c = crc;
        newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30];
        newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31];
        newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31];
        newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31];
        newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30];
        newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
        newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
        newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31];
        newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
        newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29];
        newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29];
        newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
        newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30];
        newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31];
        newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31];
        newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31];
        newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29];
        newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30];
        newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31];
        newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31];
        newcrc[20] = d[4] ^ c[12] ^ c[28];
        newcrc[21] = d[5] ^ c[13] ^ c[29];
        newcrc[22] = d[0] ^ c[14] ^ c[24];
        newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30];
        newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31];
        newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27];
        newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30];
        newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31];
        newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30];
        newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31];
        newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31];
        newcrc[31] = d[5] ^ c[23] ^ c[29];
        nextCRC32_D8 = newcrc;
    end
    endfunction
endmodule

 IP首部检验和代码:

`timescale 1ns / 1ps
//
// Engineer: 兵棒
// Create Date: 2023/12/05 14:28:20 
// Module Name: check_num
// Description: IP首部检验和的计算
// 计算公式:
//          首部检验和= ~({版本,首部长度,区分服务}+总长度+标识+{标志,片偏移}+{生存时间,协议}
//                          +源地址前16位+目的地址前16位+源地址后16位+目的地址后16位)
//


module check_num(
    input           clk,
    input           rst_n,
    input           check_start,
    input [31:0]    IP_SA,//192.168.1.123源地址
    input [31:0]    IP_DA,//192.168.1.102目的地址
    input [3:0]     ip_versions,    //版本
    input [3:0]     ip_head_length, //头部长度
    input [7:0]     ip_diffserv,    //区分服务
    input [15:0]    ip_all_length,  //总长度
    input [15:0]    ip_tag,         //标识
    input [2:0]     ip_logo,        //标志
    input [12:0]    ip_sheet,       //片偏移
    input [7:0]     ip_live,        //生存时间
    input [7:0]     ip_agreement,   //协议
    input [15:0]    ip_Optional,    //可选字段
    input [15:0]    ip_fill,        //填充

    output          ip_check_valid, //首部检验和有效
    output [15:0]   ip_checknum     //首部检验和
);

    reg     [31:0]  ip_checknum_t;
    reg     [15:0]  ip_check_over;
    reg     [15:0]  ip_check;
    reg     [3:0]   state;
    reg             valid;

    wire    [15:0]  num_1;
    wire    [15:0]  num_2;
    wire    [15:0]  num_3;
    wire    [15:0]  num_4;
    wire    [15:0]  num_5;
    wire    [15:0]  num_6;
    wire    [15:0]  num_7;

    assign  num_1={ip_versions,ip_head_length,ip_diffserv};//版本+首部长度+区分服务
    assign  num_2={ip_logo,ip_sheet};//标志+片偏移
    assign  num_3={ip_live,ip_agreement};//生存时间+协议
    assign  num_4=IP_SA[31:16];//源地址前16位
    assign  num_5=IP_SA[15:0 ];//源地址后16位
    assign  num_6=IP_DA[31:16];//目的地址后16位
    assign  num_7=IP_DA[15:0 ];//目的地址后16位

    assign  ip_checknum=~ip_check;
    assign  ip_check_valid=valid;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            ip_checknum_t   <=  0;
            ip_check_over   <=  0;
            ip_check        <=  0;
            valid           <=  0;
            state           <=  0;
        end
        else case(state)
            0:begin
                ip_checknum_t   <=  0;
                ip_check_over   <=  0;
                ip_check        <=  0;
                valid           <=  0;
                if(check_start)
                    state       <=  1;
                else
                    state       <=  0;
            end
            1:begin
                ip_checknum_t   <=  num_1+ip_all_length+ip_tag+num_2+num_3+num_4+num_5+num_6+num_7+ip_Optional+ip_fill;
                state           <=  2;
            end
            2:begin
                ip_check_over   <=  ip_checknum_t[31:16];
                state           <=  3;
            end
            3:begin
                ip_checknum_t[31:16]<=16'h0;
                if(ip_check_over>0)begin
                    state       <=  4;
                end
                else begin
                    state       <= 5;
                end
            end
            4:begin
                ip_checknum_t   <=  ip_check_over+ip_checknum_t[15:0];
                if(ip_checknum_t[31:16]>0)begin
                    state       <=  3;
                    ip_check_over<= ip_checknum_t[31:16];
                end
                else begin
                    state       <=  5;
                    ip_check_over<= ip_check_over;
                end
            end
            5:begin
                ip_check        <=  ip_checknum_t[15:0];
                valid           <=  1;
                state           <=  0;
            end
            default:begin
                ip_checknum_t   <=  0;
                ip_check        <=  0;
                ip_check_over   <=  0;
                valid           <=  0;
                state           <=  0;
            end  
        endcase
    end
endmodule

仿真代码:

`timescale 1ns / 1ps
//
// Engineer: 兵棒
// Create Date: 2023/12/05 15:32:15
// Module Name: tb_check
// Description: 仿真
//


module tb_check();
    reg             clk;           
    reg             rst_n;   
    //out     
    reg             tx_start;
    reg  [7:0]      data_i;       
    reg             data_valid_i;  
    reg  [15:0]     data_length_i; 
    wire [7:0]      tx_data;       
    wire            tx_en;         
    wire            tx_er;         
    wire            gtx_clk;
    wire            tx_data_start;
    wire            tx_done ;     

    always  #4  clk=~clk;    
    initial
    begin
        clk=0;rst_n=0;tx_start=0;data_length_i=16'd0;tx_wait=0;
        #50 rst_n=1;
        #50 tx_start=1;
        #8  tx_start=0;data_length_i=16'd30;
    end
    always@(posedge clk)begin
        if(!rst_n)
            data_i<=0;
        else    if(tx_data_start)
            data_i<=data_i+1;
        else
            data_i<=data_i;
    end
UDP_out tb_udp_out(
    .clk          (clk          )   ,
    .rst_n        (rst_n        )   ,
    .tx_start     (tx_start     )   ,
    .data_i       (data_i       )   ,
    .data_valid_i (data_valid_i )   ,
    .data_length_i(data_length_i)   ,
    .tx_data      (tx_data      )   ,
    .tx_en        (tx_en        )   ,
    .tx_er        (tx_er        )   ,
    .gtx_clk      (gtx_clk      )   ,
    .tx_data_start(tx_data_start)   ,
    .tx_done      (tx_done      )    
);

仿真结果

从仿真数据中可以看到相对位的数据都是正常输出的

一键三连,不迷路。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值