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}}