`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, // UDP接收FIFO接口 output reg udp_app_recv_fifo_rden_0, input [7:0] udp_app_recv_fifo_rddata_0, input [11:0] udp_app_recv_fifo_rdcnt_0, input udp_app_recv_fifo_empty_0, // UDP0发送FIFO接口 input udp_app_send_fifo_rden_0, output [7:0] udp_app_send_fifo_rddata_0, output [11:0] udp_app_send_fifo_rdcnt_0, output udp_app_send_fifo_empty_0, // UDP1接收FIFO接口 //we don't need // UDP1发送FIFO接口 input udp_app_send_fifo_rden_1, output [7:0] udp_app_send_fifo_rddata_1, output [11:0] udp_app_send_fifo_rdcnt_1, output udp_app_send_fifo_empty_1, // 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_ready; wire udp_recv_data_tvalid; wire [31:0]udp_recv_data; // 协议头 parameter [15:0] HDR_DATA = 16'h494e; parameter [15:0] HDR_CTRL = 16'h4d44; parameter [15:0] HDR_TOE = 16'h4547; // 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_R_WAIT =3'd7; //后面新增的,作用是等待读出新数据,解决多级驱动问题 localparam D_HEAD = 3'd1; localparam D_TOE_1 = 3'd2; localparam D_TOE_2 = 3'd3; localparam D_TOE_3 = 3'd4; localparam D_EXE = 3'd5; localparam D_CTRL =3'd6; reg [3:0]TOE_SFP_ID; reg TOE_RW_FLAG; reg [31:0] TOE_ADDR; reg [31:0] TOE_DATA; reg [19:0] TOE_LENGTH; 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; 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; //观察内部的ila ila_00 ila_udp_data ( .clk(clk), // input wire clk .probe0({ reset , udp_recv_data_tvalid , udp_recv_data , // data_fifo_din, // data_fifo_wren, parse_state, recv_udp_frame_last, payload_remain, crc32_calc, crc_match , crc_error , deal_state, udp_app_recv_fifo_ready, TOE_reg_wren, TOE_reg_rden, data_fifo_dout, data_fifo_rden, TOE_reg_din, header_reg, state_report_en, TOE_SFP_ID, TOE_DATA, TOE_ADDR, TOE_RW_FLAG, second_timer, pulse_second }) ); // --------------------------- // 读取FIFO逻辑 // --------------------------- always@(posedge clk) if(reset) udp_app_recv_fifo_rden_0 <= 1'b0; //仿真和上板的区别有2个地方,一个是这边,另外一个是秒脉冲的计数器(2处) else if(udp_app_recv_fifo_rdcnt_0 == 12'b1) //上板后不得注释!!记得取消注释 //实际应该是读计数为1时候就要拉低了,不然板子会多读一个。 udp_app_recv_fifo_rden_0 <= 1'b0; else if((~udp_app_recv_fifo_empty_0) && udp_app_recv_fifo_ready && (~deal_busy) && eth_linked) //如果连接成功才会去读,连接失败不能去读fifo。 udp_app_recv_fifo_rden_0 <= 1'b1; else udp_app_recv_fifo_rden_0 <= 1'b0; axis_dwidth_converter_0 axis_dwidth_converter_udprx( .aclk (clk), // input .aresetn (~reset), // input .s_axis_tvalid(udp_app_recv_fifo_rden_0), // input .s_axis_tready(udp_app_recv_fifo_ready), // output .s_axis_tdata (udp_app_recv_fifo_rddata_0), // 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的时候的tvalid,crc_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 (reset), // 同步复位 .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_LENGTH <= 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_R_WAIT; end end D_R_WAIT:begin deal_state <= D_HEAD; 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 //第一个为CMD高32bit 2 TOE_reg_wren <= 0; TOE_reg_rden <= 0; TOE_reg_din <= 0; //TOE控制清除。 TOE_SFP_ID <= data_fifo_dout[19:16]; //高32bit 旧[28:25] TOE_RW_FLAG <= data_fifo_dout[31] ; /// TOE_ADDR <= data_fifo_dout[15:0] ; // deal_state <= D_TOE_2; data_fifo_rden <= 1; end D_TOE_2 : begin //第二个为CMD低32bit 3 TOE_LENGTH <= data_fifo_dout[19:0]; // TOE_DATA <= data_fifo_dout; deal_state <= D_TOE_3; data_fifo_rden <= 1; end D_TOE_3 : begin // 4 TOE_LENGTH <= TOE_LENGTH -3'd4; TOE_DATA <= data_fifo_dout; deal_state <= D_EXE; data_fifo_rden <= 1'b0; TOE_reg_wren <= 1'b0; TOE_reg_rden <= 1'b0; end D_EXE : begin //5 if(header_reg == HDR_TOE)begin //开始TOE命令处理 if(TOE_LENGTH == 0)begin 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}; end else if(TOE_LENGTH == 3'd4)begin 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}; deal_state <= D_TOE_3; TOE_ADDR <= TOE_ADDR + 4'd4; data_fifo_rden <= 1'b0; //这时候关刚刚好 end else begin 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}; deal_state <= D_TOE_3; TOE_ADDR <= TOE_ADDR + 4'd4; data_fifo_rden <= 1'b1; end //处理结束 if(TOE_LENGTH == 0) begin deal_state <=D_IDLE; deal_busy = 1'b0; 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'd125000000 - 1) && state_report_en) //状态上报开启,秒计数器才开始工作 实际为:28'd125000000 要改2个地方!!! 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'd125000000 - 1 -16))begin //8ns x125 =1us 8ns x125000 =1ms 8ns x125000000 =1s pulse_second <= 1'b1; end else pulse_second <= 1'b0; status_to_udp status_to_udp_0 ( .clk(clk), .reset(reset), .status_report_en(state_report_en), .TOE_reg_out_valid(TOE_reg_out_valid), .TOE_reg_dout(TOE_reg_dout), .CMU_Status_Info_ready(CMU_Status_Info_ready), .CMU_Status_Info_valid(CMU_Status_Info_valid), .CMU_Status_Info_last(CMU_Status_Info_last), .CMU_Status_Info_data(CMU_Status_Info_data), .XYZ_Status_Info_ready(XYZ_Status_Info_ready), .XYZ_Status_Info_valid(XYZ_Status_Info_valid), .XYZ_Status_Info_last(XYZ_Status_Info_last), .XYZ_Status_Info_data(XYZ_Status_Info_data), .DAQ_Status_Info_ready(DAQ_Status_Info_ready), .DAQ_Status_Info_valid(DAQ_Status_Info_valid), .DAQ_Status_Info_last(DAQ_Status_Info_last), .DAQ_Status_Info_data(DAQ_Status_Info_data), .udp_app_send_fifo_rden_0(udp_app_send_fifo_rden_0), .udp_app_send_fifo_rddata_0(udp_app_send_fifo_rddata_0), .udp_app_send_fifo_rdcnt_0(udp_app_send_fifo_rdcnt_0), .udp_app_send_fifo_empty_0(udp_app_send_fifo_empty_0), .udp_app_send_fifo_rden_1(udp_app_send_fifo_rden_1), .udp_app_send_fifo_rddata_1(udp_app_send_fifo_rddata_1), .udp_app_send_fifo_rdcnt_1(udp_app_send_fifo_rdcnt_1), .udp_app_send_fifo_empty_1(udp_app_send_fifo_empty_1) ); endmodule