eth_ip_tx.v 模块是从UDP_TX_DRAM双端口中读取数据,加上MAC头 + 0800 + IP头 ,计算好IP头的checksum ,之后将数据流发送到TX_IP_FIFO中去.

图1

图2
ip_tx_st 状态机解析:
状态0: 初始化相关的数据, 将UDP_TX_DRAM 的子地址指向 1023,跳转到状态机1。
状态1: 等待1个时钟周期,跳转到状态机2。
状态2: 检查UDP_TX_DRAM 的子地址1023,查看双端口读取出的数据,看看UDP是否有数据准备发送,如果有,跳转到状态机3。
状态3: 根据读出的UDP长度,计算出IP包的长度和以太网包的长度,跳转到状态机4。
状态4: 查看FIFO是否有空间可以存储数据,如果有足够的空间,跳转到状态机5。
状态5: 首先将长度信息写入到FIFO中去,跳转到状态机6。
状态6 – 8: 写入目的MAC地址,跳转到状态机9。
状态9 – 11: 写入源MAC地址,跳转到状态机12。
状态12: 写入0800 以太网类型 ,跳转到状态机13。
状态13- 22: 写入IP头信息 ,跳转到状态机23。
状态23: 读取UDP的数据,写入到FIFO中去,跳转到状态机24。
状态24: 清除UDP双端口,写入FIFO封口信息,跳转到状态机25。
状态25: 清除相关的寄存器 ,跳转到状态机26。
状态26: UDP乒乓buffer 地址转换,跳转到状态机0。
副状态机(ip_chk_st)计算IP头checksum :
在发送ip 包时,4500, 4000, 4011 , 前面6 bytes 的信息是固定的,直接计算好checksum 即可。
状态0: 计算 length 的checksum, 跳转状态1。
状态1: 计算 源IP的checksum, 跳转状态2。
状态2: 计算 源IP的checksum, 跳转状态3。
状态3: 计算 目的IP的checksum, 跳转状态4。
状态4: 计算 目的IP的checksum, 跳转状态5。
状态5: 计算 最终的checksum结果, 跳转状态6。
状态6: 表示checksum 计算结束。
状态机的示意图如图3(注意省略了状态转移条件不满足时,停留在当前状态的箭头)所示:

图3 状态机示意图
eth_ip_tx.v 代码:
`timescale 1ns / 1ps
module eth_ip_tx #
(
parameter [47:0] TX_MAC_SRC = 48'h66_72_61_73_65_72,
parameter [47:0] TX_MAC_DES = 48'hff_ff_ff_ff_ff_ff,
parameter [31:0] TX_IP_SRC = 32'hc0a8003d,
parameter [31:0] TX_IP_DES = 32'hc0a800ff,
parameter IP_BUF_SIZE = 10,
parameter IP_IDX_BIT = 1
)
(
input sys_clk,
input udp_tx_wea,
input [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_tx_addra,
input [15:0] udp_tx_dina,
output [15:0] udp_tx_douta,
output [17:0] ip_fifo_din,
output reg ip_fifo_we = 0,
input [15:0] ip_fifo_cnt, //write sync cnt, the max fifo depth is 2047
input reset
);
//=========================================================================
reg udp_tx_web = 0;
reg [IP_BUF_SIZE - 1:0] udp_tx_addrb_sub = 0;
reg [IP_IDX_BIT - 1:0] udp_tx_idb = 0;
wire [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_tx_addrb = {udp_tx_idb, udp_tx_addrb_sub};
wire [15:0] udp_tx_doutb;
UDP_DRAM UDP_TX_DRAM_inst
(
.clka (sys_clk), // input wire clka
.wea (udp_tx_wea), // input wire [0 : 0] wea
.addra (udp_tx_addra), // input wire [10 : 0] addra
.dina (udp_tx_dina), // input wire [15 : 0] dina
.douta (udp_tx_douta), // output wire [15 : 0] douta
.clkb (sys_clk), // input wire clkb
.web (udp_tx_web), // input wire [0 : 0] web
.addrb (udp_tx_addrb), // input wire [10 : 0] addrb
.dinb (0), // input wire [15 : 0] dinb
.doutb (udp_tx_doutb) // output wire [15 : 0] doutb
);
//=========================================================================
reg [1:0] ip_fifo_flag = 0;
reg [15:0] ip_fifo_data = 0;
assign ip_fifo_din = {ip_fifo_flag[1], ip_fifo_data[15:8], ip_fifo_flag[0], ip_fifo_data[7:0]};
wire [15:0] ip_fifo_blank = 2047 - ip_fifo_cnt;
//=======================================================================
reg [15:0] ip_tx_len = 0; //udp包长 + 20
reg [15:0] eth_tx_len = 0; //udp包长 + 36
reg [15:0] ip_tx_cnt = 0;
reg ip_chk_start = 0;
reg ip_chk_end = 0;
reg [23:0] ip_checksum = 16'hc511; //4500(版本,首部长度,tos) + 4000(标志,片位移) + 4011(TTL + protocol)
reg [4:0] ip_tx_st = 0;
always @ (posedge sys_clk)
if(reset)
begin
udp_tx_idb <= 0;
udp_tx_web <= 0;
ip_fifo_we <= 0;
ip_tx_st <= 0;
end
else case (ip_tx_st)
0:
begin
ip_tx_cnt <= 0;
ip_chk_start <= 0;
udp_tx_addrb_sub <= {IP_BUF_SIZE{1'b1}};
udp_tx_web <= 0;
ip_fifo_we <= 0;
ip_tx_st <= 1;
end
1:
begin
udp_tx_addrb_sub <= {IP_BUF_SIZE{1'b1}};
udp_tx_web <= 0;
ip_tx_st <= 2;
end
2:
begin
if(udp_tx_doutb[15] == 1)
begin
ip_tx_st <= 3;
end
end
3:
begin
ip_tx_len <= udp_tx_doutb[11:0] + 20;
eth_tx_len <= udp_tx_doutb[11:0] + 36; // des_mac(6) + src_mac(6) + 0800(2) + ip_header(20) + package_len(2)
ip_chk_start <= 1;
ip_tx_st <= 4;
end
4:
begin
if( ip_fifo_blank > eth_tx_len)
begin
ip_tx_st <= 5;
end
end
5:
begin
// used for handle odd bytes
ip_fifo_flag <= 0;
ip_fifo_data <= eth_tx_len - 2; // mac + 0800 + ip_header + payload
ip_fifo_we <= 1;
ip_tx_st <= 6;
end
6:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= TX_MAC_DES[47:32];
ip_fifo_we <= 1;
ip_tx_st <= 7;
end
7:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= TX_MAC_DES[31:16];
ip_fifo_we <= 1;
ip_tx_st <= 8;
end
8:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= TX_MAC_DES[15:00];
ip_fifo_we <= 1;
ip_tx_st <= 9;
end
9:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= TX_MAC_SRC[47:32];
ip_fifo_we <= 1;
ip_tx_st <= 10;
end
10:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= TX_MAC_SRC[31:16];
ip_fifo_we <= 1;
ip_tx_st <= 11;
end
11:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= TX_MAC_SRC[15:00];
ip_fifo_we <= 1;
ip_tx_st <= 12;
end
12:
begin
ip_fifo_flag <= 0;
ip_fifo_data <= 16'h0800; // ethernet type
ip_fifo_we <= 1;
ip_tx_st <= 13;
end
13:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= 16'h4500; // ip header
ip_fifo_we <= 1;
ip_tx_st <= 14;
end
14:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= ip_tx_len; // ip package length
ip_fifo_we <= 1;
ip_tx_st <= 15;
end
15:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= 16'h0000; // random value
ip_fifo_we <= 1;
ip_tx_st <= 16;
end
16:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= 16'h4000; // flags ,fragment
ip_fifo_we <= 1;
ip_tx_st <= 17;
end
17:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= 16'h4011; // ttl , protocol
ip_fifo_we <= 1;
ip_tx_st <= 18;
end
18:
begin
if(ip_chk_end)
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= ip_checksum[15:0]; // checksum
ip_fifo_we <= 1;
ip_chk_start <= 0;
ip_tx_st <= 19;
end
else ip_fifo_we <= 0;
end
19:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= TX_IP_SRC[31:16]; // src ip address
ip_fifo_we <= 1;
ip_tx_st <= 20;
end
20:
begin
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= TX_IP_SRC[15:0]; // src ip address
ip_fifo_we <= 1;
ip_tx_st <= 21;
end
21:
begin
udp_tx_addrb_sub <= udp_tx_addrb_sub + 1;
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= TX_IP_DES[31:16]; // des ip address
ip_fifo_we <= 1;
ip_tx_st <= 22;
end
22:
begin
udp_tx_addrb_sub <= udp_tx_addrb_sub + 1;
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
ip_fifo_data <= TX_IP_DES[15:0]; // des ip address
ip_fifo_we <= 1;
ip_tx_st <= 23;
end
23:
begin
if(ip_tx_cnt >= ip_tx_len)
begin
ip_fifo_we <= 0;
ip_tx_st <= 24;
end
else
begin
udp_tx_addrb_sub <= udp_tx_addrb_sub + 1;
ip_tx_cnt <= ip_tx_cnt + 2;
ip_fifo_flag <= 0;
// ip_fifo_data <= {udp_tx_doutb[7:0], udp_tx_doutb[15:8]};
ip_fifo_data <= udp_tx_doutb;
ip_fifo_we <= 1;
end
end
24:
begin
udp_tx_addrb_sub <= {IP_BUF_SIZE{1'b1}};
udp_tx_web <= 1;
ip_fifo_flag <= 2'b11;
ip_fifo_data <= 16'hffff;
ip_fifo_we <= 1;
ip_tx_st <= 25;
end
25:
begin
udp_tx_web <= 0;
ip_fifo_flag <= 0;
ip_fifo_we <= 0;
ip_tx_st <= 26;
end
26: // normal finished
begin
udp_tx_idb <= udp_tx_idb + 1;
udp_tx_web <= 0;
ip_tx_st <= 0;
end
default: ip_tx_st <= 0;
endcase
//=========================================================================
// ip header checksum calculate
reg [2:0] ip_chk_st = 0;
always @ (posedge sys_clk)
if(!ip_chk_start)
begin
ip_chk_end <= 0;
ip_checksum <= 16'hc511; //4500 + 4000 + 4011
ip_chk_st <= 0;
end
else case(ip_chk_st)
0:
begin
ip_chk_end <= 0;
ip_checksum <= ip_checksum + ip_tx_len;
ip_chk_st <= 1;
end
1:
begin
ip_checksum <= ip_checksum + TX_IP_SRC[31:16];
ip_chk_st <= 2;
end
2:
begin
ip_checksum <= ip_checksum + TX_IP_SRC[15:0];
ip_chk_st <= 3;
end
3:
begin
ip_checksum <= ip_checksum + TX_IP_DES[31:16];
ip_chk_st <= 4;
end
4:
begin
ip_checksum <= ip_checksum + TX_IP_DES[15:0];
ip_chk_st <= 5;
end
5:
begin
if(|ip_checksum[23:16])
ip_checksum <= ip_checksum[15:0] + ip_checksum[23:16];
else
begin
ip_checksum[15:0] <= ~ip_checksum[15:0];
ip_chk_end <= 1;
ip_chk_st <= 6;
end
end
6:
begin
ip_chk_end <= 1;
ip_chk_st <= 6;
end
default: ip_chk_st <= 0;
endcase
//=========================================================================
endmodule