当从应用层得到数据时, eth_udp_tx.v 模块将在应用层发送过来数据的基础上,附加上udp 源port, udp 目的port , udp 长度, udp 的checksum 信息。 打成一个完整的udp包,送给ip层。在这个模块中,UDP_TX_CHECKSUM_EN 参数用来控制是否在udp 数据上加载checksum信息,如果不加载checksum 信息, 在checksum 的位置上填写0; 如果加载checksum,就需要计算 udp 头和整体的udp 数据,生成真实的checksum。

图1

图2
本节内容关心的一些关键信号,以时序图的方式呈现,如图3所示:

图3
udp_tx_st和udp_chk_st两个状态机的示意如图4(注意省略了状态转移条件不满足时,停留在当前状态的箭头)所示。

图4 udp_tx_st和udp_chk_st状态机示意图
udp_tx_st 状态机逻辑:
状态机0:初始化相关的数据,UDP_TX_DRAM的子地址指向 1023,跳转到状态机1。
状态机1:等待1个时钟周期,跳转到状态机2。
状态机2:当buffer 目前为空,跳转到状态机3。
状态机3:在地址0 的位置上填写udp 源port,跳转到状态机4。
状态机4:在地址1 的位置上填写udp 目的port,跳转到状态机5。
状态机5:先是在地址3 的位置上填写udp checksum 为 0,跳转到状态机6。
状态机6:将应用层的数据(byte)写入到buffer中去,跳转到状态机7。
状态机7:将应用层的数据(byte)写入到buffer中去,跳转到状态机8,如果没有数据,跳转到状态9。
状态机8:将应用层的数据(byte)写入到buffer中去,跳转到状态机7,如果没有数据,跳转到状态9。
状态机9:正常的数据包结束,在地址2 的位置上填写udp 的长度,如果需要计算checksum,跳转到状态10; 如果不需要checksum, 跳转到状态13。
状态机10:在udp头上填写udp 的checksum,跳转到状态13。
状态机13:对UDP_TX_DRAM的buffer进行封包,跳转到状态14。
状态机14:跳转到状态15。
状态机15:UDP_TX_DRAM的buffer 加一,跳转到状态0。
udp_chk_st 伴随状态机:
状态0: 初始化 udp_chk_sum = 16’h0011, 跳转状态 1。
状态1: 计算udp 数据的checksum, 当udp数据写入结束后,跳转状态 2。
状态2: 再计算一次udp length的checksum,跳转状态 3。
状态3: 计算源ip 地址checksum,跳转状态 4。
状态4: 计算源ip 地址checksum,跳转状态 5。
状态5: 计算目的ip 地址checksum,跳转状态 6。
状态6: 计算目的ip 地址checksum,跳转状态 7。
状态7: 计算完整的udp的checksum,标识udp checksum 计算结束,跳转状态 8。
状态8: 等待当前包封包结束,跳转状态 0。
eth_udp_tx.v 代码:
`timescale 1ns / 1ps
module eth_udp_tx #
(
parameter [31:0] TX_IP_SRC = 32'hc0a8003d,
parameter [31:0] TX_IP_DES = 32'hc0a800ff,
parameter [15:0] UDP_TX_SRC_PORT = 16'hffff,
parameter [15:0] UDP_TX_DES_PORT = 16'hffff,
parameter UDP_TX_CHECKSUM_EN = 0,
parameter IP_BUF_SIZE = 10,
parameter IP_IDX_BIT = 1
)
(
input sys_clk,
input [7:0] udp_din,
input udp_din_vld,
output reg udp_din_rdy = 0,
output reg udp_tx_wea = 0,
output [IP_BUF_SIZE + IP_IDX_BIT - 1:0] udp_tx_addra,
output reg [15:0] udp_tx_dina = 0,
input [15:0] udp_tx_douta,
input reset
);
//=========================================================================
reg [IP_BUF_SIZE - 1:0] udp_tx_addra_sub = 0;
reg [IP_IDX_BIT - 1:0] udp_tx_ida = 0;
assign udp_tx_addra = {udp_tx_ida, udp_tx_addra_sub};
//=======================================================================
reg [31:0] udp_chk_sum = 16'h0011; //UDP protocol
reg udp_chk_end = 0;
reg udp_chk_vld = 0;
reg [15:0] udp_tx_cnt = 0;
reg [3:0] udp_tx_st = 0;
always @ (posedge sys_clk)
if(reset)
begin
udp_din_rdy <= 0;
udp_tx_ida <= 0;
udp_tx_wea <= 0;
udp_tx_st <= 0;
end
else case (udp_tx_st)
0:
begin
udp_chk_end <= 0;
udp_tx_cnt <= 8; //count the UDP header
udp_tx_wea <= 0;
udp_tx_addra_sub <= {IP_BUF_SIZE{1'b1}};
udp_tx_st <= 1;
end
1:
begin
udp_tx_wea <= 0;
udp_tx_addra_sub <= {IP_BUF_SIZE{1'b1}};
udp_tx_st <= 2;
end
2:
begin
if(udp_tx_douta[15] == 0)
begin
udp_tx_st <= 3;
end
end
3:
begin
udp_tx_addra_sub <= udp_tx_addra_sub + 1; //addr 0
udp_tx_dina <= UDP_TX_SRC_PORT[15:0];
udp_tx_wea <= 1;
udp_tx_st <= 4;
end
4:
begin
udp_tx_addra_sub <= udp_tx_addra_sub + 1; //addr 1
udp_tx_dina <= UDP_TX_DES_PORT[15:0];
udp_tx_wea <= 1;
udp_tx_st <= 5;
end
5:
begin
udp_tx_addra_sub <= 3; // checksum
udp_tx_dina <= 16'h0000;
udp_tx_wea <= 1;
udp_din_rdy <= 1;
udp_tx_st <= 6;
end
6: //state 6-7 together write 2 bytes, using 2 clocks to fill 16 bits data into A/B Buffer
begin
udp_tx_wea <= 0;
if(udp_din_vld & udp_din_rdy)
begin
udp_tx_addra_sub <= udp_tx_addra_sub + 1;
udp_tx_dina <= {udp_din, 8'h00}; //odd
udp_tx_cnt <= udp_tx_cnt + 1;
udp_tx_st <= 7;
end
end
7: //state 7-8 together write 2 bytes, using 2 clocks to fill 16 bits data into A/B Buffer
begin
udp_tx_wea <= 1;
if(udp_din_vld & udp_din_rdy)
begin
udp_tx_dina[7:0] <= udp_din; // even
udp_tx_cnt <= udp_tx_cnt + 1;
if(udp_tx_cnt == 1471) // 1518 - 4 (crc) - 20 - 14 - 8
udp_din_rdy <= 0;
udp_tx_st <= 8;
end
else
begin
udp_din_rdy <= 0;
udp_tx_st <= 9;
end
end
8:
begin
udp_tx_wea <= 0;
if(udp_din_vld & udp_din_rdy)
begin
udp_tx_addra_sub <= udp_tx_addra_sub + 1;
udp_tx_dina <= {udp_din, 8'h00};
udp_tx_cnt <= udp_tx_cnt + 1;
if(udp_tx_cnt == 1471) // 1518 -4 (crc) - 20 - 14 - 8
udp_din_rdy <= 0;
udp_tx_st <= 7;
end
else
begin
udp_din_rdy <= 0;
udp_tx_st <= 9;
end
end
9:
begin
udp_tx_addra_sub <= 2;
udp_tx_dina <= udp_tx_cnt[15:0];
udp_tx_wea <= 1;
udp_chk_end <= 1;
if(UDP_TX_CHECKSUM_EN)
udp_tx_st <= 10;
else
udp_tx_st <= 13;
end
10:
begin
udp_tx_wea <= 0;
if(udp_chk_vld)
begin
udp_tx_addra_sub <= 3; // checksum
udp_tx_dina <= udp_chk_sum[15:0];
udp_tx_wea <= 1;
udp_tx_st <= 13;
end
end
13:
begin
udp_tx_addra_sub <= {IP_BUF_SIZE{1'b1}};
udp_tx_dina <= {4'b1000, udp_tx_cnt[11:0]};
udp_tx_wea <= 1;
udp_tx_st <= 14;
end
14:
begin
udp_chk_end <= 0;
udp_tx_wea <= 0;
udp_tx_st <= 15;
end
15: // normal finished
begin
udp_tx_ida <= udp_tx_ida + 1;
udp_tx_wea <= 0;
udp_tx_st <= 0;
end
default: udp_tx_st <= 0;
endcase
reg [3:0] udp_chk_st = 0;
always @ (posedge sys_clk)
if(reset)
begin
udp_chk_vld <= 0;
udp_chk_st <= 0;
udp_chk_sum <= 16'h0011;
end
else case (udp_chk_st)
0:
begin
udp_chk_vld <= 0;
udp_chk_sum <= 16'h0011;
udp_chk_st <= 1;
end
1:
begin
if(udp_tx_wea) udp_chk_sum <= udp_chk_sum + udp_tx_dina;
if(udp_chk_end) udp_chk_st <= 2;
end
2: //add UDP length again
begin
udp_chk_sum <= udp_chk_sum + udp_tx_dina;
udp_chk_st <= 3;
end
3:
begin
udp_chk_sum <= udp_chk_sum + TX_IP_SRC[31:16];
udp_chk_st <= 4;
end
4:
begin
udp_chk_sum <= udp_chk_sum + TX_IP_SRC[15:00];
udp_chk_st <= 5;
end
5:
begin
udp_chk_sum <= udp_chk_sum + TX_IP_DES[31:16];
udp_chk_st <= 6;
end
6:
begin
udp_chk_sum <= udp_chk_sum + TX_IP_DES[15:00];
udp_chk_st <= 7;
end
7:
begin
if(|udp_chk_sum[31:16])
udp_chk_sum <= udp_chk_sum[15:0] + udp_chk_sum[31:16];
else
begin
udp_chk_sum[15:0] <= ~udp_chk_sum[15:0];
udp_chk_vld <= 1;
udp_chk_st <= 8;
end
end
8:
begin
udp_chk_vld <= 0;
if(udp_chk_end == 0)
udp_chk_st <= 0;
end
default: udp_chk_st <= 0;
endcase
//=========================================================================
endmodule
更多详细内容请参考相关视频。