自己编写的代码段如下
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
自己编写的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
仿真结果分析如下:
上图可见,当mii_tx_en
拉高之时,本应该传输数字4’h5
却多传输了一个4’h0
(此数值是复位时的数值);
上图可见,在data_length_tmp != 12’h0
的计数中,我在tb中写道data_length = 10
,那么编译后,data_length_tmp
也应该等于10,也就是说我想要传递的数据长度为10个,但是这里名明显传输了11个数,从0
到a
,见上图红框部分。
上图可见,在最后的结尾处,当传送完最后一个数,也就是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
的拉高时刻正确拉高呢?
代码中,mii_tx_en
等同于en_tx
,若改为
assign mii_tx_en = (lsm_cnt >= 6’d1) && (lsm_cnt <= 6’d53);
仿真如下:
则还是会将复位时候的mii_tx_data
传输出去,也就是将4’h0
传出去,同时,在lsm_cnt = 6’d15
时发现最终传出的4’h5
只有14个,而比本应该传15个4’h5
少了一个。
那如果在LUT中将case语句之上的
else if (mii_tx_en) begin
去掉呢?
直接改成else
语句又是如何呢?
通过仿真发现,是个好办法(这里不贴图了,请自行仿真)。
当复位键按下时,
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
,对应如下图所示:
同时还要注意更改以下3个地方:
在编写代码中,根本看不懂梅哥的这一行代码:
最终自己编写代码才发现此段代码背后的深意,果然还得自己动手。
在线性序列机中,或者别的查找表中,尽量避开cnt
取值为0
的查找表的取值。