千兆以太网PHY芯片调试-基于RGMII接口的88E1111(数据收发ECHO测试)
先放结果:
Py测试代码:
import socket #网络通信 TCP,UDP
DST_IP = '192.168.0.4'
DST_PORT = 8888
DST_ADDR = (DST_IP, DST_PORT)
SRC_IP = '192.168.0.35'
SRC_PORT = 8888
SRC_ADDR = (SRC_IP, SRC_PORT)
udp = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp.bind(SRC_ADDR)
times = 1000
right_pack_time = 0
err_pack_time = 0
while True:
# data=input("输入消息")
for n in range(times):
data = b'\x10\x02\x03\x04\x05\x06\x07\x08\x09\x0A\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xBB' \
b'\x20\x02\x03\x04\x05\x06\x07\x08\x09\x0A\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xCC' \
b'\x30\x02\x03\x04\x05\x06\x07\x08\x09\x0A\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xDD' \
b'\x40\x02\x03\x04\x05\x06\x07\x08\x09\x0A\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xEE' \
b'\x50\x02\x03\x04\x05\x06\x07\x08\x09\x0A\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xFF'
udp.sendto(data, DST_ADDR) # 发消息
data2 = udp.recvfrom(1024)
if data == data2 :
right_pack_time += 1
print(f'数据返回正确 pakage times:{right_pack_time}')
else:
err_pack_time += 1
print(f'数据返回正确 pakage times:{err_pack_time}')
break
udp.close()
测试平台:
数据收发参考:Verilog 实现千兆网UDP协议 基于88E1111–数据发送
Verilog 实现千兆网UDP协议 基于88E1111–数据接收
Verilog 实现千兆网UDP协议 基于88E1111–板级验证–增加ARP
**代码架构:**实现通信代码为ETH_Control下的几个模块,也就是send 发送 receive 接收 Eth_reg 为MDIO读取phy寄存器状态。两个FIFO,ping_data_buf专为ping指令reply使用,ETH_send_buf 为数据发送缓冲,本代码体系需提前数据发送数据长度,当数据发送缓冲fifo内数据足够时,代码执行开始发送指定量数量的数据。整体构架如下图:
应用时只需关注ETH_control下子模块,cmd_process用于对数据包进行解析,实际使用时会对数据区增加编帧用于传输指令或数据等区分。完整ETH_control代码如下:
`timescale 1ns / 1ps
// _____ _____ _____ _____ _ _ ___ _____ _____
/// ___| / _ \ | _ \ | ____| | | | | / | | _ \ | _ \
//| | | | | | | | | | | |__ | |_| | / /| | | |_| | | | | |
//| | | | | | | | | | | __| | _ | / / | | | _ / | | | |
//| |___ | |_| | | |_| | | |___ | | | | / / | | | | \ \ | |_| |
//\_____| \_____/ |_____/ |_____| |_| |_| /_/ |_| |_| \_\ |_____/
// _____ ___ __ __ _____ ___ __ __ _ _ _____
//| _ \ / | \ \ / / | _ \ / | \ \ / / | | | | | _ \
//| | | | / /| | \ \/ / | | | | / /| | \ \/ / | | | | | |_| |
//| | | | / / | | \ / | | | | / / | | \ / | | | | | ___/
//| |_| | / / | | / / | |_| | / / | | / / | |_| | | |
//|_____/ /_/ |_| /_/ |_____/ /_/ |_| /_/ \_____/ |_|
//
// Company: Nler Studio
// Engineer: Yueze Liu
//
// Create Date: 14:30:16 7/15/2021
// Design Name: ETH_Control
// Module Name: ETH_Control
// Description: ETH_Control documents
// Revision: <Code_revision_information>
//
// When I wrote this, only God and I understood what I was doing
// Now, God only konws
// So don't ask me
//
module ETH_Control(
input clk_50m,
input locked,
output reg [ 3:0] Eth_Command_o ,
output [ 7:0] Txd_o ,
output Txen_o,
output Txer_o,
input Tx_Clk_i,
output Tx_Gclk_o,
input Rx_Clk_i,
input [ 7:0] Rxd_i,
input Rxdv_i,
input Rxer_i,
output reg ETH_RESET_n,
output ETH_INT_n,
input ETH_COL_i,
input ETH_CRS_i,
/*control interface*/
input Open_Eth_Sent,
input [15:0] Data_length_i,
input Eth_Fifo_Clk_i,
output [ 7:0] Eth_Fifo_Data_i,
output Eth_Fifo_Wr_en,
input [ 7:0] Eth_Fifo_en_o,
input [ 7:0] Eth_Fifo_Data_o,
output ETH_fifo_Afull_o,
output [10:0] Eth_Send_wr_count,
output [15:0] Rec_data_length,
input clk_5m,
input rst_n,
output MDC_o,
inout MDIO_io
);
/**/
reg [ 3:0] Eth_Command; //[3]receive_DATA [2]send_ARP [1]send_ICMP [0]send_data
wire ARP_addr_en;
reg ARP_addr_Get;
wire [79:0] ARP_addr_data;
reg [31:0] Destination_IP;
reg [47:0] Destination_MAC;
wire [ 7:0] E2L_Fifo_Data_o;
wire E2L_Fifo_Rd_en;
reg [31:0] eth_rst_reg;
wire [ 7:0] Ping_Fifo_Data_i;
wire Ping_Fifo_Wr_en;
wire [ 7:0] Ping_Fifo_Data_o;
wire Ping_Fifo_Rd_en;
wire Ping_Fifo_Rd_Valid;
wire Ping_Reply_Over;
wire Ping_active;
wire [15:0] Ping_data_length;
wire [15:0] Ping_Check_Sum;
reg [15:0] Ping_Check_Sum_i;
reg Ping_active_r;
wire clk_50m;
wire [10:0] Eth_Send_rd_count;
wire [ 4:0] Phy_addr;
wire [ 4:0] Reg_addr;
wire [15:0] Reg_data_i;
wire [15:0] Reg_data_o;
wire [ 0:0] Op_sw;
wire [ 0:0] Op_enable;
/*debug*/
/* */
assign ETH_INT_n = 1'b1;
assign Tx_Gclk_o = Rx_Clk_i;
/* Ethernet Power-Up Reset Process */
always @(posedge clk_50m )
begin
if(!locked) begin
eth_rst_reg <= 32'h0000_0000;
ETH_RESET_n <= 1'b0;
end
else begin
if(eth_rst_reg == 32'h02ff_ffff) begin
eth_rst_reg <= eth_rst_reg;
ETH_RESET_n <= 1'b1;
end
else begin
eth_rst_reg <= eth_rst_reg + 1'b1;
ETH_RESET_n <= 1'b0;
end
end
end
/*Process Control */
always @(posedge Rx_Clk_i or negedge locked)
begin
if(!locked)begin
Eth_Command[3] <= 1'b0; //receive_open
Eth_Command[2] <= 1'b0; //send_ARP
Eth_Command[1] <= 1'b0; //send_ICMP
Eth_Command[0] <= 1'b0; //send_data
end
else begin
Eth_Command_o <= Eth_Command;
/* ele_add receive start */
if(ETH_RESET_n) begin
Eth_Command[3] <= 1'b1;
end
else begin
Eth_Command[3] <= 1'b0;
end
/* receive ARP trigger reply // binding PC MAC IP */
if (ARP_addr_en) begin
ARP_addr_Get <= 1'b1;
Destination_MAC <= ARP_addr_data[79:32];
Destination_IP <= ARP_addr_data[31: 0];
Eth_Command[2] <= 1'b1;
end
else begin
ARP_addr_Get <= 1'b0;
Eth_Command[2] <= 1'b0;
end
/* receive ICMP trigger reply ping package */
if (Ping_active || Ping_active_r) begin
Eth_Command[1] <= 1'b1;
if(Ping_Reply_Over) begin
Ping_active_r <= 1'b0;
end
else begin
Ping_active_r <= 1'b1;
end
end
else begin
Eth_Command[1] <= 1'b0;
end
/*lock Ping_Check_Sum*/
if (Ping_active) Ping_Check_Sum_i <= Ping_Check_Sum;
else Ping_Check_Sum_i<= Ping_Check_Sum_i;
/*START send_data*/
if(Open_Eth_Sent) begin
if(Eth_Send_rd_count > Data_length_i - 4'd10)begin
Eth_Command[0] <= 1'b1;
end
else begin
Eth_Command[0] <= 1'b0;
end
end
else begin
Eth_Command[0] <= 1'b0;
end
end
end
ETH_Send ETH_Send_u(
.clk_i (Rx_Clk_i ),
.rst_n (ETH_RESET_n ),
.Txen_o (Txen_o ),
.Txer_o (Txer_o ),
.Txd_o (Txd_o ),
.Eth_Command (Eth_Command ),
.Data_length_i (Data_length_i ),
.Eth_Fifo_Data_o (E2L_Fifo_Data_o ),
.Eth_Fifo_Rd_en (E2L_Fifo_Rd_en ),
.Destination_IP (Destination_IP ),
.Destination_MAC (Destination_MAC ),
.Ping_data_length (Ping_data_length ),
.Ping_Check_Sum (Ping_Check_Sum_i ),
.Ping_Reply_Over (Ping_Reply_Over ),
.Ping_Fifo_Data_o (Ping_Fifo_Data_o ),
.Ping_Fifo_Rd_en (Ping_Fifo_Rd_en )
);
ETH_Receive ETH_Receive_u(
.clk_i (Rx_Clk_i ),
.rst_n (ETH_RESET_n ),
.Rxer_i (Rxer_i ),
.Rxdv_i (Rxdv_i ),
.Rxd_o (Rxd_i ),
.Eth_Command (Eth_Command ),
.Destination_IP (Destination_IP ),
.Destination_MAC (Destination_MAC ),
.Eth_Fifo_Data_i (Eth_Fifo_Data_i ),
.Eth_Fifo_Wr_en (Eth_Fifo_Wr_en ),
.Ping_Fifo_Data_i (Ping_Fifo_Data_i ),
.Ping_Fifo_Wr_en (Ping_Fifo_Wr_en ),
.ARP_addr_en (ARP_addr_en ),
.ARP_addr_Get (ARP_addr_Get ),
.ARP_addr_data (ARP_addr_data ),
.Ping_active (Ping_active ),
.Ping_data_length (Ping_data_length ),
.Ping_Check_Sum (Ping_Check_Sum ),
.Rec_data_length (Rec_data_length )
);
Ping_data_buf Ping_data_buf_u (
.rst (!locked ),
.wr_clk (Rx_Clk_i ),
.rd_clk (Rx_Clk_i ),
.din (Ping_Fifo_Data_i ),
.wr_en (Ping_Fifo_Wr_en ),
.rd_en (Ping_Fifo_Rd_en ),
.dout (Ping_Fifo_Data_o ),
.full ( ),
.empty ( ),
.valid (Ping_Fifo_Rd_Valid )
);
Eth_Send_buf Eth_Send_buf_u (
.rst (!locked ), // input wire rst
.wr_clk (Eth_Fifo_Clk_i ), // input wire wr_clk
.rd_clk (Rx_Clk_i ), // input wire rd_clk
.din (Eth_Fifo_Data_o ), // input wire [7 : 0] din
.wr_en (Eth_Fifo_en_o ), // input wire wr_en
.rd_en (E2L_Fifo_Rd_en ), // input wire rd_en
.dout (E2L_Fifo_Data_o ), // output wire [7 : 0] dout
.full ( ), // output wire full
.almost_full (ETH_fifo_Afull_o ), // output wire almost_full
.empty ( ), // output wire empty
.rd_data_count (Eth_Send_rd_count ), // output wire [10 : 0] rd_data_count
.wr_data_count (Eth_Send_wr_count ) // output wire [10 : 0] wr_data_count
);
assign MDIO_io = (Op_sw_r) ? MDIO_o:1'bz;
Eth_Reg_Wr Eth_Reg_Wr_u(
.clk_i (clk_5m ),
.rst_n (locked ),
.MDC_o (MDC_o ),
.MDIO_i (MDIO_io ),
.MDIO_o (MDIO_o ),
.Phy_addr (Phy_addr ),
.Reg_addr (Reg_addr ),
.Reg_data_i (Reg_data_i ),
.Reg_data_o (Reg_data_o ),
.Op_sw (Op_sw ),
.Op_enable (Op_enable ),
.Op_sw_r (Op_sw_r )
);
vio_0 vio_u (
.clk (clk_5m ),
.probe_in0 (Reg_data_o ),
.probe_out0 (Reg_data_i ),
.probe_out1 (Phy_addr ),
.probe_out2 (Reg_addr ),
.probe_out3 (Op_sw ),
.probe_out4 (Op_enable )
);
endmodule
对外控制接口:
Open_Eth_Sent,开启发送
Data_length_i,发送数据长度
接收数据直接写入fifo,这次测试实现CALLBACK所以外部没有连接fifo
Eth_Fifo_Clk_i,
Eth_Fifo_Data_i,
Eth_Fifo_Wr_en,
发送数据缓冲fifo
Eth_Fifo_en_o,
Eth_Fifo_Data_o,
ETH_fifo_Afull_o,
Eth_Send_wr_count,
接收数据package长度,从首部中提取出来计算出实际数据长度
Rec_data_length,
Process Control 内实现模式切换,包含UDP通讯,ARP响应,ICMP内PING reply
实现callback只需顶层将接收与发送信号相连
assign Open_Eth_Sent = 1'b1;
assign Eth_Fifo_Data_o = Eth_Fifo_Data_i;
assign Eth_Fifo_en_o = Eth_Fifo_Wr_en;
assign Data_length_i = Rec_data_length ;
assign Eth_Wr_Fifo_Clk = Rx_Clk_i;