已经写好了并调试好了代码,直接上代码:

module tb_axis_user2ether_if ;

reg clk = 0 ,rst = 0  ;

always#5 clk =~clk ; 


initial begin 
$dumpfile("tb_axis_user2ether_if.vcd");
$dumpvars;
end 

reg [31:0]  c = 0 ;always @(posedge clk) c<=c+1;
 

reg[15:0] r=0; 
reg s_valid = 0  , s_last  = 0 , s_pkt_end = 0 ;
wire s_ready ;

integer i ;
task fill_data ;
input [15:0] len ;
begin
@(posedge clk) ;
r = 0 ;s_valid = 1 ; 
for(i=0;i<len;i=i+1)begin  r<=r+1;@(posedge clk);end 
s_valid=0;
end 
endtask

wire [15:0] test_len =  1000;
initial begin 
 rst =1 ;
#100 rst = 0 ;
#100 fill_data (test_len) ;
for(i=0;i< 2000 ;i=i+1) @(posedge clk);
$finish ;
end 

	 axis_user2ether_if#(.AW(10),.DW(16)) 
	 axis_user2ether_if(
	  .clk( clk ),
	  .rst( rst ),
	//cfg if 
	  .cfg_udp_port('h8080 ),	
	//axi stream to ether if 
	  .s_din( r ),
	  .s_valid( s_valid ),
	  .s_last( s_last ),
	  .s_pkt_end( s_pkt_end ),
	  .s_ready( s_ready ),
	//ether udp if 
      .m_udp_tx_busy( 1'b0  ) ,
     .m_udp_tx_len( ),
     .m_udp_tx_dat( ),
     .m_udp_tx_start( ) 
	);
	

endmodule 
 
	
	
	
	module axis_user2ether_if#( 
        parameter AW = 12 , // NOT LESS THAN 10
        parameter DW = 16  // 16 FOR SIMULATION ,8 FOR REAL USE 
	)(
	input clk,rst,
	//cfg if 
	input cfg_udp_port,	
	//axi stream to ether if 
	input [15:0]s_din,
	input s_valid,s_last,s_pkt_end,
	output   s_ready,
	//ether udp if 
    input m_udp_tx_busy ,
    output reg [15:0]m_udp_tx_len,
    output reg [DW-1:0]m_udp_tx_dat,
    output reg m_udp_tx_start  , 
    output reg m_udp_tx_end  
	);
	
	wire [DW-1:0] fifo_u8 ,fwft_dout;
	wire [AW:0] fifo_cntr;
	wire [DW-1:0]  u8 ;
	reg rd_fifo ;
	wire wr_fifo =  s_valid & ~full  ;
	
sc_fifo#(
.AW(AW),
.DW(DW)
)sc_fifo(

.clk(clk),
.rst(rst),

.din(s_din),
.wr( wr_fifo ),
.full( full ),

.dout( fifo_u8 ),
.rd(rd_fifo),
.empty(empty),

.fwft_dout(fwft_dout),
.fifo_cntr(fifo_cntr) 

);
localparam WAIT_HI_BIT   = 5  ;   
reg s_lastr ;always@(posedge clk) s_lastr<=s_last ;
wire pkt_end  = ( s_lastr || s_pkt_end );
reg need_flush  ;
always @(posedge clk) if (rst) need_flush<=0; else  if (pkt_end)need_flush<=0; else if (st==10 && fifo_cntr==0)  need_flush<=0; 

always @( * )  m_udp_tx_dat = fifo_u8 ;

reg [WAIT_HI_BIT:0] wait_cntr ; 
always @ (posedge clk) if (rst |empty | wr_fifo  ) wait_cntr<=0;else  if (wait_cntr[WAIT_HI_BIT] == 0) wait_cntr<= wait_cntr+1 ; 
reg [7:0]  st ; 

reg m_udp_tx_start_d1   ;

always @( posedge clk ) m_udp_tx_start_d1 <= ( st==20) &&  (c ==1  );
always @( posedge clk ) m_udp_tx_start    <=  m_udp_tx_start_d1 ;
always @( posedge clk ) if (st==10)m_udp_tx_len<= (fifo_cntr > 1456) ?  1456 : fifo_cntr;

reg [11:0] c; always @ (posedge clk) case (st) 20 : c<=1+c;default c<=1;endcase  

always@(posedge clk)  if (rst) st<=0; else case (st)
0  : st <= 10 ;
10 : if ( wait_cntr[WAIT_HI_BIT]  ||  ( fifo_cntr[AW:9] !=0 ) || need_flush  )st <=((m_udp_tx_busy==0 )&& (fifo_cntr != 0))?20: 10 ; //
20 : if (c == m_udp_tx_len) st<=30;
30 : st<=40;
40 : st<=10;
default st<=0; 
endcase

always@(posedge clk) if (rst)  rd_fifo <= 0 ;else case (st) 20 : rd_fifo <= 1 ;default rd_fifo<=0; endcase 

reg m_udp_tx_end_d1 , m_udp_tx_end_d2 ;
always@(posedge clk )m_udp_tx_end_d1 <= (st==20 ) &&(  c == m_udp_tx_len );
always@(posedge clk )m_udp_tx_end_d2 <= m_udp_tx_end_d1 ;
always@(posedge clk )m_udp_tx_end    <= m_udp_tx_end_d1 ;
assign s_ready =  ~full & ~need_flush ;	
endmodule

	
/*
module sc_fifo#(
.AW(4),
.DW(32)
)(

.clk(),
.rst(),

.din(),
.wr(),
.full(),

.dout(),
.rd(),
.empty(),


.fwft_dout(),
.fifo_cntr() 

);
*/

module sc_fifo#(
        parameter AW = 5 ,
        parameter DW = 64,
        parameter ALMOST_FULL = 10 ,
        parameter ALMOST_EMPTY = 12
    )(
        input clk,rst,
        input [ DW-1:0] din,
        input wr,rd,
        output full,empty,
        output reg  almost_full,
        output reg almost_empty,
        output  reg  [ DW-1:0] dout,
        output   [ DW-1:0] fwft_dout,
        output reg [ AW:0] fifo_cntr
    );
    parameter MAX_FIFO_LEN = (1<<AW ) ;
    parameter ALMOST_FULL_LEN  = MAX_FIFO_LEN - 10  ;
    parameter ALMOST_EMPTY_LEN = 5  ;
    reg [ DW-1:0] buff[0:  MAX_FIFO_LEN -1] ;
    reg [ AW-1:0] wr_ptr, rd_ptr ;
    assign full  = fifo_cntr == (  MAX_FIFO_LEN   ) ;
    assign empty = fifo_cntr == 0 ;
    always @* almost_full <= fifo_cntr > ALMOST_FULL_LEN ;
    always @* almost_empty <= fifo_cntr < ALMOST_EMPTY_LEN ;

    wire valid_rd =   rd ;
    wire valid_wr =   wr ;

    always@(posedge clk) if (rst) wr_ptr <= 0;else if(valid_wr)wr_ptr<=wr_ptr+1;
    always@(posedge clk) if (rst)rd_ptr <= 0 ;else if (valid_rd)rd_ptr <= rd_ptr+1;
    always@(posedge clk)
    casex ({rst,valid_wr,valid_rd})
        3'b1xx : fifo_cntr<=0;
        3'b010 : fifo_cntr<=fifo_cntr+1;
        3'b001 : fifo_cntr<=fifo_cntr-1;
        3'b011 ,3'b000 :fifo_cntr<=fifo_cntr ;
    endcase
    always@(posedge clk) if (valid_wr) buff[wr_ptr] <=din ;
    always@(posedge clk) if (valid_rd) dout <= buff[rd_ptr] ;
    assign  fwft_dout = buff[rd_ptr] ;
endmodule

工作原理:

1,里面有一个FIFO,用户往FIFO写内容,程序状态机根据情况从读端口读出内容组成UDP接口发送时序给UDP发送模块。

2,在UDP的BUSY信号输出为0,并且满足以下三种情况下程序状态机将FIFO的数据读出,之后给UDP发送接口:

A,FIFO数据大于512字节。

B,已经有连续64个周期FIFO未被写入了。

C,用户触发了LAST或者PKT_END,立即发送当前的包。

几个想法:

1, 使用的时候可以设置FIFO的深度,如果FPGA剩余的BRAM多不妨设置大一些。

2,BRAM在调试时候要做是否发送溢出的检测。

3,发送条件中的A,B可以参数化,用户可以自己修改。我琢磨512和64这俩参数应该不错了。

4,尽量不要使用LAST和PKT_END,因为会将状态机挂起知道所有的用户数据传递到UDP发送端。

仿真截图,因为代码已经调试好了,直接看效果图:

这是发送7个字节的

Android udp怎么连续发送大量数据_UDP

 -----

发送1000个字节

 

Android udp怎么连续发送大量数据_网络协议_02

 

Android udp怎么连续发送大量数据_UDP_03

Android udp怎么连续发送大量数据_网络协议_04

可见发送1000个字节分成了两次,第一次是512,第二次是1000-512.

这里我们看到两次发送之间间隔大约有不到10个周期,如果假设UDP通道被此用户独占,实际接UDP发送时候两个包的间隔时间是(n+95)个周期,再加上这个10个周期大约就是 n+110个周期的样子。

这里我们考虑将这个发送阈值设置为1024,但是也有取舍。就是用户数据写入512到1024期间,UDP是一直再傻等发送的。这实际是浪费了1024-512个周期,而实际如果这期间发送数据的话,用了512+110个周期发送数据,这样看来傻等合适。但是这里的假设就是写端每个周期都写入数据,如果从写入512到1024字节期间零零散散等待了超过110秒,就不如再512字节时候触发UDP实际发送了。另外因为写入时间和UDP发送事件是异步的,再次UDP可以发送数据数据时候,写入的已经完全可以超过512了,比如是1400字节,也就可以一次性把这1400字节发出。512只是一个允许发送的最小阈值。

Android udp怎么连续发送大量数据_网络协议_05