Menu Close

以太网UDP 实验(eth_udp_rx.v)

当以太网包数据被正确接收后, 解析出正确的IP地址后,送给UDP模块处理。 UDP模块需要检查源端口号,目的端口号,检查UDP的checksum是否正确,如果所有检查都是正确的,将数据送给应用层。

ethernet verilog code flowchart

图1

UDP rx interface

图2

状态机(udp_rx_st)逻辑的描述如下,状态流程图如图3(注意省略了状态转移条件不满足时,停留在当前状态的箭头)所示:

状态机处理过程:其中任何一步检查出错误,将状态机跳转到12。

状态0:初始化相应的寄存器,将A/B Buffer的子地址指向 1023, 跳转到状态1。注意这里udp_checksum被初始化成-20,因为在代码中计算了一次UDP包头长度,一次IP包头长度,实际上需要的是两次UDP包头长度,所以将差值(-20)先设置好。

状态1:等待1个时钟周期, 跳转到状态2。

状态2:两个时钟周期后,从子地址1023处读出标志,用来查看UDP_RX_DRAM中是否有数据包需要解析(A/B Buffer是否可以读数据),如果有, 跳转到状态3。设置A/B Buffer地址到IP长度处。

状态3:读取UDP_RX_DRAM中数据包的长度, 跳转到状态4。设置A/B Buffer地址到IP协议处。

状态4:计算IP长度的checksum, 跳转到状态5。设置A/B Buffer地址到源IP地址处。

状态5:计算IP协议 的checksum, 跳转到状态6。设置A/B Buffer地址到源IP地址处。

状态6:计算源IP地址, 目的IP地址, UDP源port, 目的port的checksum, 跳转到状态7。

状态7:计算UDP数据长度, 计算UDP长度的checksum, 跳转到状态8。验证UDP源port, 目的port是否正确,如果不正确,立起udp_rx_error。

状态8:计算UDP checksum (16-bit)的checksum, 跳转到状态9。注意这里判断了udp_rx_len[15]是否为1,如果为1,则表示在状态7中  udp_rx_len <= udp_rx_data[11:0] – 8;   的结果是负数,因此说明UDP的长度小于8(包头不完整),转到状态13,并立起udp_rx_error。这里也收集前面状态7的UDP源port或 目的port错误,转到状态13。如果没有错误,转到状态9。

状态9:根据UDP数据计算checksum,读出数据,如果剩余数据大于两个byte,转到状态10;如果剩余数据少于两个byte,转到状态12,注意要区分剩余1个byte数据,和数据偶数个被读完的情况(剩余0个byte数据)。

状态10:根据UDP数据计算checksum,读出数据,如果剩余数据大于两个byte,转到状态9;如果剩余数据少于两个byte,继续判断:如果剩余1个byte数据,转到状态11;如果是数据偶数个被读完的情况(剩余0个byte数据),转到状态12。

状态11:处理奇数长度的最后一个数据,同时计算checksum,跳转到状态12;

状态12:计算checksum的结果,如果计算的结果正确或者UDP包中checksum位置填写的是0,跳转到状态13; 如果checksum计算的结果不对,表示checksum 错误信息,跳转到状态13

状态13:清除UDP_RX_DRAM的封包字节, 跳转到状态14。

状态14:跳转到状态15。

状态15:UDP_RX_DRAM的A/B Buffer 位置加一, 跳转到状态0。

 

UDP rx state machine flowchart

图3 udp_rx_st流程图

 

eth_udp_rx.v 代码:

`timescale 1ns / 1ps


module eth_udp_rx #
(
    parameter [15:0] UDP_RX_SRC_PORT    = 16'hffff,
    parameter UDP_RX_SRC_PORT_EN        = 0,
    parameter [15:0] UDP_RX_DES_PORT    = 16'hffff,
    parameter UDP_RX_DES_PORT_EN        = 0,
    
    parameter IP_BUF_SIZE    = 10,
    parameter IP_IDX_BIT     = 1
)
(
    input         sys_clk,

    output reg    udp_rx_web = 0,
    output [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_rx_addrb,
    input  [15:0] udp_rx_doutb,
    
    output reg [7:0] udp_dout = 0,
    output reg    udp_dout_en = 0,
    
    output reg [3:0] udp_rx_error = 0, // 0: checksum err; 1: src_port err; 2: des_port err; 3: udp len err

    input         reset
);
//=========================================================================
//=========================================================================
reg  [IP_BUF_SIZE - 1:0] udp_rx_addrb_sub = 0;
reg  [IP_IDX_BIT - 1:0] udp_rx_idb = 0;
assign udp_rx_addrb = {udp_rx_idb, udp_rx_addrb_sub};

//=======================================================================   
reg udp_chksum_flag = 0;
reg [31:0] udp_port = 0; // {src port, des port}
wire [15:0] udp_rx_data = {udp_rx_doutb[7:0], udp_rx_doutb[15:8]};

reg  [31:0] udp_checksum = 0;
reg  [15:0] udp_rx_cnt = 0;
reg  [15:0] udp_rx_len = 0;
reg  [3:0]  udp_rx_st = 0;
always @ (posedge sys_clk)
if(reset)
begin
    udp_rx_idb <= 0;
    udp_rx_web <= 0;
    
    udp_rx_st <= 0;
end 
else case (udp_rx_st)
0:
begin
    udp_chksum_flag <= 0;
    udp_rx_error <= 0;
    
    udp_dout_en <= 0;
    udp_checksum <= -20;   //len in IP header = len in UDP header + 20
    udp_rx_cnt <= 0;
    
    udp_rx_web <= 0;
    udp_rx_addrb_sub <= {IP_BUF_SIZE{1'b1}};
    
    udp_rx_st <= 1;
end
1:
begin
    udp_rx_web <= 0;
    udp_rx_addrb_sub <= {IP_BUF_SIZE{1'b1}};

    udp_rx_st <= 2;
end
2:
begin
    if(udp_rx_doutb[15] == 1)
    begin
        udp_rx_addrb_sub <= 8;  // jump to IP header length position
        udp_rx_st <= 3;
    end
end
3:
begin
    udp_rx_len <= udp_rx_doutb[11:0];
    udp_rx_addrb_sub <= 11; // ip protocol
    
    udp_rx_st <= 4;
end
4:
begin
    udp_checksum <= udp_checksum + udp_rx_data;
    udp_rx_addrb_sub <= 13; // src ip
    
    udp_rx_st <= 5;
end
5:
begin
    udp_checksum <= udp_checksum + {8'h00,udp_rx_data[7:0]};
    udp_rx_addrb_sub <= 14; // src ip
    
    udp_rx_st <= 6;
end
6:
begin
    udp_checksum <= udp_checksum + udp_rx_data;
    udp_rx_addrb_sub <= udp_rx_addrb_sub + 1;
    
    udp_port <= {udp_port[15:0], udp_rx_data}; // get udp src port and des port 
    if(udp_rx_addrb_sub == 19)
    begin
        udp_rx_st <= 7;
    end
end
7:
begin
    udp_rx_len <= udp_rx_data[11:0] - 8;

    udp_checksum <= udp_checksum + udp_rx_data;
    udp_rx_addrb_sub <= udp_rx_addrb_sub + 1;
    
    if( UDP_RX_SRC_PORT_EN && (udp_port[31:16] != UDP_RX_SRC_PORT) )
    begin
        udp_rx_error[1] <= 1;
    end
    
    if( UDP_RX_DES_PORT_EN && (udp_port[15:00] != UDP_RX_DES_PORT) )
    begin
        udp_rx_error[2] <= 1;
    end
    
    udp_rx_st <= 8;
end
8:
begin
    udp_checksum <= udp_checksum + udp_rx_data;

    if(udp_rx_data == 0) // udp do not calculate checksum
        udp_chksum_flag <= 1;
    
    if(udp_rx_len[15])  // udp_rx_len < 8 bytes no payload error
    begin
        udp_rx_error[3] <= 1;
        udp_rx_st <= 13;
    end
    else if(|udp_rx_error)
        udp_rx_st <= 13;
    else                // calculate checksum
        udp_rx_st <= 9;
        
end
9:
begin
    udp_dout <= udp_rx_doutb[7:0];
    udp_dout_en <= 1;

    udp_rx_cnt <= udp_rx_cnt + 2;
    udp_rx_addrb_sub <= udp_rx_addrb_sub + 1;

    if(udp_rx_len == 0)
    begin
        udp_dout_en <= 0;
        udp_rx_st <= 12;
    end
    else if(udp_rx_len == 1)
    begin
        udp_checksum <= udp_checksum + {udp_rx_data[15:8], 8'h00};
        udp_rx_st <= 12;
    end
    else
    begin
        udp_checksum <= udp_checksum + udp_rx_data;
        udp_rx_st <= 10;
    end
end
10:
begin
    udp_dout <= udp_rx_doutb[15:8];
    udp_dout_en <= 1;
    
    if(udp_rx_cnt == {udp_rx_len[15:1], 1'b0})
    begin
        if(udp_rx_len[0]) udp_rx_st <= 11;
        else udp_rx_st <= 12;
    end
    else
        udp_rx_st <= 9;
        
end
11:
begin
    udp_checksum <= udp_checksum + {udp_rx_data[15:8], 8'h00};
    udp_dout <= udp_rx_doutb[7:0];
    udp_dout_en <= 1;

    udp_rx_st <= 12;
end
12:
begin
    udp_dout_en <= 0;
    
    if(|udp_checksum[31:16])
        udp_checksum <= udp_checksum[15:0] + udp_checksum[31:16];
    else
    begin
        udp_checksum <= ~udp_checksum;
        
        if(udp_checksum[15:0] == 16'hffff  || udp_chksum_flag == 1)
            udp_rx_st <= 13; // checksum ok
        else
        begin
            udp_rx_error[0] <= 1;
            udp_rx_st <= 13; // checksum error    
        end
    end    
end
13:
begin
    udp_dout_en <= 0;
    
    udp_rx_addrb_sub <=  {IP_BUF_SIZE{1'b1}};
    udp_rx_web <= 1;
    
    udp_rx_st <= 14;
end
14:
begin
    udp_rx_web <= 0;
    udp_rx_st <= 15;
end


15: // normal finished
begin
    udp_rx_idb <= udp_rx_idb + 1;
    
    udp_rx_web <= 0;
    udp_rx_st <= 0;
end
default: udp_rx_st <= 0;
endcase

//=========================================================================


    
endmodule

 

 

 

Posted in FPGA, FPGA 教材教案, RISC-V, Verilog, Verilog, 教材与教案, 文章

发表回复

相关链接