用在XGMII的UDP协议实现一个字节序列处理模块

66 篇文章 23 订阅
58 篇文章 27 订阅

10G光口数据宽度是8字节,我们在实现UDP协议时候,每一层的头部不是正好的8字节,比如IP头部是20字节,这样就要求我们在IP层上PLAYLOAD要处理一下:

图中阴影部分可以是UDP,以及ICMP报文等。我们看到8字节对齐的内容要加上20字节的IP包头要先输出一个4字节补齐之前IP报头缺少的。

为了更加通用,我写了下面这个模块。 

/*
module bit_ff_tb ;
 
reg  clk = 0 , rst  = 1  ;
always #5 clk = ~clk ;  
initial begin 
$dumpfile("v.vcd");
$dumpvars(0);
#400000; 
$finish ;
end 

 parameter AW = 5  ;
 
reg [63:0]  wr_din=0 ;
wire [63:0] rd_dout ;
reg wr_en =0,rd_en =0;
reg   [3:0] wr_byte_cntr=0 ;
reg   [3:0] rd_byte_cntr=0 ;

wire [AW:0] gap ;

always@(posedge clk ) if (rst) wr_din<= {8'h00,8'h0,8'h0,8'h0,8'h0,8'h0,8'h0,8'h00}  ;else 
wr_din<=wr_din+ {8'h01,8'h01,8'h01,8'h01,8'h01,8'h01,8'h01,8'h01}  ;

integer i;

initial begin 
rd_byte_cntr=2;
#200 rst =0;
@(posedge clk);
@(posedge clk);
wr_en=1;wr_byte_cntr=8;
@(posedge clk);
for(i=0;i<2;i=i+1) @(posedge clk);
wr_en=1;wr_byte_cntr=8;
@(posedge clk);
wr_en=0;
@(posedge clk);
for(i=0;i<20;i=i+1) @(posedge clk);
$finish ; 
end 

bit_fifo#(.AW(AW)) bit_fifo(
          .clk(clk ),
		  .rst(rst ),
		  .wr_din( wr_din),
          .wr_byte_cntr(wr_byte_cntr ),
		  .wr_en(wr_en ) ,
		  .rd_dout( rd_dout) ,
          .rd_byte_cntr(rd_byte_cntr ) ,
		  .rd_en(rd_en ) , 
		  .empty(empty ),
		  .full(full ),
		  .gap(gap )
    ); 

always @*  rd_en = ~empty ;
endmodule

*/


module bit_ff_tb ;
 
reg  clk = 0 , rst  = 1  ;
always #5 clk = ~clk ;  
initial begin 
$dumpfile("v.vcd");
$dumpvars(0);
#400000; 
$finish ;
end 

 parameter AW = 5  ;
 
reg [63:0]  s_d64=0 ;
wire [63:0] rd_dout ;
reg s_valid =0 ;
reg   [3:0] wr_byte_cntr=0 ;
reg   [3:0] rd_byte_cntr=0 ;

wire [AW:0] gap ;

always@(posedge clk ) if (rst) s_d64<= {8'h00,8'h0,8'h0,8'h0,8'h0,8'h0,8'h0,8'h00}  ;else 
s_d64<=s_d64+ {8'h01,8'h01,8'h01,8'h01,8'h01,8'h01,8'h01,8'h01}  ;

integer i;

initial begin 
rd_byte_cntr=2;
#200 rst =0;
@(posedge clk);
@(posedge clk);
s_valid=1;wr_byte_cntr=8;
@(posedge clk);
for(i=0;i<2;i=i+1) @(posedge clk);
s_valid=1;wr_byte_cntr=8;
@(posedge clk);
s_valid=0;
@(posedge clk);
for(i=0;i<20;i=i+1) @(posedge clk);
$finish ; 
end 

 bit_ch#( .FIRST_LEN(2) ,  .AW(6)   ) ii(
  .clk( clk ) ,
  .rst( rst ) , 
  .s_valid( s_valid) ,
  .s_d64( s_d64) ,
  .s_cntr (wr_byte_cntr ) ,

  .m_q64( ) ,
  .m_valid( ) , 
  .m_last( ) ,
  .m_keep ( ) ,
  .m_ready(1'b1 ) 
); 

endmodule

/*


 bit_ch#( .FIRST_LEN(4) ,  .AW(6)   ) ii(
  .clk( clk ) ,
  .rst( rst ) , 
  .s_valid( ) ,
  .s_d64( ) ,
  .s_cntr ( ) ,

  .m_q64( ) ,
  .m_valid( ) , 
  .m_last( ) ,
  .m_keep ( ) ,
  .m_ready( ) 
);


*/
module  bit_ch#(
		parameter FIRST_LEN =2,
        parameter AW = 4   
)(
input clk,rst, s_valid,
input [63:0] s_d64,
input [4:0] s_cntr ,

output [63:0] m_q64,
output reg m_valid, m_last,
output reg [7:0] m_keep ,
input m_ready
);


wire [AW:0] gap ;
wire empty_w ;	
wire empty = ( m_ready == 0 ) ? 1: empty_w;
	

reg [3:0] rd_byte_cntr ;

always @ (posedge clk)
case (rd_byte_cntr)
0:m_keep<=0;
1:m_keep<=1'b1;
2:m_keep<=2'b11;
3:m_keep<=3'b111;
4:m_keep<=4'b1111;
5:m_keep<=5'b11111;
6:m_keep<=6'b111111;
7:m_keep<=7'b1111111;
8:m_keep<=8'b11111111;
endcase 

wire full; 
reg empty_r ;always @ (posedge clk )empty_r <= empty ;
always @ (*) if ( {empty_r,empty} == 2'b10 ) rd_byte_cntr = FIRST_LEN;else  rd_byte_cntr = (gap[3]) ?  8  :  gap  ; 
wire rd_en = ~empty ; 
always@(posedge clk) m_valid <= rd_en ;

always@(*)  m_last = { m_valid,rd_en }== 2'b10 ; 


bit_fifo#(.AW(AW)) bit_fifo(
          .clk(clk ),
		  .rst(rst ),
		  .wr_din( s_d64),
          .wr_byte_cntr(  s_cntr  ),
		  .wr_en(s_valid ) ,
		  .rd_dout( m_q64) ,
          .rd_byte_cntr(rd_byte_cntr ) ,
		  .rd_en(rd_en ) , 
		  .empty(empty_w ),
		  .full(  ),
		  .gap(gap )
    ); 

endmodule 
	

 
	

module bit_fifo#(
        parameter AW = 4   
    )(
        input clk,rst,
		input [ 64-1:0]wr_din,
        input [3:0] wr_byte_cntr,
		input wr_en ,
		output reg   [ 64-1 : 0 ]rd_dout ,
        input   [ 3 : 0 ] rd_byte_cntr ,
		input  rd_en , 
		output empty,full,
		output reg [AW:0]gap
    ); 
 
    parameter MAX_FIFO_LEN = ( 1 << AW ) ;
    reg [ 8-1:0] buff[0:  MAX_FIFO_LEN -1] ;
    integer i ;          initial    for(i=0;i<MAX_FIFO_LEN;i=1+i)  buff[i] = 0;       
    assign full  = gap == MAX_FIFO_LEN ;
	assign empty = gap == 0 ; 
	reg [ AW-1:0] wr_ptr =0 , rd_ptr = 0  ;
    always@(posedge clk) if (rst)   wr_ptr <= 0 ; else if ( wr_en  ) wr_ptr <= wr_ptr + wr_byte_cntr ;
    always@(posedge clk) if (rst)   rd_ptr <= 0 ; else if ( rd_en  ) rd_ptr <= rd_ptr + rd_byte_cntr ; 
 
	
	wire  [ AW-1:0] wr_ptr_plus_0 = wr_ptr + 0 ;
	wire  [ AW-1:0] wr_ptr_plus_1 = wr_ptr + 1 ;
	wire  [ AW-1:0] wr_ptr_plus_2 = wr_ptr + 2 ;
	wire  [ AW-1:0] wr_ptr_plus_3 = wr_ptr + 3 ;
	wire  [ AW-1:0] wr_ptr_plus_4 = wr_ptr + 4 ;
	wire  [ AW-1:0] wr_ptr_plus_5 = wr_ptr + 5 ;
	wire  [ AW-1:0] wr_ptr_plus_6 = wr_ptr + 6 ;
	wire  [ AW-1:0] wr_ptr_plus_7 = wr_ptr + 7 ; 
	
	wire  [ AW-1:0] rd_ptr_plus_0 = rd_ptr + 0 ;
	wire  [ AW-1:0] rd_ptr_plus_1 = rd_ptr + 1 ;
	wire  [ AW-1:0] rd_ptr_plus_2 = rd_ptr + 2 ;
	wire  [ AW-1:0] rd_ptr_plus_3 = rd_ptr + 3 ;
	wire  [ AW-1:0] rd_ptr_plus_4 = rd_ptr + 4 ;
	wire  [ AW-1:0] rd_ptr_plus_5 = rd_ptr + 5 ;
	wire  [ AW-1:0] rd_ptr_plus_6 = rd_ptr + 6 ;
	wire  [ AW-1:0] rd_ptr_plus_7 = rd_ptr + 7 ;  
	
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_0 ]<= wr_din[ 0*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_1 ]<= wr_din[ 1*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_2 ]<= wr_din[ 2*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_3 ]<= wr_din[ 3*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_4 ]<= wr_din[ 4*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_5 ]<= wr_din[ 5*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_6 ]<= wr_din[ 6*8 +: 8] ;
 always@(posedge clk) if (wr_en )   buff[ wr_ptr_plus_7 ]<= wr_din[ 7*8 +: 8] ;
 
 always@(posedge clk) if (rd_en )   rd_dout[ 0*8 +: 8] <=buff[rd_ptr_plus_0 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 1*8 +: 8] <=buff[rd_ptr_plus_1 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 2*8 +: 8] <=buff[rd_ptr_plus_2 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 3*8 +: 8] <=buff[rd_ptr_plus_3 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 4*8 +: 8] <=buff[rd_ptr_plus_4 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 5*8 +: 8] <=buff[rd_ptr_plus_5 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 6*8 +: 8] <=buff[rd_ptr_plus_6 ];
 always@(posedge clk) if (rd_en )   rd_dout[ 7*8 +: 8] <=buff[rd_ptr_plus_7 ];   


	always@(posedge clk)
    casex ({rst,wr_en,rd_en})
        3'b1xx : gap <= 0;
        3'b010 : gap <= gap + wr_byte_cntr;
        3'b001 : gap <= gap - rd_byte_cntr;
		3'b011 : gap <= gap + wr_byte_cntr - rd_byte_cntr;
    endcase
	
endmodule

这里其实就输入输出位数不相等的同步FIFO一个技巧性的应用。

----------------------------------------------------

 我们输入4组内容:

8字节:0202020202020202

8字节:0303030303030303

8字节:0404040404040404

4字节:05050505 

我们在输出中设置第一次输出为2个字节,那我们看输出:

 我们得到了5组输出分别是

2字节:0202

8字节:0303020202020202

8字节:0404030303030303

8字节:0505040404040404

2字节:0505

我们看到last信号也得到了正确的输出。

这些字节是按照小字端排布的,所以我们看到一切正常,没有问题。

另外关于AW的设置,设置AW=4是使用16个字节作为缓冲区,只有在FIRST_LEN等于8时候才满足,这里我们设置AW=5,这样就有32字节的缓冲区就够了。多了也没有必要。

{{aAxvOXMOIvVUoXMxvoxiowMwWV8xxWTxoxOIOVIUUOvwVOUiIoUvvTMMVMwovWHWX8vOUOUiviOowTTHVvi88iwvOIoX8HiVoOIOT8HVmH8oiV8UIHMoiHIoVU8VvmvIWXTvvOvv8xvMovOWMTOwxMiV8UmooOTvvwUIoTwvmWUoiTw8VmvoHWwMIUWOixiowiUoiXwiwwMMIiIXHwUmOWUVmXXwV8iHWOTUiwTU8xwOoV8HVmTWZz}}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值