基于FPAG的UDP数据包的收发

`timescale 1ns / 1ps
//
// Module name  :   udp_rcv        
// Project name : 
// Target device:             
// Author       :   lixiongxiong
// Create Date  :           
// Tool version : 
// Description  :   

// IP datagram header format
//
//    0          4          8                      16      19             24                    31
//    --------------------------------------------------------------------------------------------
//    |             src port                       |                  dst port                   |
//    |                                            |                                             |
//    --------------------------------------------------------------------------------------------
//    |           UDP length                       |                  checksum                   |
//    |                                            |                                             |
//    --------------------------------------------------------------------------------------------
//    |                                          Data                                            |
//    |                                                                                          |
//    --------------------------------------------------------------------------------------------
//    |                                          ....                                            |
//    |                                                                                          |
//    --------------------------------------------------------------------------------------------
//
// * - in 32 bit words 

// All rights reserved,Software Technology Co., Ltd Wuhan
//
module udp_rcv
(
input                   tx_clk              ,
input                   reset               ,
input       [31:0]      ip_rcv_src_ip_addr  ,
input       [7 :0]      udp_rcv_data        ,
input                   udp_rcv_vld         ,
output  reg [15:0]      udp_rcv_data_length ,
output  reg [15:0]      udp_rcv_src_port    ,
output  reg [15:0]      udp_rcv_dst_port    ,
output  reg [31:0]      udp_rcv_src_ip_addr ,
output  reg [7 :0]      udp_rcv_pdata       ,
output  reg             udp_rcv_pvld        ,
output  reg [15:0]      udp_rcv_pkt_cnt      
);

reg         [11:0]      byte_counter        ;
/*****************************************************************************************

******************************************************************************************/
always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        byte_counter <= 12'd0;
    else if(udp_rcv_vld == 1'b1)
        byte_counter <= byte_counter + 1'b1;
    else
        byte_counter <= 12'd0;    
end
/*****************************************************************************************

******************************************************************************************/
always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        begin
            udp_rcv_data_length<= 16'd0;
            udp_rcv_src_port <= 16'd0;
            udp_rcv_dst_port <= 32'd0;
            udp_rcv_pdata <= 8'd0;
            udp_rcv_pvld <= 1'b0;
            udp_rcv_src_ip_addr <= 32'd0;
        end    
    else if(udp_rcv_vld == 1'b1)
        begin
            case(byte_counter)
                12'd0:  begin
                            udp_rcv_src_port[15:8] <= udp_rcv_data;
                            udp_rcv_src_ip_addr <= ip_rcv_src_ip_addr;
                        end    
                12'd1:  udp_rcv_src_port[7:0] <= udp_rcv_data;
                12'd2:  udp_rcv_dst_port[15:8] <= udp_rcv_data;
                12'd3:  udp_rcv_dst_port[7:0] <= udp_rcv_data;
                12'd4:  udp_rcv_data_length[15:8] <= udp_rcv_data;
                12'd5:  udp_rcv_data_length[7:0] <= udp_rcv_data;
                12'd6: ;
                12'd7: ; 
                default:
                        begin
                            udp_rcv_pdata <= udp_rcv_data;
                            udp_rcv_pvld  <= 1'b1;
                        end    
            endcase    
        end
    else
        begin
            udp_rcv_pdata <= 8'd0;
            udp_rcv_pvld  <= 1'b0;
        end            
end


/*****************************************************************************************
status calc
******************************************************************************************/
reg                     udp_rcv_vld_dly     ;

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_rcv_vld_dly <= 1'd0;
    else
        udp_rcv_vld_dly <= udp_rcv_vld;   
end

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_rcv_pkt_cnt <= 16'd0;
    else if((udp_rcv_vld == 1'b1)&&(udp_rcv_vld_dly == 1'b0))
        udp_rcv_pkt_cnt <= udp_rcv_pkt_cnt + 1'b1;   
end


endmodule

`timescale 1ns / 1ps
//
// Module name  :   udp_send        
// Project name : 
// Target device:             
// Author       :   lixiongxiong
// Create Date  :           
// Tool version : 
// Description  :   

// IP datagram header format
//
//    0          4          8                      16      19             24                    31
//    --------------------------------------------------------------------------------------------
//    |             src port                       |                  dst port                   |
//    |                                            |                                             |
//    --------------------------------------------------------------------------------------------
//    |           UDP length                       |                  checksum                   |
//    |                                            |                                             |
//    --------------------------------------------------------------------------------------------
//    |                                          Data                                            |
//    |                                                                                          |
//    --------------------------------------------------------------------------------------------
//    |                                          ....                                            |
//    |                                                                                          |
//    --------------------------------------------------------------------------------------------
//
// * - in 32 bit words 

// All rights reserved,Software Technology Co., Ltd Wuhan
//
module udp_send
(
input                   tx_clk              ,
input                   reset               ,
input       [7 :0]      udp_send_pdata      ,
input                   udp_send_pvld       ,
output                  udp_send_ready      ,
input       [15:0]      udp_send_src_port   ,
input       [15:0]      udp_send_dst_port   ,
input       [31:0]      udp_send_dst_ip_addr,
input       [31:0]      our_ip_address      ,
output                  udp_nwk_req         ,
output      [15:0]      udp_send_data_length,
output  reg [31:0]      udp_send_dst_ip_addr_r,
output  reg [7 :0]      udp_send_data       ,
output  reg             udp_send_vld        ,
output  reg [15:0]      udp_send_drop_pkt_cnt,
output  reg [15:0]      udp_send_pkt_cnt
);

reg         [2 :0]      udp_tx_state        ;
reg         [2 :0]      nxt_udp_tx_state    ;
reg         [1 :0]      udp_send_pvld_dly   ;
reg         [7 :0]      udp_send_pdata_dly1 ;
reg         [7 :0]      udp_send_pdata_dly2 ;
wire                    rcv_start           ;
wire                    rcv_end             ;
wire                    udp_send_end        ;
reg         [10:0]      byte_counter        ;
reg         [10:0]      udp_send_pdata_length;
wire        [15:0]      udp_send_data_length1;
wire        [15:0]      udp_send_data_length2;
wire                    ram_wren            ;
reg         [15:0]      checksum1           ;
wire        [15:0]      checksum_send       ;
reg         [3 :0]      gen_checksum_cnt    ;
wire                    gen_checksum_end    ;
reg         [15:0]      udp_send_src_port_r ;
reg         [15:0]      udp_send_dst_port_r ;
reg         [10:0]      udp_reply_cnt       ;
reg         [10:0]      rdaddress           ;
wire        [7 :0]      ram_rdata           ;
             
wire                    udp_send_drop       ;


localparam  IDLE            = 3'd0;
localparam  RECEIVE         = 3'd1;
localparam  GEN_CHECKSUM    = 3'd2;   
localparam  SEND            = 3'd3; 

/*****************************************************************************************

******************************************************************************************/
always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        begin   
            udp_send_src_port_r<= 16'd0;
            udp_send_dst_port_r<= 16'd0;
            udp_send_dst_ip_addr_r<= 32'd0;
        end    
    else if(rcv_start == 1'b1)
        begin   
            udp_send_src_port_r <= udp_send_src_port;
            udp_send_dst_port_r <= udp_send_dst_port;
            udp_send_dst_ip_addr_r <= udp_send_dst_ip_addr;
        end    
end

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        begin   
            udp_send_pvld_dly <= 2'd0;
            udp_send_pdata_dly1<= 8'd0;
            udp_send_pdata_dly2<= 8'd0;
        end    
    else
        begin   
            udp_send_pvld_dly <= {udp_send_pvld_dly[0],udp_send_pvld};
            udp_send_pdata_dly1<= udp_send_pdata;
            udp_send_pdata_dly2<= udp_send_pdata_dly1;
        end    
end

assign rcv_start = ((udp_send_pvld == 1'b1)&&(udp_send_pvld_dly[0] == 1'b0)) ? 1'b1 : 1'b0;
assign rcv_end = ((udp_send_pvld_dly[0] == 1'b0)&&(udp_send_pvld_dly[1] == 1'b1)) ? 1'b1 : 1'b0;
assign gen_checksum_end = ((udp_tx_state == GEN_CHECKSUM)&&(gen_checksum_cnt == 4'd9)) ? 1'b1 : 1'b0;

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        byte_counter <= 11'd0;
    else if((udp_send_pvld_dly[0] == 1'b1)&&(udp_tx_state == RECEIVE))
        byte_counter <= byte_counter + 1'b1;
    else
        byte_counter <= 11'd0;    
end

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        gen_checksum_cnt <= 4'd0;
    else if(udp_tx_state == GEN_CHECKSUM)
        gen_checksum_cnt <= gen_checksum_cnt + 1'b1;
    else
        gen_checksum_cnt <= 4'd0;    
end

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_send_pdata_length <= 10'd0;
    else if((udp_send_pvld_dly[0] == 1'b0)&&(udp_send_pvld_dly[1] == 1'b1))
        udp_send_pdata_length <= byte_counter;  
end

assign udp_send_data_length1 = {5'd0,udp_send_pdata_length}+16'd8;
assign udp_send_data_length2 = {5'd0,udp_send_pdata_length}+16'd8 + 16'd20;
assign udp_send_data_length  = udp_send_data_length2;
/*****************************************************************************************

******************************************************************************************/

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_tx_state <= IDLE;
    else
        udp_tx_state <= nxt_udp_tx_state;
end

always@(*)
begin
    case(udp_tx_state)
        IDLE:
            begin
                if(rcv_start == 1'b1)
                    nxt_udp_tx_state = RECEIVE; 
                else
                    nxt_udp_tx_state = IDLE;
            end
        RECEIVE:
            begin
                if(rcv_end == 1'b1)
                    nxt_udp_tx_state = GEN_CHECKSUM;
                else
                    nxt_udp_tx_state = RECEIVE; 
            end
        GEN_CHECKSUM:
            begin
                if(gen_checksum_end == 1'b1)
                    nxt_udp_tx_state = SEND;   
                else
                    nxt_udp_tx_state = GEN_CHECKSUM;
            end
        SEND:
            begin
                if(udp_send_end == 1'b1)
                    nxt_udp_tx_state = IDLE;   
                else
                    nxt_udp_tx_state = SEND;
            end           
        default:
            nxt_udp_tx_state <= IDLE;
    endcase                                  
end


/*****************************************************************************************

******************************************************************************************/
assign ram_wren = ((udp_tx_state == RECEIVE)&&(udp_send_pvld_dly[0] == 1'b1)) ? 1'b1 : 1'b0;

dpram_8d_10a u_dpram_8d_10a (
    .clock              ( tx_clk                ),
    .data               ( udp_send_pdata_dly1   ),
    .rdaddress          ( rdaddress             ),
    .wraddress          ( byte_counter          ),
    .wren               ( ram_wren              ),
    .q                  ( ram_rdata             )
    );

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        rdaddress <= 11'd0;
    else if((udp_tx_state == SEND)&&(udp_reply_cnt >= 11'd41))
        rdaddress <= udp_reply_cnt-11'd41;
    else
        rdaddress <= 11'd0;       
end

/*****************************************************************************************

******************************************************************************************/
always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        checksum1 <= 16'd0; 
    else 
        begin
            case(udp_tx_state)
                IDLE:   checksum1 <= 16'd0;
                RECEIVE:
                    begin
                        if((udp_send_pvld_dly[0] == 1'b0)&&(udp_send_pvld_dly[1] == 1'b1)
                                &&(byte_counter[0] == 1'b1))
                            checksum1 <= complement({udp_send_pdata_dly2,8'h00},checksum1);
                        else if((udp_send_pvld_dly[0] == 1'b1)&&(byte_counter[0] == 1'b1))
                            checksum1 <= complement({udp_send_pdata_dly2,udp_send_pdata_dly1},checksum1);
                        else
                            checksum1 <= checksum1;    
                    end
                GEN_CHECKSUM:
                    begin
                        case(gen_checksum_cnt)
                            4'd0:   checksum1 <= complement(our_ip_address[31:16],checksum1);
                            4'd1:   checksum1 <= complement(our_ip_address[15:0],checksum1);
                            4'd2:   checksum1 <= complement(udp_send_dst_ip_addr[31:16],checksum1);
                            4'd3:   checksum1 <= complement(udp_send_dst_ip_addr[15:0],checksum1);
                            4'd4:   checksum1 <= complement({8'd0,8'd17},checksum1);
                            4'd5:   checksum1 <= complement(udp_send_data_length1,checksum1);
                            4'd6:   checksum1 <= complement(udp_send_src_port_r,checksum1);   
                            4'd7:   checksum1 <= complement(udp_send_dst_port_r,checksum1);   
                            4'd8:   checksum1 <= complement(udp_send_data_length1,checksum1);
                            4'd9:   checksum1 <= complement(16'd0,checksum1);  
                            default:;
                        endcase
                    end
                SEND: checksum1 <= checksum1;
                default: checksum1 <= checksum1;
            endcase
        end        
end

assign checksum_send = ~checksum1;


function    [15:0]  complement
(
input       [15:0]  dataina,
input       [15:0]  datainb
);

reg [16:0]  temp    ;

begin
    temp = dataina + datainb;
    complement = temp[15:0]+temp[16];
end  
 
endfunction 

/*****************************************************************************************

******************************************************************************************/
assign udp_nwk_req = gen_checksum_end;
assign udp_send_ready = (udp_tx_state == IDLE) ? 1'b1 : 1'b0;

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_reply_cnt <= 11'd0;
    else if(udp_tx_state == SEND)
        udp_reply_cnt <= udp_reply_cnt + 1'b1;
    else
        udp_reply_cnt <= 11'd0;       
end

assign udp_send_end = ((udp_reply_cnt == udp_send_pdata_length+8+20+14-1)&&(udp_tx_state == SEND)) ? 1'b1 : 1'b0;
                                                                   //8-->udp header length
                                                                   //20-->ip header length
                                                                   //14-->ETH header length

always @(*)
begin
    if(udp_reply_cnt < 11'd35)
        udp_send_data = 8'd0;
    else if(udp_reply_cnt == 11'd35)
        udp_send_data = udp_send_src_port_r[15:8];
    else if(udp_reply_cnt == 11'd36)
        udp_send_data = udp_send_src_port_r[7:0];    
    else if(udp_reply_cnt == 11'd37)
        udp_send_data = udp_send_dst_port_r[15:8];
    else if(udp_reply_cnt == 11'd38)
        udp_send_data = udp_send_dst_port_r[7:0]; 
    else if(udp_reply_cnt == 11'd39)
        udp_send_data = udp_send_data_length1[15:8];
    else if(udp_reply_cnt == 11'd40)
        udp_send_data = udp_send_data_length1[7:0];  
    else if(udp_reply_cnt == 11'd41)
        udp_send_data = checksum_send[15:8];
    else if(udp_reply_cnt == 11'd42)
        udp_send_data = checksum_send[7:0];          
    else
        udp_send_data = ram_rdata;    
end

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_send_vld <= 1'd0;
    else if(udp_tx_state == SEND)
        udp_send_vld <= 1'b1;
    else
        udp_send_vld <= 1'd0;    
end

/*****************************************************************************************
status calc
******************************************************************************************/

assign udp_send_drop = ((rcv_start == 1'b1)&&(udp_send_ready == 1'b0)) ? 1'b1 : 1'b0;

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_send_drop_pkt_cnt <= 16'd0;
    else if(udp_send_drop == 1'b1)
        udp_send_drop_pkt_cnt <= udp_send_drop_pkt_cnt + 1'b1;   
end

always @(posedge tx_clk or negedge reset)
begin
    if(reset == 1'b0)
        udp_send_pkt_cnt <= 16'd0;
    else if(rcv_start == 1'b1)
        udp_send_pkt_cnt <= udp_send_pkt_cnt + 1'b1;   
end

endmodule

你可能感兴趣的:(FPGA,板块5:网络通信,UDP)