FPGA之以太网ARP发送

文章目录

      • 1 代码段
      • 2 TB段
      • 3 分析
        • 3.1 分析一
        • 3.2 分析二
        • 3.3 分析三
      • 4 收获
        • 4.1 收获一
        • 4.2 收获二

参考梅雪松的2017年以太网发送部分的视频教程以及代码,对自己编写代码过程中遇到的一些问题进行了调试,是为此篇。

1 代码段

自己编写的代码段如下

module eth_send(
	input rstn,
	//MII
	input 	mii_tx_clk	,
	output 	mii_tx_en	,
//	output   mii_tx_error,
	
	output reg [3:0]	mii_tx_data	,
	
	//FIFO
	input [3:0] fifo_rddata	,
	output 		fifo_rdreq	,
	output 		fifo_rdclk	,
	
	input 		pulse			,
	input [47:0]des_mac		,
	input [47:0]src_mac		,
	input [15:0]type_length	,
	input [31:0]crc_result	,
	input [11:0]data_length		//ARP数据段的长度
); 

parameter LSM_CNT_MAX = 6'd53;

reg [5:0] lsm_cnt	;
reg 		 en_tx	;

reg [47:0]des_mac_tmp		;
reg [15:0]type_length_tmp	;
reg [11:0]data_length_tmp	;

wire tx_arp;

assign mii_tx_en  = en_tx		;
assign fifo_rdreq = tx_arp		;
assign fifo_rdclk = mii_tx_clk;

//en_tx============================================
wire tx_done = (lsm_cnt == LSM_CNT_MAX);
always @ (posedge mii_tx_clk or negedge rstn) begin
	if (!rstn)
		en_tx <= 1'b0;
	else if (pulse)
		en_tx <= 1'b1;
	else if (tx_done)
		en_tx <= 1'b0;
	else
		en_tx <= en_tx;
end

assign tx_arp = (lsm_cnt == 44) && (data_length_tmp!=12'h0);  

//lsm_cnt-----------------------------------------
always @ (posedge mii_tx_clk or negedge rstn) begin
	if (!rstn)
		lsm_cnt <= 6'b0;
	else if (en_tx) begin
		if (tx_arp)
			lsm_cnt <= lsm_cnt;
		else if (tx_done)
			lsm_cnt <= 6'b0;
		else
			lsm_cnt <= lsm_cnt + 1'b1;
	end
	else
		lsm_cnt <= 6'b0;
end

//tmp---------------------------------------------
always @ (posedge mii_tx_clk or negedge rstn) begin
	if (!rstn) begin
		des_mac_tmp 	<= 48'b0;
		type_length_tmp<= 16'b0;
	end
	else if (pulse) begin
		des_mac_tmp 	<= des_mac		;
		type_length_tmp<= type_length	;
	end
	else begin
		des_mac_tmp 	<= des_mac_tmp		;
		type_length_tmp<= type_length_tmp;
	end
end

//data_length_tmp-------------------------------------
always @ (posedge mii_tx_clk or negedge rstn) begin
	if (!rstn) 
		data_length_tmp <= 12'b0;
	else if (pulse)
		data_length_tmp <= data_length;
	else if (tx_arp)
		data_length_tmp <= data_length_tmp - 1'b1;
	else
		data_length_tmp <= data_length_tmp;
end

//LSM-----------------------------------------------
always @ (posedge mii_tx_clk or negedge rstn) begin
    if (!rstn)
        mii_tx_data <= 4'b0;
	 else if (mii_tx_en) begin
		  case (lsm_cnt)
            'd0, 'd1, 'd2, 'd3, 'd4, 'd5, 'd6, 
            'd7, 'd8, 'd9, 'd10,'d11,'d12,'d13,'d14: 
                mii_tx_data <= 4'h5;
            
            'd15: mii_tx_data <= 4'hd;

            'd16: mii_tx_data <= des_mac_tmp[43:40];
            'd17: mii_tx_data <= des_mac_tmp[47:44];
            'd18: mii_tx_data <= des_mac_tmp[35:32];
            'd19: mii_tx_data <= des_mac_tmp[39:36];
            'd20: mii_tx_data <= des_mac_tmp[27:24];
            'd21: mii_tx_data <= des_mac_tmp[31:28];
            'd22: mii_tx_data <= des_mac_tmp[19:16];
            'd23: mii_tx_data <= des_mac_tmp[23:20];
            'd24: mii_tx_data <= des_mac_tmp[11: 8];
            'd25: mii_tx_data <= des_mac_tmp[15:12];
            'd26: mii_tx_data <= des_mac_tmp[ 3: 0];
            'd27: mii_tx_data <= des_mac_tmp[ 7: 4];

            'd28: mii_tx_data <= src_mac[43:40];
            'd29: mii_tx_data <= src_mac[47:44];
            'd30: mii_tx_data <= src_mac[35:32];
            'd31: mii_tx_data <= src_mac[39:36];
            'd32: mii_tx_data <= src_mac[27:24];
            'd33: mii_tx_data <= src_mac[31:28];
            'd34: mii_tx_data <= src_mac[19:16];
            'd35: mii_tx_data <= src_mac[23:20];
            'd36: mii_tx_data <= src_mac[11: 8];
            'd37: mii_tx_data <= src_mac[15:12];
            'd38: mii_tx_data <= src_mac[ 3: 0];
            'd39: mii_tx_data <= src_mac[ 7: 4];

            'd40: mii_tx_data <= type_length_tmp[11: 8];
            'd41: mii_tx_data <= type_length_tmp[15:12];
            'd42: mii_tx_data <= type_length_tmp[ 3: 0];
            'd43: mii_tx_data <= type_length_tmp[ 7: 4];

            'd44: mii_tx_data <= fifo_rddata;

			'd45: mii_tx_data <= crc_result[27:24];
			'd46: mii_tx_data <= crc_result[31:28];
			'd47: mii_tx_data <= crc_result[19:16];
			'd48: mii_tx_data <= crc_result[23:20];
			'd49: mii_tx_data <= crc_result[11: 8];
			'd50: mii_tx_data <= crc_result[15:12];
			'd51: mii_tx_data <= crc_result[ 3: 0];
			'd52: mii_tx_data <= crc_result[ 7: 4];

            default : mii_tx_data <= 4'h0;
        endcase
    end
end

endmodule

2 TB段

自己编写的tb段如下:

`timescale 1ns/1ns
`define p 40

module eth_send_tb;

	reg 		rstn		;
	reg 		mii_tx_clk	;
	reg [ 3:0]	fifo_rddata	;
	reg 		pulse		;
	reg [47:0]	des_mac		;
	reg [47:0] 	src_mac		;
	reg [15:0] 	type_length	;
	reg [31:0]	crc_result	;
	reg [11:0]	data_length	;
	
	wire	   mii_tx_en	;
	wire 	   fifo_rdreq	;
	wire 	   fifo_rdclk	;
	wire [3:0] mii_tx_data	;
	
initial 			mii_tx_clk = 1'b0			;
always #(`p/2)	mii_tx_clk = ~mii_tx_clk;

initial begin
	#(`p*2000);
	$stop;
end

initial begin
	rstn 		= 1'b0;	#(`p*10+3);
	rstn 		= 1'b1;
	
	//round one
	des_mac		= 48'hff_ff_ff_ff_ff_ff	;
	src_mac 		= 48'h00_21_85_c5_2b_8f	;
	type_length = 16'h08_06				;
	crc_result  = 32'hab_cd_ef_21		;
	data_length = 12'd10					;
	
	#(`p);	pulse = 1'b1;
	#(`p); 	pulse = 1'b0;
	
	#(`p*1000)
	
	//round two
	des_mac		= 48'hff_ff_ff_ff_ff_ff	;
	src_mac 	= 48'h00_21_85_c5_2b_8f	;
	type_length = 16'h08_06				;
	crc_result  = 32'hab_cd_ef_21		;
	data_length = 12'd50				;
	
	#(`p);	pulse = 1'b1;
	#(`p); 	pulse = 1'b0;
end

//for fifo_rddata
//��������FIFO���������Ѷ�

always @(posedge mii_tx_clk) begin
	if (!rstn)
		fifo_rddata = 0;
	else if (fifo_rdreq)
		fifo_rddata = fifo_rddata + 1'b1;
	else
		fifo_rddata = 0;
end


eth_send eth_send(
	.rstn		(rstn		),
	.mii_tx_clk	(mii_tx_clk	),
	.mii_tx_en	(mii_tx_en	),
	.mii_tx_data(mii_tx_data),
	.fifo_rddata(fifo_rddata),
	.fifo_rdreq	(fifo_rdreq	),
	.fifo_rdclk	(fifo_rdclk	),
	.pulse		(pulse		),
	.des_mac	(des_mac	),
	.src_mac	(src_mac	),
	.type_length(type_length),
	.crc_result	(crc_result	),
	.data_length(data_length)
);
	
endmodule

3 分析

仿真结果分析如下:

3.1 分析一

FPGA之以太网ARP发送_第1张图片
上图可见,当mii_tx_en拉高之时,本应该传输数字4’h5却多传输了一个4’h0(此数值是复位时的数值);
FPGA之以太网ARP发送_第2张图片

上图可见,在data_length_tmp != 12’h0的计数中,我在tb中写道data_length = 10,那么编译后,data_length_tmp也应该等于10,也就是说我想要传递的数据长度为10个,但是这里名明显传输了11个数,从0a,见上图红框部分。

FPGA之以太网ARP发送_第3张图片

上图可见,在最后的结尾处,当传送完最后一个数,也就是crc_result中的4’h2时,mii_tx_en拉低,符合实际情况。

综上,在mii_tx_en拉高的过程中,最开始多传递了一个数4’h5,以及在传输ARP字段时只想传10个数却传了11个数。将data_length_tmp != 12’h0改为data_length_tmp != 12’h1,可使ARP字段正确传输,而如何将mii_tx_en的拉高时刻正确拉高呢?

3.2 分析二

代码中,mii_tx_en等同于en_tx,若改为
assign mii_tx_en = (lsm_cnt >= 6’d1) && (lsm_cnt <= 6’d53);
仿真如下:
FPGA之以太网ARP发送_第4张图片
则还是会将复位时候的mii_tx_data传输出去,也就是将4’h0传出去,同时,在lsm_cnt = 6’d15时发现最终传出的4’h5只有14个,而比本应该传15个4’h5少了一个。

那如果在LUT中将case语句之上的
else if (mii_tx_en) begin 去掉呢?
直接改成else语句又是如何呢?

通过仿真发现,是个好办法(这里不贴图了,请自行仿真)。

3.3 分析三

当复位键按下时,lsm_cnt = 0
当外部脉冲没有到来的时候,lsm_cnt = 0
当传输完成产生tx_done信号之后,lsm_cnt = 0

也就是说,当lsm_cnt = 0时,对应了很多种电路状态,那么在查找表中(LUT中),让lsm_cnt = 0时就让查找表工作,或者说让查找表在lsm_cnt = 0的时候取值为4’h5,是非常不妥的。

换句话说,当lsm_cnt = 0时,电路根本没有工作,如果这时让查找表工作,那岂不是没有意义?

所以避开lsm_cnt = 0时在查找表中的取值,具体做法为让lsm_cnt = 0时,case的取值为0;同时将之前的case语句中的取值全体加1,对应如下图所示:
FPGA之以太网ARP发送_第5张图片
FPGA之以太网ARP发送_第6张图片
同时还要注意更改以下3个地方:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4 收获

4.1 收获一

在编写代码中,根本看不懂梅哥的这一行代码:
FPGA之以太网ARP发送_第7张图片
最终自己编写代码才发现此段代码背后的深意,果然还得自己动手。

4.2 收获二

在线性序列机中,或者别的查找表中,尽量避开cnt取值为0的查找表的取值。

你可能感兴趣的:(FPGA)