这里主要是加上了UDP和IP和HEADER。
为了简化设计提高运行效率,这里UDP没有实现CHECK SUM。
代码编译通过,接下来要进行仿真,死磕时序,可能今晚有时间搞搞。
module pack_udp_ip_tb ;
reg clk = 0 , rst = 1 ;
always #5 clk = ~clk ;
initial begin
$dumpfile("v.vcd");
$dumpvars(0);
#100000;
$finish ;
end
wire [31:0] s_src_ip = {8'd192,8'd168,8'd3,8'd12} ;
wire [31:0] s_dst_ip = {8'd192,8'd168,8'd3,8'd12} ;
wire [31:0] s_src_port = 'h4321 ;
wire [31:0] s_dst_port = 'h1234 ;
reg s_valid = 0 ;
wire s_ready ;
reg [64:0] s_din = 0 ;
always@(posedge clk ) if (rst)s_din<= {8'h00,8'h0,8'h0,8'h0,8'h0,8'h0,8'h0,8'h00} ;else
s_din <= s_din + {8'h01,8'h01,8'h01,8'h01,8'h01,8'h01,8'h01,8'h01} ;
reg [3:0] s_byte_cnt = 8 ;
reg [15:0] s_byte_len = 256 ;
wire [63:0] m_dout;
wire [7:0 ]m_keep ;
wire m_valid,m_last ;
pack_udp_ip pack_udp_ip (
.clk ( clk ),
.rst ( rst ),
.s_src_ip ( s_src_ip ),
.s_dst_ip ( s_dst_ip ),
.s_src_port ( s_src_port ),
.s_dst_port ( s_dst_port ),
.s_valid ( s_valid ) ,
.s_ready ( s_ready ) ,
.s_din ( s_din ) ,
.s_byte_cnt ( s_byte_cnt ) ,
.s_byte_len ( s_byte_len ) ,
.m_ready ( 1'b1 ) , // mac
.m_dout ( m_dout ) ,
.m_keep ( m_keep ) ,
.m_valid ( m_valid ),
.m_last (m_last )
);
endmodule
module pack_udp_ip (
input clk,rst,
input [31:0] s_src_ip,s_dst_ip,
input [15:0] s_src_port,s_dst_port,
input s_valid ,
output s_ready ,
input [63:0] s_din ,
input [3:0] s_byte_cnt ,
input [15:0] s_byte_len ,
input m_ready , // mac
output reg [63:0] m_dout ,
output reg [7:0] m_keep ,
output reg m_valid,m_last
);
wire [3:0] ip_version = 4'h4 ; //ipv4
wire [3:0] header_len = 4'h5 ; //header length
wire [15:0] checksum ;
reg [15:0] s_ip_pack_len_p28_r ; always@(posedge clk) s_ip_pack_len_p28_r <= 28 + s_byte_len ;
reg [15:0] s_ip_pack_len_p8_r ; always@(posedge clk) s_ip_pack_len_p8_r <= 8 + s_byte_len ;
wire [15:0] s_ip_id = 16'hAABB ;
wire [7:0 ] s_ip_TTL = 64 ;
wire [7:0 ] s_ip_type = 111;//UDP TYPE
wire [63:0] bit_ch_u64 ;
reg st_en_bit_ch = 0 ;
wire [7:0] bit_ch_m_keep ;
wire [63:0]bit_ch_m_q64 ;
bit_ch#( .FIRST_LEN(4) , .AW(6) ) ii(
.clk( clk ) ,
.rst( rst ) ,
.s_valid( s_valid ) ,
.s_d64( s_d64 ) ,
.s_ready (s_ready) , // s_ready = s_valid if fifo not full
.s_cntr (s_byte_cnt ) ,
.m_q64( bit_ch_m_q64 ) ,
.m_valid(bit_ch_m_valid ) ,
.m_last(bit_ch_m_last ) ,
.m_keep ( bit_ch_m_keep ) ,
.m_ready( st_en_bit_ch )
);
always @ (posedge clk)if (rst)st_en_bit_ch<=0;
else case (st)
22,23: st_en_bit_ch<=1;
default st_en_bit_ch<=0;
endcase
ip_chksum_gen ip_chksum_gen (
.clk(clk ) ,
.rst(rst ) ,
.valid( 1'b1) ,
.ready ( ) ,
.in0({ip_version, header_len,8'b0} ) ,//0
.in1( s_ip_pack_len_p20_r) , //1
.in2(s_ip_id ) ,//2
.in3( 16'h0000 ) , //3
.in4( {s_ip_TTL,s_ip_type} ) , //4
.in5( 16'h0 ) ,//5
.in6(s_src_ip[31:16] ) ,//6
.in7(s_src_ip[15:0] ) ,//7
.in8(s_dst_ip[31:16] ) ,//8
.in9(s_dst_ip[15:0] ) ,//9
.checksum(checksum)
);
reg [7:0] st; always @ (posedge clk)if (rst) st<=0; else case(st)
0 : st<=10;
10 : if (s_valid & m_ready )st<=15;
15:st<=16;16:st<=17;17:st<=20;
20,21,22,23:st<=st+1;
24 : if (bit_ch_m_last) st<=10;
default st<=10;
endcase
/*
0
m_dout[ 0*8 +: 8 ] <= {ip_version[3:0], header_len[3:0]} ;
m_dout[ 1*8 +: 8 ] <= 0 ;
m_dout[ 2*8 +: 8 ] <= s_ip_pack_len_p28_r[15:8] ;
m_dout[ 3*8 +: 8 ] <= s_ip_pack_len_p28_r[7:0] ;
100:begin m_ip_tx_data<= {ip_version[3:0], header_len[3:0]} ;end
101:begin m_ip_tx_data<= 0 ;end
102:begin m_ip_tx_data<= s_ip_pack_len_p20_r[15:8] ;end //OK
103:begin m_ip_tx_data<= s_ip_pack_len_p20_r[7:0] ;end //OK
///
1
m_dout[ 0*8 +: 8 ] <= s_ip_id[15:8] ;
m_dout[ 1*8 +: 8 ] <= s_ip_id[7:0] ;
m_dout[ 2*8 +: 8 ] <= 0 ;
m_dout[ 3*8 +: 8 ] <= 0 ;
104:begin m_ip_tx_data<= s_ip_id[15:8] ;end //ok
105:begin m_ip_tx_data<= s_ip_id[7:0] ;end //ok
106:begin m_ip_tx_data<= 0 ; end
107:begin m_ip_tx_data<= 0 ; end
/
2
m_dout[ 0*8 +: 8 ] <= s_ip_TTL ;
m_dout[ 1*8 +: 8 ] <= s_ip_type ;
m_dout[ 2*8 +: 8 ] <= checksum[15:8] ;;
m_dout[ 3*8 +: 8 ] <= checksum[7:0] ; ;
108:begin m_ip_tx_data<= s_ip_TTL ;end //ok
109:begin m_ip_tx_data<= s_ip_type; end //ok
110:begin m_ip_tx_data<= checksum[15:8] ;end
111:begin m_ip_tx_data<= checksum[7:0] ;end
//
3
m_dout[ 0*8 +: 8 ] <= s_ip_src[3*8+:8] ;
m_dout[ 1*8 +: 8 ] <= s_ip_src[2*8+:8] ;
m_dout[ 2*8 +: 8 ] <= s_ip_src[1*8+:8] ;
m_dout[ 3*8 +: 8 ] <= s_ip_src[0*8+:8] ;
112:begin m_ip_tx_data<= s_ip_src[31:24];end
113:begin m_ip_tx_data<= s_ip_src[23:16] ;end
114:begin m_ip_tx_data<= s_ip_src[15:8] ;end
115:begin m_ip_tx_data<= s_ip_src[7:0] ;end
4
m_dout[ 0*8 +: 8 ] <= s_ip_dst[3*8+:8] ;
m_dout[ 1*8 +: 8 ] <= s_ip_dst[2*8+:8] ;
m_dout[ 2*8 +: 8 ] <= s_ip_dst[1*8+:8] ;
m_dout[ 3*8 +: 8 ] <= s_ip_dst[0*8+:8] ;
116:begin m_ip_tx_data<= s_ip_dst[31:24] ;end
117:begin m_ip_tx_data<= s_ip_dst[23:16] ;end
118:begin m_ip_tx_data<= s_ip_dst[15:8] ;end
119:begin m_ip_tx_data<= s_ip_dst[7:0] ;end
*/
always @ (posedge clk) if (rst){ m_valid,m_last }<=0 ; else case (st)
20: begin ip_hdr_word_0 ;end
21: begin ip_hdr_word_1 ;end
22: begin ip_hdr_word_2 ;end
23: begin ip_hdr_word_3 ;end
24: begin bit_ch_bypass ;end
default { m_valid,m_last }<=0 ;
endcase
task ip_hdr_word_0 ; begin
// 0
m_dout[ 0*8 +: 8 ] <= {ip_version[3:0], header_len[3:0]} ;
m_dout[ 1*8 +: 8 ] <= 0 ;
m_dout[ 2*8 +: 8 ] <= s_ip_pack_len_p28_r[15:8] ;
m_dout[ 3*8 +: 8 ] <= s_ip_pack_len_p28_r[7:0] ;
m_dout[ 4*8 +: 8 ] <= s_ip_id[15:8] ;
m_dout[ 5*8 +: 8 ] <= s_ip_id[7:0] ;
m_dout[ 6*8 +: 8 ] <= 0 ;
m_dout[ 7*8 +: 8 ] <= 0 ;
m_keep <=8 ; m_valid <= 1; m_last <= 0;
end endtask
task ip_hdr_word_1 ; begin
// 2
m_dout[ 0*8 +: 8 ] <= s_ip_TTL ;
m_dout[ 1*8 +: 8 ] <= s_ip_type ;
m_dout[ 2*8 +: 8 ] <= checksum[15:8] ;
m_dout[ 3*8 +: 8 ] <= checksum[7:0] ;
// 3
m_dout[ 4*8 +: 8 ] <= s_src_ip[3*8 +: 8] ;
m_dout[ 5*8 +: 8 ] <= s_src_ip[2*8 +: 8] ;
m_dout[ 6*8 +: 8 ] <= s_src_ip[1*8 +: 8] ;
m_dout[ 7*8 +: 8 ] <= s_src_ip[0*8 +: 8] ;
m_keep <=8 ; m_valid <= 1; m_last <= 0;
end endtask
task ip_hdr_word_2 ; begin
m_keep <=8 ; m_valid <= 1; m_last <= 0;
m_dout[ 0*8 +: 8 ] <= s_dst_ip[3*8 +: 8] ;
m_dout[ 1*8 +: 8 ] <= s_dst_ip[2*8 +: 8] ;
m_dout[ 2*8 +: 8 ] <= s_dst_ip[1*8 +: 8] ;
m_dout[ 3*8 +: 8 ] <= s_dst_ip[0*8 +: 8] ;
m_dout[ 4*8 +: 8 ] <= s_src_port[1*8 +: 8 ] ;
m_dout[ 5*8 +: 8 ] <= s_src_port[0*8 +: 8 ] ;
m_dout[ 6*8 +: 8 ] <= s_dst_port[1*8 +: 8 ] ;
m_dout[ 7*8 +: 8 ] <= s_dst_port[0*8 +: 8 ] ;
/*
300:begin wr_en<=1;wr_data<= src_port_reg[15:8]; wr_addr<=0 ; end
301:begin wr_en<=1;wr_data<= src_port_reg[7:0] ; wr_addr<=1; end
302:begin wr_en<=1;wr_data<= dst_port_reg[15:8]; wr_addr<=2 ; end
303:begin wr_en<=1;wr_data<= dst_port_reg[7:0] ; wr_addr<=3; end
*/
end endtask
task ip_hdr_word_3 ; begin
// 4
m_keep <=8 ; m_valid <= 1; m_last <= 0;
m_dout[ 0*8 +: 8 ] <= s_ip_pack_len_p8_r[15:8] ;
m_dout[ 1*8 +: 8 ] <= s_ip_pack_len_p8_r[7:0 ] ;
m_dout[ 2*8 +: 8 ] <= 0 ;
m_dout[ 3*8 +: 8 ] <= 0 ;
m_dout[ 4*8 +: 8 ] <= bit_ch_m_q64[0*8 +: 8 ] ;
m_dout[ 5*8 +: 8 ] <= bit_ch_m_q64[1*8 +: 8 ] ;
m_dout[ 6*8 +: 8 ] <= bit_ch_m_q64[2*8 +: 8 ] ;
m_dout[ 7*8 +: 8 ] <= bit_ch_m_q64[3*8 +: 8 ] ;
/*
304:begin wr_en<=1;wr_data<= s_ip_pack_len_p8_r[15:8]; wr_addr<=4 ; end
305:begin wr_en<=1;wr_data<= s_ip_pack_len_p8_r[7:0]; wr_addr<=5 ; end
306:begin wr_en<=0;wr_data<= 0; wr_addr<=0 ; end
307:begin wr_en<=0;wr_data<= 0; wr_addr<=0 ; end
*/
m_keep <=8 ; m_valid <= 1; m_last <= 0;
end endtask
task bit_ch_bypass ; begin
m_dout[ 0*8 +: 64 ] <= bit_ch_m_q64[0*8 +: 64 ] ;
m_keep <=bit_ch_m_keep ; m_valid <=bit_ch_m_valid ; m_last <= bit_ch_m_last;
end endtask
endmodule
module ip_chksum_gen(
input clk,rst,
input valid,
output reg ready ,
input [15:0] in0,in1,in2,in3,in4,
input [15:0] in5,in6,in7,in8,in9,
output reg [15:0] checksum
);
//checksum function
function [31:0] checksum_adder ( input [31:0] dataina, input [31:0] datainb );
begin checksum_adder = dataina + datainb; end
endfunction
function [31:0] checksum_out ( input [31:0] dataina );
begin checksum_out = dataina[15:0]+dataina[31:16]; end
endfunction
//checksum generation
reg [16:0] checksum_tmp0 ;
reg [16:0] checksum_tmp1 ;
reg [16:0] checksum_tmp2 ;
reg [16:0] checksum_tmp3 ;
reg [16:0] checksum_tmp4 ;
reg [17:0] checksum_tmp5 ;
reg [17:0] checksum_tmp6 ;
reg [18:0] checksum_tmp7 ;
reg [19:0] checksum_tmp8 ;
reg [16:0] check_out ;
reg [15:0] checkout_buf ;
reg [3:0]valid_r ;always @ (posedge clk) { ready , valid_r }<={valid_r[3:0],valid} ;
always@(posedge clk)begin
checksum_tmp0 <= checksum_adder(in0,in1);
checksum_tmp1 <= checksum_adder(in2,in3) ;
checksum_tmp2 <= checksum_adder(in4,in5) ;
checksum_tmp3 <= checksum_adder(in6,in7) ;
checksum_tmp4 <= checksum_adder(in8,in9) ;// stage 1
checksum_tmp5 <= checksum_adder(checksum_tmp0, checksum_tmp1) ;
checksum_tmp6 <= checksum_adder(checksum_tmp2, checksum_tmp3) ;
checksum_tmp7 <= checksum_adder(checksum_tmp5, checksum_tmp6) ;
checksum_tmp8 <= checksum_adder(checksum_tmp4, checksum_tmp7) ; // stage2
check_out <= checksum_out(checksum_tmp8) ; //stage3
checkout_buf <= checksum_out(check_out) ; // stage4
checksum <= ~ checkout_buf[15:0] ; // stage5
end
endmodule
/*
bit_ch#( .FIRST_LEN(4) , .AW(6) ) ii(
.clk( clk ) ,
.rst( rst ) ,
.s_valid( ) ,s_ready(),
.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 reg s_ready ,
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<=8'h00000000;
1:m_keep<=8'b00000001;
2:m_keep<=8'b00000011;
3:m_keep<=8'b00000111;
4:m_keep<=8'b00001111;
5:m_keep<=8'b00011111;
6:m_keep<=8'b00111111;
7:m_keep<=8'b01111111;
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 ;
always @ (*)s_ready = gap[3] ; // gap>=8
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
这里面主要注意BIT_CH模块加入的时序的打磨。这个仿真成功后立即做ICMP_REPLAY的组包并进行仿真。
这样之后发送部分就写完毕了,接下来开始写接受部分的解析和分支处理。在一个接收模块里面解析出ARP ICMP和UDP,并提取相关参数,分给另外一些对应模块里面处理。其中ARP和ICMP发给主状态机,UDP报文则发给用户程序。