UDP_data_process/UDP_data_process.v

358 lines
11 KiB
Verilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/10/31 16:59:43
// Design Name:
// Module Name: UDP_data_process
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module UDP_data_process (
input clk,
input reset,
input eth_linked,
output reg pulse_second,
// input data_fifo_rden,
// UDP接收FIFO接口
output reg udp_app_recv_fifo_rden,
input [7:0] udp_app_recv_fifo_rddata,
input [11:0] udp_app_recv_fifo_rdcnt,
input udp_app_recv_fifo_empty,
// UDP发送FIFO接口
input udp_app_send_fifo_rden,
output [7:0] udp_app_send_fifo_rddata,
output [11:0] udp_app_send_fifo_rdcnt,
output udp_app_send_fifo_empty,
// TOE寄存器接口
output reg TOE_reg_wren,
output reg TOE_reg_rden,
output reg [65:0] TOE_reg_din,
input TOE_reg_out_valid,
input [65:0] TOE_reg_dout,
// 通信板(CMU)状态信息接口
output CMU_Status_Info_ready,
input CMU_Status_Info_valid,
input CMU_Status_Info_last,
input [31:0] CMU_Status_Info_data,
// 调控板(XYZ)状态信息接口
output XYZ_Status_Info_ready,
input XYZ_Status_Info_valid,
input XYZ_Status_Info_last,
input [31:0] XYZ_Status_Info_data,
// 读出板(DAQ)状态信息接口
output DAQ_Status_Info_ready,
input DAQ_Status_Info_valid,
input DAQ_Status_Info_last,
input [31:0] DAQ_Status_Info_data
);
// wire udp_app_recv_fifo_rden_r;
wire udp_app_recv_fifo_ready;
wire udp_recv_data_tvalid;
wire [31:0]udp_recv_data;
// 协议头
parameter [15:0] HDR_DATA = 16'h4d44;
parameter [15:0] HDR_CTRL = 16'h4547;
parameter [15:0] HDR_TOE = 16'h494e;
// 4个状态空闲、读Header、读Length、读Payload&Check
reg [1:0] parse_state;
localparam P_IDLE = 2'd0;
localparam P_DATA = 2'd1;
reg [2:0] deal_state;
reg deal_busy;
localparam D_IDLE = 3'd0;
localparam D_HEAD = 3'd1;
localparam D_TOE_1 = 3'd2;
localparam D_TOE_2 = 3'd3;
localparam D_EXE = 3'd4;
localparam D_CTRL =3'd5;
reg [3:0]TOE_SFP_ID;
reg TOE_RW_FLAG;
reg [31:0] TOE_ADDR;
reg [31:0] TOE_DATA;
reg [15:0] header_reg;
reg [15:0] length_reg;
reg [31:0] data_reg;
reg [31:0] crc32_calc;
reg [31:0] crc32_recv;
reg [15:0] payload_remain;
reg recv_udp_frame_last;
reg crc_match; // CRC校验匹配标记
wire crc_error;
wire [31:0]udp_recv_data_reorder;
reg cnt;
wire data_fifo_rst ;
reg data_fifo_wren;
reg [31:0] data_fifo_din;
reg data_fifo_rden;
wire [31:0] data_fifo_dout;
wire data_fifo_empty;
wire data_fifo_full;
reg state_report_en;
reg [27:0] second_timer = 'b0;
// ---------------------------
// 读取FIFO逻辑
// ---------------------------
always@(posedge clk)
if(reset)
udp_app_recv_fifo_rden <= 1'b0;
else if((~udp_app_recv_fifo_empty) && udp_app_recv_fifo_ready && (~deal_busy))
udp_app_recv_fifo_rden <= 1'b1;
else if(udp_app_recv_fifo_rdcnt == 12'b0)
udp_app_recv_fifo_rden <= 1'b0;
else
udp_app_recv_fifo_rden <= 1'b0;
//assign udp_app_recv_fifo_rden_r = udp_app_recv_fifo_rden && (~udp_app_recv_fifo_empty); // udp recv data does not delay, so the en needn't delay
axis_dwidth_converter_0 axis_dwidth_converter_udprx(
.aclk (clk), // input
.aresetn (~reset), // input
.s_axis_tvalid(udp_app_recv_fifo_rden), // input
.s_axis_tready(udp_app_recv_fifo_ready), // output
.s_axis_tdata (udp_app_recv_fifo_rddata), // input [7:0]
.m_axis_tvalid(udp_recv_data_tvalid), // output
.m_axis_tready(1'b1), // input
.m_axis_tdata (udp_recv_data) // output [63:0]
);
assign udp_recv_data_reorder = {udp_recv_data[7:0], udp_recv_data[15:8], udp_recv_data[23:16], udp_recv_data[31:24]};
assign crc_error = crc_match ^ recv_udp_frame_last;
always @(posedge clk or posedge reset) begin
if(reset)begin
cnt <=0;
parse_state <= 0;
crc32_recv<=0;
crc_match =1'b0;
payload_remain<=0;
recv_udp_frame_last <=0;
crc32_calc <= 32'hFFFFFFFF;
end
else begin
case (parse_state)
P_IDLE : begin
crc32_calc <= 32'hFFFFFFFF;
recv_udp_frame_last <=1'b0;
crc_match =1'b0;
if (udp_recv_data_tvalid) begin
payload_remain <= udp_recv_data_reorder[15:0];
data_fifo_din <=udp_recv_data_reorder;//存数据,跳到PDATA的时候就存成功了。
data_fifo_wren <=1'b1;
parse_state <= P_DATA;
end
end
P_DATA : begin
data_fifo_wren <=1'b0;
if (udp_recv_data_tvalid) begin
if(payload_remain == 0) begin //判断余量为0的时候的tvalidcrc_rev数据就到了。
parse_state <= P_IDLE;
crc32_recv <= udp_recv_data_reorder;
recv_udp_frame_last <=1'b1; //收到完整一帧
data_fifo_rden <= 1'b1;
if(crc32_calc == udp_recv_data_reorder)
crc_match =1'b1;
else
crc_match =1'b0;
end
else begin
data_reg <= udp_recv_data_reorder;
data_fifo_din <=udp_recv_data_reorder; //存数据,判断payload_remain == 0 payload就完整存进去了。
data_fifo_wren <=1'b1;
crc32_calc <= calc_crc32(udp_recv_data_reorder,crc32_calc);
payload_remain <= payload_remain -4;
end
end
end
endcase
end
end
fifo_generator_0 data_cache_fifo (
.clk (clk), // 时钟
.srst (data_fifo_rst), // 同步复位
.din (data_fifo_din), // 写入数据
.wr_en (data_fifo_wren), // 写使能
.rd_en (data_fifo_rden), // 读使能
.dout (data_fifo_dout), // 读出数据
.full (data_fifo_full), // 满标志
.empty (data_fifo_empty) // 空标志
);
//处理状态机
always @(posedge clk or posedge reset) begin
if(reset)begin
data_fifo_rden <= 0;
deal_state <=0;
deal_busy <=0;
TOE_SFP_ID <=0;
TOE_RW_FLAG <=0;
TOE_ADDR <= 0;
TOE_DATA <= 0;
header_reg <=0;
TOE_reg_wren <= 0;
TOE_reg_rden <= 0;
TOE_reg_din <= 0;
state_report_en <= 0;
end
else begin
case(deal_state)
D_IDLE : begin
TOE_reg_wren <= 0;
TOE_reg_rden <= 0;
TOE_reg_din <= 0;
if(recv_udp_frame_last)begin //last拉高的同时 也把data_fifo_rden拉高了
deal_busy <= 1'b1;
data_fifo_rden <= 1; // 这个拉高其实没用。如果这时候拉高,下个时钟数据处来,下下个时钟才能触发。所以这个时钟数据就要出来。
deal_state <= D_HEAD;
end
end
D_HEAD :begin //判断是头的类型,执行对应操作
header_reg <= data_fifo_dout[31:16]; // Header高字节 data_fifo_dout出来的操作和被赋值的操作是同时进行的默认赋值前一个数。
if( data_fifo_dout[31:16]== HDR_TOE )begin
deal_state<= D_TOE_1;
data_fifo_rden <= 1;
end
else if(data_fifo_dout[31:16] == HDR_CTRL)begin
deal_state <= D_CTRL;
data_fifo_rden <= 0; //如果现在拉低了,
end
else
deal_state <= D_IDLE;
end
D_TOE_1 :begin
TOE_reg_wren <= 0;
TOE_reg_rden <= 0;
TOE_reg_din <= 0; //TOE控制清除。
TOE_SFP_ID <= data_fifo_dout[23:20]; //TOE是64比特的数据此时获得的是高32bit
TOE_RW_FLAG <= data_fifo_dout[16] ;
TOE_ADDR <= data_fifo_dout[15:0] ; //虽然是32比特的寄存器但地址就是16位。
deal_state <= D_TOE_2;
data_fifo_rden <= 1;
end
D_TOE_2 : begin
TOE_DATA <= data_fifo_dout;
deal_state <= D_EXE;
data_fifo_rden <= 0;
end
D_EXE : begin
if(header_reg == HDR_TOE)begin
//开始TOE命令处理
if(TOE_RW_FLAG) TOE_reg_rden <= 1'b1;
else TOE_reg_wren <= 1'b1;
TOE_reg_din <= {TOE_SFP_ID[1:0],TOE_ADDR,TOE_DATA};
//处理结束
if(data_fifo_empty) begin deal_state <=D_IDLE; deal_busy = 1'b0; end
else begin deal_state <= D_TOE_1; data_fifo_rden <= 1; end
end
end
D_CTRL : begin
if(data_fifo_dout ==32'h1000_0001)begin
state_report_en <= 1;
end
else if (data_fifo_dout ==32'h1000_0000)begin
state_report_en <= 0;
end
else begin
state_report_en <= 0;
end
deal_busy = 1'b0;
deal_state <= D_IDLE;
end
endcase
end
end
//CRC32计算函数生成多项式G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1初始值0xffffffff。
function [31:0] calc_crc32;
input [31:0] data;
input [31:0] crc;
reg [31:0] new_crc;
integer i;
localparam [31:0] POLY = 32'h04C11DB7;
begin
new_crc = crc ^ data;
for (i = 0; i < 32; i = i + 1) begin
if (new_crc[31]) begin
new_crc = (new_crc << 1) ^ POLY;
end else begin
new_crc = new_crc << 1;
end
end
calc_crc32 = new_crc;
end
endfunction
// 1 second timer
always@(posedge clk)
if(reset)
second_timer <= 'b0;
else if((second_timer < 28'd125 - 1) && state_report_en) //状态上报开启,秒计数器才开始工作 实际为28'd125000000
second_timer <= second_timer + 1'b1;
else
second_timer <= 28'd0;
always@(posedge clk)
if(reset)
pulse_second <= 1'b0;
else if( (second_timer >28'd125 - 1 -16))begin
pulse_second <= 1'b1;
end
else
pulse_second <= 1'b0;
endmodule