参考1:IP包结构??ccIP报文格式详解_海阔天空sky的博客-CSDN博客_ip报文格式??????
我们看到UDP的头部很简单
?用C代码表示如下:
typedef struct _udp_hdr
{
unsigned short src_port; //远端口号
unsigned short dst_port; //目的端口号
unsigned short uhl; //udp头部长度
unsigned short chk_sum; //16位udp检验和
}udp_hdr;
UDP的下一层是IP层,但是这个IP层也给多ICMP提供服务,所以IP专门做一个打包处理模块,所以这里UDP之按照UDP协议加上hdr就好。
这里我们要设计一个udp_tx_enframe模块,输入一个原始的数据包,输出一个打包好的udp数据包,但是不带ip包头。输入是:源端口,目的端口,字节流长度,以及字节流内容;输出为打包好的udp字节流。这里面因为牵扯了16位的chk_sum,我们要接收到所有的字节包后才能计算出来这个数值,因此我们必须有个缓存收完所有的字节流内容之后计算出来chk_sum之后再发出udp报头和报文。我们走的是以太网一个包大约1K-2K字节,我们选择一个2048字节的双口RAM做缓存。
我们还是按照流处理的一般规则,输入口做成slave输出口做成master。之后就写代码:
module udp_tx_pack (
input clk,rst,
input [31:0] src_ip,dst_ip;
input [15:0] src_port,dst_port, tx_len,
input tx_start,
output reg tx_busy ,
input [7:0] tx_dat,
output [15:0] udp_tx_len ,
output udp_tx_start,
input udp_tx_busy ,
output[7:0] udp_tx_dat ,
output reg [31:0] udp_src_ip,udp_dst_ip
);
reg [11:0] wr_addr,wr_addr_end ;
reg [7:0] wr_data;
reg wr_req;
reg [11:0] rd_addr ;
reg [15:0] st,st2 ;
reg [11:0] wr_cntr ;
reg [15:0] src_port_reg ,dst_port_reg , tx_len_reg ;
always @ (posedge clk) if (rst) {src_port_reg ,dst_port_reg }<=0;else if (st==100&tx_start) {src_port_reg ,dst_port_reg } <={ src_port,dst_port };
always @ (posedge clk) if (rst) wr_addr_end<=0; else if (st==100&tx_start) wr_addr_end <= tx_len + 4 ;
always @(posedge clk) if (st=100&tx_start){udp_src_ip,udp_dst_ip}<={src_ip,dst_ip};
always @ (posedge clk) if (rst)st<=0;else case (st)
0:st<=100;
100: if (tx_start)st<= 200;
200: if (wr_addr == wr_addr_end ) st <= 300 ;
301,302,303,304,305,306,307:st<=st+1;
308: st<=400;// tell st2 can now pick this data
400: st<=500;
500: if (rd_addr==10 && st2==400) st<=600;
600: st<=100; // ok , free now
default st<=0;
endcase
reg [15:0] chksum = 0 ;
always @(posedge clk) if (rst) chksum<=0; else case (st)
0,100: chksum <= 0;
200,300,301,302,303,304,305,306,307: chksum<=chksum+wr_data ;
endcase
always @(posedge clk) if (rst) tx_busy<=0;else case(st)200:busy<=1;600:busy<=0;endcase
always @(posedge clk)case (st)
100:begin wr_en<=1;wr_data<= tx_dat; wr_addr<= 4; end
200:begin wr_en<=1;wr_data<= tx_dat; wr_addr<=wr_addr+1; end
301:begin wr_en<=1;wr_data<= src_port_reg[7:0]; wr_addr<=0 ; end
300:begin wr_en<=1;wr_data<= src_port_reg[15:8]; wr_addr<=1 ; end
303:begin wr_en<=1;wr_data<= dst_port_reg[7:0]; wr_addr<=2 ; end
302:begin wr_en<=1;wr_data<= dst_port_reg[15:8]; wr_addr<=3 ; end
304:begin wr_en<=1;wr_data<= 8; wr_addr<=4 ; end
305:begin wr_en<=1;wr_data<= 0; wr_addr<=5 ; end
307:begin wr_en<=1;wr_data<= chksum[7:0]; wr_addr<=6 ; end
306:begin wr_en<=1;wr_data<= chksum[15:8]; wr_addr<=7 ; end
default begin wr_en<=0;wr_data<=0 ; wr_addr<= 0; end
endcase
always@(posedge clk) if (rst)st2<=0;else case (st2)
0:st2<=100;
100:if (st==400)st2<=200;
200:if (udp_tx_busy==0) st2<=400;
400:if (rd_addr == wr_addr_end) st2<=500 ;
500:st2<=600;
600:st2<=100;
default st2<=0;
endcase
always@(posedge clk) udp_tx_start<= st2==200 & udp_tx_busy!=0;
wire [7:0] rd_data ; assign udp_tx_dat = rd_data;
ram2port #( .DWIDTH(8),.AWIDTH(12))ram2port_i(.clk(clk),.wr_en(wr_en),.wr_addr(wr_addr) ,
.rd_addr(rd_addr) ,.wr_data(wr_data),.rd_data(rd_data) );
endmodule
module ram2port
#(
parameter DWIDTH=32,
parameter AWIDTH=9
)
(
input clk,
input wr_en,
input [AWIDTH-1:0] wr_addr ,
input [AWIDTH-1:0] rd_addr ,
input [DWIDTH-1:0] wr_data,
output reg [DWIDTH-1:0] rd_data,
);
reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
integer i;
initial begin
for(i=0;i<(1<<AWIDTH);i=i+1)
ram[i] <= {DWIDTH{1'b0}};
rd_data <= 0;
end
always @ (posedge clk) if (wr_en) ram[wr_addr]<=wr_data;
always @ (posedge clk) rd_data <= ram[rd_addr] ;
endmodule
上述代码粗略写写,代码还没有进行调试。有空继续。下一篇将写一些arp_cache。
|