上期给出了udp协议的发送端,这期讲讲接收端
发送端顶层代码:
`timescale 1ns / 1ps
//
// Engineer: 兵棒
// Create Date: 2023/12/06 15:56:20
// Module Name: UDP_in
// Description: UDP接收顶层控制 接口位GMII千兆网通信
// Attention:1、ip_checknum的计算,数据要完全囊括进去。
// 2、数据对比的工作放在最后进行对比,先把所有数据接受完
//
module UDP_in#(
parameter FPGA_MAC_ADDR = 48'h02_00_00_00_00_02, // FPGA MAC地址
parameter FPGA_IP_ADDR = 32'hc0_a8_01_66, // FPGA IP地址
parameter FPGA_UDP_PORT = 16'd0 // FPGA UDP端口号
)(
input RX_CLK,//接收数据参考时钟,时钟频率为125MHz 。 RX_CLK 是由PHY 侧提供的
input rst_n,
input [7:0] RXD,//ReceiveData ,数据接收信号,共 8 根信号线。
input RX_ER,//Receive Error 接收数据错误提示信号;同步于 RX_CLK高电平有效,表示 RX_ER 有效期内传输的数据无效。对于10Mbps 速率下, RX_ER 不起作用 。
input RX_DV,//Reveive Data Valid 接收数据有效信号;拉高时表示接收数据有效。
output [7:0] rx_data,
output rx_data_valid,
output reg rx_done
);
// 前导码
localparam ETH_PREAMBLE = 8'h55;
localparam ETH_SFD = 8'hd5;
//帧类型
reg [15:0] ETH_TYPE =0;
// IP首部参数
reg [3:0] IP_HEAD_VER =0;//版本
reg [3:0] IP_HEAD_LEN =0;//首部长度
reg [7:0] IP_HEAD_TOS =0;//区分服务
reg [15:0] IP_LENGTH =0;
reg [15:0] IP_HEAD_ID =0;//标识
reg [2:0] IP_HEAD_FLAG =0;//标志
reg [12:0] IP_HEAD_OFFSET =0;//片偏移
reg [7:0] IP_HEAD_TTL =0;//生存时间
reg [7:0] IP_HEAD_PROT =0;//协议
reg [15:0] PS_CHECK =0;
reg [31:0] PS_IP_ADDR =0;//PS ip
reg [31:0] AIM_IP_ADDR =0;//FPGA ip
reg [15:0] IP_Optional =0;//可选字段
reg [15:0] IP_fill =0;//填充
reg [7:0] FPGA_MAC[5:0] ;// FPGA MAC地址
reg [7:0] PS_MAC[5:0] ;// PS MAC地址
//udp
reg [15:0] udp_ps_post =0;
reg [15:0] udp_fpga_post =0;
reg [15:0] udp_length =0;
reg [15:0] udp_check =0;
reg [3:0] udp_cnt =0;
reg [31:0] CRC32_DATA_O =0;
reg [7:0] rx_data_o =0;
reg rx_data_valid_o =0;
reg [15:0] rx_cnt =0;
reg [3:0] crc_cnt =0;
reg [3:0] lead_code_cnt =0;
reg [3:0] fpga_mac_cnt =0;
reg [3:0] ps_mac_cnt =0;
reg [3:0] state =0;
reg check_start =0;
reg [7:0] ip_head_cnt =0;
reg I_CRC_INIT =0;
wire fpga_mac_right,fpga_mac_right0,fpga_mac_right1,fpga_mac_right2,fpga_mac_right3,fpga_mac_right4,fpga_mac_right5;
wire check_right ;
wire [15:0] ip_checknum ;
wire ip_check_valid ;
wire [15:0] IP_CHECK ;
wire [31:0] CRC32_DATA ;
wire ip_right ;
wire udp_post_right ;
wire crc_right ;
wire I_CRC_EN ;
wire [7:0] data_o ;
assign rx_data=rx_data_o;
assign rx_data_valid=rx_data_valid_o;
//根据需要适当将判断值输出运用
assign fpga_mac_right0 = (FPGA_MAC[0] == FPGA_MAC_ADDR[47:40]) ? 1: 0;//发送端物理地址高位
assign fpga_mac_right1 = (FPGA_MAC[1] == FPGA_MAC_ADDR[39:32]) ? 1: 0;
assign fpga_mac_right2 = (FPGA_MAC[2] == FPGA_MAC_ADDR[31:24]) ? 1: 0;
assign fpga_mac_right3 = (FPGA_MAC[3] == FPGA_MAC_ADDR[23:16]) ? 1: 0;
assign fpga_mac_right4 = (FPGA_MAC[4] == FPGA_MAC_ADDR[15:8 ]) ? 1: 0;
assign fpga_mac_right5 = (FPGA_MAC[5] == FPGA_MAC_ADDR[7 :0 ]) ? 1: 0;//发送端物理地址低位
assign fpga_mac_right = fpga_mac_right0&fpga_mac_right1&fpga_mac_right2&fpga_mac_right3&fpga_mac_right4&fpga_mac_right5;//物理地址判断
assign IP_CHECK=(ip_check_valid) ? ip_checknum : IP_CHECK;//校验和取值
assign check_right=(IP_CHECK==PS_CHECK) ? 1 : 0;//校验和判断
assign ip_right=(AIM_IP_ADDR==FPGA_IP_ADDR) ? 1 : 0;//IP地址判断
assign udp_post_right=(udp_fpga_post==FPGA_UDP_PORT) ? 1 : 0;//udp端口判断
assign crc_right=(CRC32_DATA_O==CRC32_DATA) ? 1 : 0;//FCS检错值判断
assign I_CRC_EN=(state>=0&&state<=7) ? RX_DV : 0;
assign data_o=(I_CRC_EN) ? RXD : data_o;
always@(posedge RX_CLK or negedge rst_n)begin
if(!rst_n)begin
state <= 0;
lead_code_cnt <= 0;
ps_mac_cnt <= 0;
check_start <= 0;
ip_head_cnt <= 0;
udp_cnt <= 0;
rx_cnt <= 0;
rx_data_o <= 0;
rx_data_valid_o <= 0;
crc_cnt <= 0;
rx_done <= 0;
PS_MAC[0] <= 0;
PS_MAC[1] <= 0;
PS_MAC[2] <= 0;
PS_MAC[3] <= 0;
PS_MAC[4] <= 0;
PS_MAC[5] <= 0;
I_CRC_INIT <= 0;
end
else if(RX_ER)
state <= 9;
else
case (state)
0:begin
lead_code_cnt <= 0;
ps_mac_cnt <= 0;
check_start <= 0;
ip_head_cnt <= 0;
udp_cnt <= 0;
rx_cnt <= 0;
rx_data_o <= 0;
rx_data_valid_o <= 0;
crc_cnt <= 0;
rx_done <= 0;
PS_MAC[0] <= 0;
PS_MAC[1] <= 0;
PS_MAC[2] <= 0;
PS_MAC[3] <= 0;
PS_MAC[4] <= 0;
PS_MAC[5] <= 0;
I_CRC_INIT <= 0;
if(!RX_ER)begin
state <=1;
I_CRC_INIT<=1;
end
else begin
state <=0;
I_CRC_INIT<=0;
end
end
1:begin
I_CRC_INIT<=0;
if(RXD==ETH_PREAMBLE&&RX_DV)
lead_code_cnt <= lead_code_cnt + 1;
else if(RXD==ETH_SFD&&RX_DV)
lead_code_cnt <= lead_code_cnt + 1;
else
lead_code_cnt <= lead_code_cnt;
if(lead_code_cnt>=4'd7)
state <= 2;
else
state <= 1;
end
2:begin
lead_code_cnt <= 0;
if(fpga_mac_cnt>=5)begin
state <= 3;
end
else
state <= 2;
end
3:begin
if(RX_DV)begin
PS_MAC[ps_mac_cnt]<= RXD;
ps_mac_cnt <= ps_mac_cnt + 1;
end
else begin
ps_mac_cnt <= ps_mac_cnt;
end
if(ps_mac_cnt>=4'd5)
state <= 4;
else
state <= 3;
end
4:begin
ps_mac_cnt <= 0;
if(RX_DV)
ETH_TYPE[15:8]<= RXD;
else
ETH_TYPE[15:8]<= ETH_TYPE[15:8];
state<=5;
end
5:begin
if(RX_DV)
ip_head_cnt <= ip_head_cnt + 1;
else
ip_head_cnt <= ip_head_cnt;
case (ip_head_cnt)
0:ETH_TYPE[7:0] <= RXD;
1:begin
IP_HEAD_VER <=RXD[7:4];
IP_HEAD_LEN <=RXD[3:0];
end
2:IP_HEAD_TOS <=RXD;
3:IP_LENGTH[15:8] <=RXD;
4:IP_LENGTH[7:0] <=RXD;
5:IP_HEAD_ID[15:8] <=RXD;
6:IP_HEAD_ID[7:0] <=RXD;
7:begin
IP_HEAD_FLAG <=RXD[7:5];
IP_HEAD_OFFSET[12:8]<=RXD[4:0];
end
8:IP_HEAD_OFFSET[7:0] <=RXD;
9:IP_HEAD_TTL <=RXD;
10:IP_HEAD_PROT <=RXD;
11:PS_CHECK[15:8] <=RXD;
12:PS_CHECK[7:0] <=RXD;
13:PS_IP_ADDR[31:24] <=RXD;
14:PS_IP_ADDR[23:16] <=RXD;
15:PS_IP_ADDR[15:8] <=RXD;
16:PS_IP_ADDR[7:0] <=RXD;
17:AIM_IP_ADDR[31:24] <=RXD;
18:AIM_IP_ADDR[23:16] <=RXD;
19:AIM_IP_ADDR[15:8] <=RXD;
20:begin
AIM_IP_ADDR[7:0] <=RXD;
state <= 6;
check_start <= 1;
end
//此部分是可选部分和填充部分,看需求添加即可
// 21:IP_Optional[15:8] <=RXD;
// 22:IP_Optional[7:0] <=RXD;
// 23:IP_fill[15:8] <=RXD;
// 24:begin
// IP_fill[7:0] <=RXD;
// state <= 6;
// check_start <= 1;
// end
default: ;
endcase
end
6:begin
check_start <= 0;
ip_head_cnt <= 0;
if(RX_DV)
udp_cnt <= udp_cnt + 1;
else
udp_cnt <= udp_cnt;
case (udp_cnt)
0: udp_ps_post[15:8] <=RXD;
1: udp_ps_post[7:0] <=RXD;
2: udp_fpga_post[15:8] <=RXD;
3: udp_fpga_post[7:0] <=RXD;
4: udp_length[15:8] <=RXD;
5: udp_length[7:0] <=RXD;
6: udp_check[15:8] <=RXD;
7: begin
state <=7;
udp_check[7:0] <=RXD;
end
default: ;
endcase
end
7:begin
udp_cnt <= 0;
if(RX_DV)begin
rx_data_o <= RXD;
rx_cnt <= rx_cnt + 1;
rx_data_valid_o <= 1;
end
else begin
rx_data_o <= rx_data_o;
rx_cnt <= rx_cnt;
rx_data_valid_o <= 0;
end
if(rx_cnt>=udp_length-4'd9)
state <= 8;
else
state <= 7;
end
8:begin
rx_cnt <= 0;
rx_data_valid_o <= 0;
rx_data_o <= 0;
if(RX_DV)
crc_cnt <= crc_cnt + 1;
else
crc_cnt <= crc_cnt;
case (crc_cnt)
0:CRC32_DATA_O[7:0] <= RXD;
1:CRC32_DATA_O[15:8] <= RXD;
2:CRC32_DATA_O[23:16] <= RXD;
3:begin
CRC32_DATA_O[31:24] <= RXD;
state <= 9;
end
default:;
endcase
end
9:begin
rx_done <= 1;
state <= 0;
end
default:begin
state <= 0;
lead_code_cnt <= 0;
ps_mac_cnt <= 0;
check_start <= 0;
ip_head_cnt <= 0;
udp_cnt <= 0;
rx_cnt <= 0;
rx_data_o <= 0;
rx_data_valid_o <= 0;
crc_cnt <= 0;
rx_done <= 0;
PS_MAC[0] <= 0;
PS_MAC[1] <= 0;
PS_MAC[2] <= 0;
PS_MAC[3] <= 0;
PS_MAC[4] <= 0;
PS_MAC[5] <= 0;
end
endcase
end
always@(posedge RX_CLK or negedge rst_n)begin
if(!rst_n)begin
fpga_mac_cnt<= 0;
FPGA_MAC[0] <= 0;
FPGA_MAC[1] <= 0;
FPGA_MAC[2] <= 0;
FPGA_MAC[3] <= 0;
FPGA_MAC[4] <= 0;
FPGA_MAC[5] <= 0;
end
else if(state==2)begin
if(RX_DV)begin
FPGA_MAC[fpga_mac_cnt]<= RXD;
fpga_mac_cnt <= fpga_mac_cnt + 1;
end
else begin
fpga_mac_cnt <= fpga_mac_cnt;
end
end
else begin
fpga_mac_cnt<= 0;
FPGA_MAC[0] <= 0;
FPGA_MAC[1] <= 0;
FPGA_MAC[2] <= 0;
FPGA_MAC[3] <= 0;
FPGA_MAC[4] <= 0;
FPGA_MAC[5] <= 0;
end
end
check_num chek_num_in(
.IP_SA (AIM_IP_ADDR ),
.IP_DA (PS_IP_ADDR ),
.clk (RX_CLK ),
.rst_n (rst_n ),
.check_start (check_start ),
.ip_versions (IP_HEAD_VER ),
.ip_head_length (IP_HEAD_LEN ),
.ip_diffserv (IP_HEAD_TOS ),
.ip_all_length (IP_LENGTH ),
.ip_tag (IP_HEAD_ID ),
.ip_logo (IP_HEAD_FLAG ),
.ip_sheet (IP_HEAD_OFFSET ),
.ip_live (IP_HEAD_TTL ),
.ip_agreement (IP_HEAD_PROT ),
.ip_Optional (IP_Optional ),
.ip_fill (IP_fill ),
.ip_check_valid (ip_check_valid ),
.ip_checknum (ip_checknum )
);
CRC32_D8 CRC32_D8_in(
.I_OPR_CLK (RX_CLK ),
.I_OPR_RSTN (rst_n ),
.I_CRC_INIT (I_CRC_INIT ),
.I_CRC_EN (I_CRC_EN ),
.I_DATA (data_o ),
.O_CRC_RES (CRC32_DATA )
);
endmodule
例化部分的代码参考上一篇文章
仿真代码:
`timescale 1ns / 1ps
//
// Engineer: 兵棒
// Create Date: 2023/12/07 15:32:15
// Module Name: tb_check
// Description: 仿真
//
module tb_check();
reg clk;
reg rst_n;
//out
reg tx_start;
reg tx_wait;
reg [7:0] data_i;
reg data_valid_i;
reg [15:0] data_length_i;
wire [7:0] tx_data;
wire tx_en;
wire tx_er;
wire gtx_clk;
wire tx_data_start;
wire tx_done ;
//in
wire [7:0] rx_data ;
wire rx_data_valid ;
always #4 clk=~clk;
initial
begin
clk=0;rst_n=0;tx_start=0;data_length_i=16'd0;tx_wait=0;
#50 rst_n=1;
#50 tx_start=1;
#8 tx_start=0;data_length_i=16'd30;
end
always@(posedge clk)begin
if(!rst_n)
data_i<=0;
else
data_i<=data_i+1;
end
UDP_out tb_udp_out(
.clk (clk ) ,
.rst_n (rst_n ) ,
.tx_start (tx_start ) ,
.data_i (data_i ) ,
.data_valid_i (data_valid_i ) ,
.data_length_i(data_length_i) ,
.tx_data (tx_data ) ,
.tx_en (tx_en ) ,
.tx_er (tx_er ) ,
.gtx_clk (gtx_clk ) ,
.tx_data_start(tx_data_start) ,
.tx_done (tx_done )
);
UDP_in tb_udp_in(
.RX_CLK (clk ) ,
.rst_n (rst_n ) ,
.RXD (tx_data ) ,
.RX_ER (tx_er ) ,
.RX_DV (tx_en ) ,
.rx_data (rx_data ) ,
.rx_data_valid(rx_data_valid)
);
endmodule
仿真图
接收到的数据是通过上一期的发送端做了一个回环测试,可以看到接收端RXD数据正常