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

图1

图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。

图3 udp_rx_st流程图
eth_udp_rx.v 代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
`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 |