Verilog编写UDP协议-接受端RX

上期给出了udp协议的发送端,这期讲讲接收端

Verilog编写UDP协议-发送端TX-优快云博客

发送端顶层代码: 

`timescale 1ns / 1ps
//
// Engineer: 兵棒
// Create Date: 2023/12/06 15:56:20 
// Module Name: UDP_in
// Description: UDP接收顶层控制 接口位GMII千兆网通信
// Attention:1、ip_checknum的计算,数据要完全囊括进去。
//            2、数据对比的工作放在最后进行对比,先把所有数据接受完
//


module UDP_in#(
    parameter 			FPGA_MAC_ADDR				=				48'h02_00_00_00_00_02,      // FPGA MAC地址
    parameter 			FPGA_IP_ADDR				=				32'hc0_a8_01_66,            // FPGA IP地址
    parameter 			FPGA_UDP_PORT				=				16'd0 				        // FPGA UDP端口号
)(
    input           RX_CLK,//接收数据参考时钟,时钟频率为125MHz 。 RX_CLK 是由PHY 侧提供的
    input           rst_n,
    input [7:0]     RXD,//ReceiveData ,数据接收信号,共 8 根信号线。
    input           RX_ER,//Receive Error 接收数据错误提示信号;同步于 RX_CLK高电平有效,表示 RX_ER 有效期内传输的数据无效。对于10Mbps 速率下, RX_ER 不起作用 。
    input           RX_DV,//Reveive Data Valid 接收数据有效信号;拉高时表示接收数据有效。
    output [7:0]    rx_data,
    output          rx_data_valid,
    output reg      rx_done
);  
    // 前导码
    localparam 			ETH_PREAMBLE 			=				8'h55;
    localparam 			ETH_SFD 				=				8'hd5;
    //帧类型
    reg [15:0]  ETH_TYPE        =0;
    
    // IP首部参数
    reg	[3:0]   IP_HEAD_VER		=0;//版本
    reg	[3:0]   IP_HEAD_LEN 	=0;//首部长度
    reg	[7:0]   IP_HEAD_TOS     =0;//区分服务
    reg [15:0]  IP_LENGTH       =0;
    reg	[15:0]  IP_HEAD_ID 		=0;//标识
    reg	[2:0]   IP_HEAD_FLAG 	=0;//标志
    reg	[12:0]  IP_HEAD_OFFSET 	=0;//片偏移
    reg	[7:0]   IP_HEAD_TTL 	=0;//生存时间
    reg	[7:0]   IP_HEAD_PROT 	=0;//协议
    reg [15:0]  PS_CHECK        =0;
    reg [31:0]  PS_IP_ADDR      =0;//PS ip
    reg [31:0]  AIM_IP_ADDR     =0;//FPGA ip
    reg [15:0]  IP_Optional     =0;//可选字段
    reg [15:0]  IP_fill         =0;//填充
    reg [7:0]   FPGA_MAC[5:0]   ;// FPGA MAC地址
    reg [7:0]   PS_MAC[5:0]     ;// PS MAC地址
    //udp
    reg [15:0]  udp_ps_post     =0;
    reg [15:0]  udp_fpga_post   =0;
    reg [15:0]  udp_length      =0;
    reg [15:0]  udp_check       =0;
    reg [3:0]   udp_cnt         =0;
    reg [31:0]  CRC32_DATA_O    =0;
    reg [7:0]   rx_data_o       =0;
    reg         rx_data_valid_o =0;
    reg [15:0]  rx_cnt          =0;
    reg [3:0]   crc_cnt         =0;

    reg [3:0]   lead_code_cnt   =0;
    reg [3:0]   fpga_mac_cnt    =0;
    reg [3:0]   ps_mac_cnt      =0;
    reg [3:0]   state           =0;
    
    
    reg         check_start     =0;
    reg [7:0]   ip_head_cnt     =0;
    reg         I_CRC_INIT      =0;
    
    wire            fpga_mac_right,fpga_mac_right0,fpga_mac_right1,fpga_mac_right2,fpga_mac_right3,fpga_mac_right4,fpga_mac_right5;
    wire            check_right     ;
    wire [15:0]     ip_checknum     ;
    wire            ip_check_valid  ;
    wire [15:0]     IP_CHECK        ;
    wire [31:0]     CRC32_DATA      ;
    wire            ip_right        ;
    wire            udp_post_right  ;
    wire            crc_right       ;
    wire            I_CRC_EN        ;
    wire [7:0]      data_o          ;

    assign  rx_data=rx_data_o;
    assign  rx_data_valid=rx_data_valid_o;

    //根据需要适当将判断值输出运用
    assign  fpga_mac_right0 = (FPGA_MAC[0] == FPGA_MAC_ADDR[47:40]) ? 1: 0;//发送端物理地址高位
    assign  fpga_mac_right1 = (FPGA_MAC[1] == FPGA_MAC_ADDR[39:32]) ? 1: 0;
    assign  fpga_mac_right2 = (FPGA_MAC[2] == FPGA_MAC_ADDR[31:24]) ? 1: 0;
    assign  fpga_mac_right3 = (FPGA_MAC[3] == FPGA_MAC_ADDR[23:16]) ? 1: 0;
    assign  fpga_mac_right4 = (FPGA_MAC[4] == FPGA_MAC_ADDR[15:8 ]) ? 1: 0;
    assign  fpga_mac_right5 = (FPGA_MAC[5] == FPGA_MAC_ADDR[7 :0 ]) ? 1: 0;//发送端物理地址低位
    assign  fpga_mac_right  = fpga_mac_right0&fpga_mac_right1&fpga_mac_right2&fpga_mac_right3&fpga_mac_right4&fpga_mac_right5;//物理地址判断
    assign  IP_CHECK=(ip_check_valid) ? ip_checknum : IP_CHECK;//校验和取值
    assign  check_right=(IP_CHECK==PS_CHECK) ? 1 : 0;//校验和判断
    assign  ip_right=(AIM_IP_ADDR==FPGA_IP_ADDR) ? 1 : 0;//IP地址判断
    assign  udp_post_right=(udp_fpga_post==FPGA_UDP_PORT) ? 1 : 0;//udp端口判断
    assign  crc_right=(CRC32_DATA_O==CRC32_DATA) ? 1 : 0;//FCS检错值判断
    
    assign  I_CRC_EN=(state>=0&&state<=7) ? RX_DV : 0;
    assign  data_o=(I_CRC_EN) ? RXD : data_o;


    always@(posedge RX_CLK or negedge rst_n)begin
        if(!rst_n)begin
            state           <= 0;
            lead_code_cnt   <= 0;
            ps_mac_cnt      <= 0;
            check_start     <= 0;
            ip_head_cnt     <= 0;
            udp_cnt         <= 0;
            rx_cnt          <= 0;
            rx_data_o       <= 0;
            rx_data_valid_o <= 0;
            crc_cnt         <= 0;
            rx_done         <= 0;
            PS_MAC[0]       <= 0;
            PS_MAC[1]       <= 0;
            PS_MAC[2]       <= 0;
            PS_MAC[3]       <= 0;
            PS_MAC[4]       <= 0;
            PS_MAC[5]       <= 0;
            I_CRC_INIT      <= 0;
        end
        else if(RX_ER)
            state           <= 9;
        else 
            case (state)
                0:begin
                    lead_code_cnt   <= 0;
                    ps_mac_cnt      <= 0;
                    check_start     <= 0;
                    ip_head_cnt     <= 0;
                    udp_cnt         <= 0;
                    rx_cnt          <= 0;
                    rx_data_o       <= 0;
                    rx_data_valid_o <= 0;
                    crc_cnt         <= 0;
                    rx_done         <= 0;
                    PS_MAC[0]       <= 0;
                    PS_MAC[1]       <= 0;
                    PS_MAC[2]       <= 0;
                    PS_MAC[3]       <= 0;
                    PS_MAC[4]       <= 0;
                    PS_MAC[5]       <= 0;
                    I_CRC_INIT      <= 0;
                    if(!RX_ER)begin
                        state   <=1;
                        I_CRC_INIT<=1;
                    end
                    else begin
                        state   <=0;
                        I_CRC_INIT<=0;
                    end
                end
                1:begin
                    I_CRC_INIT<=0;
                    if(RXD==ETH_PREAMBLE&&RX_DV)
                        lead_code_cnt   <= lead_code_cnt + 1;
                    else if(RXD==ETH_SFD&&RX_DV)
                        lead_code_cnt   <= lead_code_cnt + 1;
                    else
                        lead_code_cnt   <= lead_code_cnt;

                    if(lead_code_cnt>=4'd7)
                        state           <= 2;
                    else
                        state   <= 1;
                end
                2:begin
                    lead_code_cnt   <= 0;
                    if(fpga_mac_cnt>=5)begin
                        state   <= 3;
                    end
                    else
                        state   <= 2;
                end
                3:begin
                    if(RX_DV)begin
                        PS_MAC[ps_mac_cnt]<= RXD;
                        ps_mac_cnt  <= ps_mac_cnt + 1;
                    end
                    else begin
                        ps_mac_cnt  <= ps_mac_cnt;
                    end
                    if(ps_mac_cnt>=4'd5)
                        state       <= 4;
                    else
                        state       <= 3;
                end
                4:begin
                    ps_mac_cnt  <= 0;
                    if(RX_DV)
                        ETH_TYPE[15:8]<= RXD;
                    else
                        ETH_TYPE[15:8]<= ETH_TYPE[15:8];
                    state<=5;
                end
                5:begin
                    if(RX_DV)
                        ip_head_cnt <= ip_head_cnt + 1;
                    else
                        ip_head_cnt <= ip_head_cnt;
                    case (ip_head_cnt)
                        0:ETH_TYPE[7:0]         <= RXD;
                        1:begin
                            IP_HEAD_VER         <=RXD[7:4];
                            IP_HEAD_LEN         <=RXD[3:0];
                        end
                        2:IP_HEAD_TOS           <=RXD;
                        3:IP_LENGTH[15:8]       <=RXD;
                        4:IP_LENGTH[7:0]        <=RXD;
                        5:IP_HEAD_ID[15:8]      <=RXD;
                        6:IP_HEAD_ID[7:0]       <=RXD;
                        7:begin
                            IP_HEAD_FLAG        <=RXD[7:5];
                            IP_HEAD_OFFSET[12:8]<=RXD[4:0];
                        end
                        8:IP_HEAD_OFFSET[7:0]   <=RXD;
                        9:IP_HEAD_TTL           <=RXD;
                        10:IP_HEAD_PROT          <=RXD;
                        11:PS_CHECK[15:8]        <=RXD;
                        12:PS_CHECK[7:0]        <=RXD;
                        13:PS_IP_ADDR[31:24]    <=RXD;
                        14:PS_IP_ADDR[23:16]    <=RXD;
                        15:PS_IP_ADDR[15:8]     <=RXD;
                        16:PS_IP_ADDR[7:0]      <=RXD;
                        17:AIM_IP_ADDR[31:24]   <=RXD;
                        18:AIM_IP_ADDR[23:16]   <=RXD;
                        19:AIM_IP_ADDR[15:8]    <=RXD;
                        20:begin
                            AIM_IP_ADDR[7:0]     <=RXD;
                            state               <= 6;
                            check_start         <= 1;
                        end
                        //此部分是可选部分和填充部分,看需求添加即可
                        // 21:IP_Optional[15:8]    <=RXD;
                        // 22:IP_Optional[7:0]     <=RXD;
                        // 23:IP_fill[15:8]        <=RXD;
                        // 24:begin
                        //     IP_fill[7:0]        <=RXD;
                        //     state               <= 6;
                        //     check_start         <= 1;
                        // end
                        default: ;
                    endcase
                end
                6:begin
                    check_start     <= 0;
                    ip_head_cnt     <= 0;
                    if(RX_DV)
                        udp_cnt         <= udp_cnt + 1;
                    else
                        udp_cnt         <= udp_cnt;
                    case (udp_cnt)
                        0: udp_ps_post[15:8]    <=RXD;
                        1: udp_ps_post[7:0]     <=RXD;
                        2: udp_fpga_post[15:8]  <=RXD;
                        3: udp_fpga_post[7:0]   <=RXD;
                        4: udp_length[15:8]     <=RXD;
                        5: udp_length[7:0]      <=RXD;
                        6: udp_check[15:8]      <=RXD;
                        7: begin
                            state               <=7;
                            udp_check[7:0]      <=RXD;
                        end
                        default: ;
                    endcase
                end
                7:begin
                    udp_cnt             <= 0;
                    if(RX_DV)begin
                        rx_data_o       <= RXD;
                        rx_cnt          <= rx_cnt + 1;
                        rx_data_valid_o <= 1;
                    end
                    else begin
                        rx_data_o       <= rx_data_o;
                        rx_cnt          <= rx_cnt;
                        rx_data_valid_o <= 0;
                    end
                    if(rx_cnt>=udp_length-4'd9)
                        state   <= 8;
                    else
                        state   <= 7;
                end
                8:begin
                    rx_cnt          <= 0;
                    rx_data_valid_o <= 0;
                    rx_data_o       <= 0;
                    if(RX_DV)
                        crc_cnt         <= crc_cnt + 1;
                    else
                        crc_cnt         <= crc_cnt;
                    case (crc_cnt)
                        0:CRC32_DATA_O[7:0]   <= RXD;
                        1:CRC32_DATA_O[15:8]   <= RXD;
                        2:CRC32_DATA_O[23:16]    <= RXD;
                        3:begin
                            CRC32_DATA_O[31:24]   <= RXD;
                            state               <= 9;
                        end
                        default:;
                    endcase
                end
                9:begin
                    rx_done     <= 1;
                    state       <= 0;
                end
                default:begin
                    state           <= 0;
                    lead_code_cnt   <= 0;
                    ps_mac_cnt      <= 0;
                    check_start     <= 0;
                    ip_head_cnt     <= 0;
                    udp_cnt         <= 0;
                    rx_cnt          <= 0;
                    rx_data_o       <= 0;
                    rx_data_valid_o <= 0;
                    crc_cnt         <= 0;
                    rx_done         <= 0;
                    PS_MAC[0]       <= 0;
                    PS_MAC[1]       <= 0;
                    PS_MAC[2]       <= 0;
                    PS_MAC[3]       <= 0;
                    PS_MAC[4]       <= 0;
                    PS_MAC[5]       <= 0;
                end
            endcase
    end
    always@(posedge RX_CLK or negedge rst_n)begin
        if(!rst_n)begin
            fpga_mac_cnt<= 0;
            FPGA_MAC[0] <= 0;
            FPGA_MAC[1] <= 0;
            FPGA_MAC[2] <= 0;
            FPGA_MAC[3] <= 0;
            FPGA_MAC[4] <= 0;
            FPGA_MAC[5] <= 0;
        end
        else if(state==2)begin
            if(RX_DV)begin
                FPGA_MAC[fpga_mac_cnt]<= RXD;
                fpga_mac_cnt <= fpga_mac_cnt + 1;
            end
            else begin
                fpga_mac_cnt <= fpga_mac_cnt;
            end
        end
        else begin
            fpga_mac_cnt<= 0; 
            FPGA_MAC[0] <= 0;
            FPGA_MAC[1] <= 0;
            FPGA_MAC[2] <= 0;
            FPGA_MAC[3] <= 0;
            FPGA_MAC[4] <= 0;
            FPGA_MAC[5] <= 0;
        end
    end
    
    check_num   chek_num_in(
                    .IP_SA          (AIM_IP_ADDR    ),
                    .IP_DA          (PS_IP_ADDR     ),
                    .clk            (RX_CLK         ),
                    .rst_n          (rst_n          ),
                    .check_start    (check_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    ) 
                );
    CRC32_D8    CRC32_D8_in(
                    .I_OPR_CLK      (RX_CLK         ),
                    .I_OPR_RSTN     (rst_n          ),
                    .I_CRC_INIT     (I_CRC_INIT     ),
                    .I_CRC_EN       (I_CRC_EN       ),
                    .I_DATA         (data_o         ),
                    .O_CRC_RES      (CRC32_DATA     )
                );
endmodule

例化部分的代码参考上一篇文章

Verilog编写UDP协议-发送端TX-优快云博客

仿真代码:

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


module tb_check();
    reg             clk;           
    reg             rst_n;   
    //out     
    reg             tx_start;
    reg             tx_wait;
    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 ;     
    //in
    wire [7:0]    rx_data       ;
    wire          rx_data_valid ; 

    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
            data_i<=data_i+1;
    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      )    
);

UDP_in tb_udp_in(
    .RX_CLK       (clk          )   ,
    .rst_n        (rst_n        )   ,
    .RXD          (tx_data      )   ,
    .RX_ER        (tx_er        )   ,
    .RX_DV        (tx_en        )   ,
    .rx_data      (rx_data      )   ,
    .rx_data_valid(rx_data_valid)
); 
endmodule

 仿真图

接收到的数据是通过上一期的发送端做了一个回环测试,可以看到接收端RXD数据正常

在Quartus II 15.0中进行Altera三速以太网IP核的配置和仿真,首先需要创建一个工程,并选择合适的FPGA器件,例如EP4CE10C8。接着,在IP Catalog中找到并添加三速以太网IP核,选择Verilog作为描述语言。在配置IP核的过程中,要确保与NIOS II处理器的接口匹配,并根据UDP协议的需求设置相应的MAC层参数。 参考资源链接:[Quartus II 15.0仿真实验:探索Altera三速以太网IP核](https://wenku.youkuaiyun.com/doc/6401acafcce7214c316ecbfa?spm=1055.2569.3001.10343) 完成IP核的配置后,Quartus II会自动生成IP核的Verilog代码。开发者需要将此代码集成到FPGA设计中,并编写相应的NIOS II软件代码以及UDP协议栈来与之交互。在Modelsim-ALTERA仿真环境中,通过编写Testbench来模拟网络数据包的发送和接收过程,确保NIOS II处理器能够通过IP核发送和接收UDP数据包。 仿真过程中,重点观察MAC层的信号,如RX_CLK、RX_DV、RX_ER、RX_DATA以及TX方向的信号,验证数据包的正确组装、拆解和传输。通过分析仿真波形,开发者可以检查数据包在不同速度下的传输情况,验证协议规范的满足程度,并及时发现并解决可能的问题。这项工作保证了FPGA设计中的网络功能按预期工作,并与NIOS II处理器及UDP协议正确交互。推荐阅读《Quartus II 15.0仿真实验:探索Altera三速以太网IP核》,进一步了解如何在Quartus II中实现和测试三速以太网IP核的详细步骤和技巧。 参考资源链接:[Quartus II 15.0仿真实验:探索Altera三速以太网IP核](https://wenku.youkuaiyun.com/doc/6401acafcce7214c316ecbfa?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值