【以太网通信】FPGA 实现 UDP 协议的校验

UDP 协议提供了一种低延迟的网络通信方式,通信效率高,但不保证接收的可靠性,常用在以太网图像传输等高速通信场合。

目录

1 UDP 协议

2 校验过程

3 HDL 描述


1 UDP 协议

        用户数据报协议(User Datagram Protocol, UDP)是一种面向无连接的传输协议,采用这种协议的通讯,无需事先建立连接。

        UDP 数据段由 UDP 首部和数据两部分组成,其中首部的长度固定为 8 个字节,首部包括源端口、目的端口、UDP 长度和 16 位校验和。

2 校验过程

        UDP 协议校验时需要添加 12 字节的伪首部,并且和 IP 协议不同,UDP 协议还需要校验数据。发送数据时,UDP 协议的校验步骤为:

(1)在 UDP 首部前添加 12 字节的伪首部;

(2)将首部校验和部分置零为 0x0000;

(3)以 16bit 为字长进行反码求和(数据不足的需补齐 16bit);

(4)将校验结果填充到 UDP 首部。

        接收数据时,UDP 协议的校验步骤为:

(1)在 UDP 首部前添加 12 字节的伪首部;

(2)以 16bit 为字长进行反码求和;

(3)判断校验结果是否为 0xFFFF;

(4)若检验结果为 0xFFFF,校验通过;否则检验失败,丢弃该数据段。

3 HDL 描述

        根据反码求和的特性,可以把 UDP 协议的校验分两部分处理,伪首部 + 首部的校验为一部分,UDP 用户数据的校验为另一部分。用户数据的校验需要根据实际的位宽,转换为 16bit。

VHDL 版本

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity validate_udp is
   port(
      -- System level
      sys_rst         : in std_logic;
      sys_clk         : in std_logic;
		
      -- IP and UDP information
      local_ip_addr   : in std_logic_vector(4*8-1 downto 0);
      remote_ip_addr  : in std_logic_vector(4*8-1 downto 0);
      local_udp_port  : in std_logic_vector(2*8-1 downto 0);
      remote_udp_port : in std_logic_vector(2*8-1 downto 0);
      udp_packet_len  : in std_logic_vector(2*8-1 downto 0);
		
      -- UDP user data input
      udp_usr_data    : in std_logic_vector(7 downto 0);
      udp_usr_wren    : in std_logic;
		
      -- UDP checksum output
      udp_checksum    : out std_logic_vector(2*8-1 downto 0)
	);
end entity;
architecture behav of validate_udp is
   -- internal signal declarations
   subtype word is std_logic_vector(15 downto 0);
   type check_info_t is array(0 to 9) of word;
   signal udp_check_info: check_info_t;
	
   signal usr_data_buf: std_logic_vector(15 downto 0);
   signal usr_wren_toggle: std_logic;
   signal usr_wren_toggle_d1: std_logic;
   signal checksum_head: std_logic_vector(15 downto 0);
   signal checksum_data: std_logic_vector(15 downto 0);

   function checksum_adder(
      ina: std_logic_vector(15 downto 0);
      inb: std_logic_vector(15 downto 0)
   ) return std_logic_vector is
      variable tmp1,tmp2,tmp: std_logic_vector(31 downto 0);
   begin
      tmp1 := X"0000" & ina;
      tmp2 := X"0000" & inb;
      tmp := tmp1 + tmp2;
      return tmp(15 downto 0) + tmp(31 downto 16);
   end function;

   function checksum_out(
      ina: std_logic_vector(15 downto 0);
      inb: std_logic_vector(15 downto 0)
   ) return std_logic_vector is
      variable tmp1,tmp2,tmp: std_logic_vector(31 downto 0);
   begin
      tmp1 := X"0000" & ina;
      tmp2 := X"0000" & inb;
      tmp := tmp1 + tmp2;
      return not(tmp(15 downto 0) + tmp(31 downto 16));
   end function;

begin
   -- todo
   process(sys_rst,sys_clk)
   begin 
      if sys_rst = '1' then 
         udp_check_info <= (others => (others => '0'));
      elsif rising_edge(sys_clk) then 
         udp_check_info(0) <= local_ip_addr(4*8-1 downto 2*8);
         udp_check_info(1) <= local_ip_addr(2*8-1 downto 0*8);
         udp_check_info(2) <= remote_ip_addr(4*8-1 downto 2*8);
         udp_check_info(3) <= remote_ip_addr(2*8-1 downto 0*8);
         udp_check_info(4) <= X"0011";  -- UDP protocol
         udp_check_info(5) <= udp_packet_len;
         udp_check_info(6) <= local_udp_port;
         udp_check_info(7) <= remote_udp_port;
         udp_check_info(8) <= udp_packet_len;
         udp_check_info(9) <= X"0000";  -- UDP Checksum padding
      end if;
   end process;

   process(udp_check_info)
      variable tmp: std_logic_vector(31 downto 0);
   begin
      tmp := (others => '0');
      for i in 0 to 9 loop
         tmp := tmp + udp_check_info(i);
      end loop;
      checksum_head <= tmp(15 downto 0) + tmp(31 downto 16);
   end process;

   process(sys_rst,sys_clk) 
   begin
      if sys_rst = '1' then
         usr_data_buf <= (others => '0');
         usr_wren_toggle <= '0';
         usr_wren_toggle_d1 <= '0';
      elsif rising_edge(sys_clk) then
         if udp_usr_wren = '1' then
            usr_data_buf <= usr_data_buf(7 downto 0) & udp_usr_data;
         else
            usr_data_buf <= (others => '0');
         end if;
		
         if udp_usr_wren = '1' then
            usr_wren_toggle <= not usr_wren_toggle;
         else
            usr_wren_toggle <= '0';
         end if;
		
         usr_wren_toggle_d1 <= usr_wren_toggle;
      end if;
   end process;

   process(sys_rst,sys_clk)
   begin
      if sys_rst = '1' then
         checksum_data <= (others => '0');
      elsif rising_edge(sys_clk) then
         if usr_wren_toggle_d1 = '1' then
            checksum_data <= checksum_adder(checksum_data, usr_data_buf);
         else
            checksum_data <= (others => '0');
         end if;
      end if;
   end process;

   process(sys_rst,sys_clk)
   begin
      if sys_rst = '1' then
         udp_checksum <= (others => '0');
      elsif rising_edge(sys_clk) then
         udp_checksum <= checksum_out(checksum_head, checksum_data);
      end if;
   end process;
end architecture;

Verilog 版本

`timescale 1ns / 1ps

module validate_udp(
	// System level
	sys_rst,
	sys_clk,
	
	// IP and UDP information
	local_ip_addr,
	remote_ip_addr,
	local_udp_port,
	remote_udp_port,
	udp_packet_len,
	
	// UDP user data input
	udp_usr_data,
	udp_usr_wren,
	
	// UDP checksum output
	udp_checksum
);

	// IO ports declarations
	input            sys_rst;
	input            sys_clk;
	input  [4*8-1:0] local_ip_addr;
	input  [4*8-1:0] remote_ip_addr;
	input  [2*8-1:0] local_udp_port;
	input  [2*8-1:0] remote_udp_port;
	input  [2*8-1:0] udp_packet_len;
	input  [7:0]     udp_usr_data;
	input            udp_usr_wren;
	output [2*8-1:0] udp_checksum;
	reg    [2*8-1:0] udp_checksum;
	
	// internal function declarations
	function [15:0] checksum_adder;
		input [15:0] ina;
		input [15:0] inb;
		integer tmp,tmp1,tmp2;
	begin
		tmp1 = {16'd0, ina};
		tmp2 = {16'd0, inb};
		tmp = tmp1 + tmp2;
		checksum_adder = tmp[15:0] + tmp[31:16];
	end
	endfunction
	
	function [15:0] checksum_output;
		input [15:0] ina;
		input [15:0] inb;
		integer tmp,tmp1,tmp2;
	begin
		tmp1 = {16'd0, ina};
		tmp2 = {16'd0, inb};
		tmp = tmp1 + tmp2;
		checksum_output = ~(tmp[15:0] + tmp[31:16]);
	end
	endfunction

	// internal signal declarations
	reg [2*8-1:0] udp_check_info[9:0];
	reg [2*8-1:0] checksum_head,checksum_data;
	reg [4*8-1:0] tmp1,tmp2;
	
	reg [2*8-1:0] usr_data_buf;
	reg           usr_wren_toggle,usr_wren_toggle_d1;
	
	integer i;
	
	always@(posedge sys_rst or posedge sys_clk) begin
		if(sys_rst)
			for(i = 0; i < 10; i=i+1)
				udp_check_info[i] <= 16'h0000;
		else begin
			udp_check_info[0] <= local_ip_addr[4*8-1-:16];
			udp_check_info[1] <= local_ip_addr[2*8-1-:16];
			udp_check_info[2] <= remote_ip_addr[4*8-1-:16];
			udp_check_info[3] <= remote_ip_addr[2*8-1-:16];
			udp_check_info[4] <= 16'h0011;  // UDP protocol
			udp_check_info[5] <= udp_packet_len;
			udp_check_info[6] <= local_udp_port;
			udp_check_info[7] <= remote_udp_port;
			udp_check_info[8] <= udp_packet_len;
			udp_check_info[9] <= 16'h0000;  // UDP checksum bytes padding
		end
	end
	
	always@(*) begin
		tmp1 = 32'd0;
		for(i = 0; i < 10; i=i+1) begin
			tmp1 = tmp1 + udp_check_info[i];
		end
		checksum_head = tmp1[15:0] + tmp1[31:16];
	end
	
	always@(posedge sys_rst or posedge sys_clk) begin
		if(sys_rst) begin
			usr_data_buf <= 16'd0;
			usr_wren_toggle <= 1'd0;
			usr_wren_toggle_d1 <= 1'd0;
		end
		else begin
			if(udp_usr_wren)
				usr_data_buf <= {usr_data_buf[7:0], udp_usr_data};
			else
				usr_data_buf <= 16'd0;
				
			if(udp_usr_wren)
				usr_wren_toggle <= ~usr_wren_toggle;
			else
				usr_wren_toggle <= 1'd0;
				
			usr_wren_toggle_d1 <= usr_wren_toggle;				
		end		
	end
	
	always@(posedge sys_rst or posedge sys_clk) begin
		if(sys_rst)
			checksum_data <= 16'd0;
		else
			if(usr_wren_toggle_d1)
				checksum_data <= checksum_adder(checksum_data, usr_data_buf);
			else
				checksum_data <= 16'd0;
	end
	
	always@(posedge sys_rst or posedge sys_clk) begin
		if(sys_rst)
			udp_checksum <= 16'd0;
		else
			udp_checksum <= checksum_output(checksum_head, checksum_data);
	end
endmodule

        综合得到的 RTL 电路如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋洋Young

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值