From 6287315eef2a850ccb3e8958f192fa23b0fd3bc5 Mon Sep 17 00:00:00 2001 From: yangshenbo Date: Wed, 5 Nov 2025 14:39:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 初步完成所有功能,但两个接收解析和接收转发未合并 --- UDP_data_process.v | 357 +++++++++++++++++++++++++++++++++++++++++++++ status_to_udp.v | 333 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 690 insertions(+) create mode 100644 UDP_data_process.v create mode 100644 status_to_udp.v diff --git a/UDP_data_process.v b/UDP_data_process.v new file mode 100644 index 0000000..d06c556 --- /dev/null +++ b/UDP_data_process.v @@ -0,0 +1,357 @@ +`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的时候的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 (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 diff --git a/status_to_udp.v b/status_to_udp.v new file mode 100644 index 0000000..6427331 --- /dev/null +++ b/status_to_udp.v @@ -0,0 +1,333 @@ +module status_to_udp ( + input clk, + input reset, + + input TOE_reg_out_valid, + input [65:0] TOE_reg_dout, + // 通信板(CMU)状态信息接口 + output reg CMU_Status_Info_ready, + input CMU_Status_Info_valid, + input CMU_Status_Info_last, + input [31:0] CMU_Status_Info_data, + + // 调控板(XYZ)状态信息接口 + output reg XYZ_Status_Info_ready, + input XYZ_Status_Info_valid, + input XYZ_Status_Info_last, + input [31:0] XYZ_Status_Info_data, + + // 读出板(DAQ)状态信息接口 + output reg DAQ_Status_Info_ready, + input DAQ_Status_Info_valid, + input DAQ_Status_Info_last, + input [31:0] DAQ_Status_Info_data, + + // 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 +); + +// =========================== 参数定义 =========================== +reg [2:0] A_state; +localparam IDLE = 3'd0; +localparam WAIT_READ =3'd1; +localparam RECV_TOE = 3'd2; +localparam RECV_CMU = 3'd3; +localparam RECV_XYZ = 3'd4; +localparam RECV_DAQ = 3'd5; + + +reg [2:0]S_state; +localparam SEND_IDLE = 3'd0; +localparam SEND_TOE_HEAD_LENGTH = 3'd1; +localparam SEND_TOE_DATA_1 = 3'd2; +localparam SEND_TOE_DATA_2 = 3'd3; +localparam SEND_CRC = 3'd4; +localparam SEND_INFO_HEAD_LENGTH = 3'd5; +localparam SEND_INFO_DATA = 3'd6; + + + + + + +// =========================== 寄存器定义 =========================== + + +reg [31:0] data_buffer; +reg [1:0] byte_counter; +reg buffer_valid; + +// FIFO相关信号 +reg fifo_wr_en; +reg [31:0] fifo_wr_data; +wire fifo_full; +wire TOE_rec_fifo_empty; +reg TOE_rec_fifo_rden; +wire [65:0]TOE_rec_fifo_dout; +reg [63:0]TOE_ready_Data; +reg TOE_ready_Data_valid; +reg [63:0]TOE_payload; + +reg [31:0]CMU_Status_data; +reg send_busy; +reg [31:0]crc32_calc; +reg info_recv_flag; +reg [15:0]Info_data_bytes_num; + + + +// =========================== FIFO实例化 =========================== + +//512 depth 32to8 +fifo_generator_32to8 fifo_32to8 ( + .clk(clk), // input wire clk + .rst(reset), // input wire rst + .wr_en(fifo_wr_en), // input wire wr_en + .din(fifo_wr_data), // input wire [31 : 0] din + .full(), // output wire full + + .rd_en(udp_app_send_fifo_rden), // input wire rd_en + .dout(udp_app_send_fifo_rddata), // output wire [7 : 0] doutCMU + .empty(udp_app_send_fifo_empty), // output wire empty + .rd_data_count(udp_app_send_fifo_rdcnt), // output wire [11 : 0] rd_data_count + + .wr_rst_busy(), // output wire wr_rst_busy + .rd_rst_busy() // output wire rd_rst_busy +); + +//256 depth 66 to 66 +fifo_generator_66to66 TOE_rec_fifo ( + .clk(clk), // input wire clk + .din(TOE_reg_dout), // input wire [65 : 0] din + .wr_en(TOE_reg_out_valid), // input wire wr_en + .rd_en(TOE_rec_fifo_rden), // input wire rd_en + .dout(TOE_rec_fifo_dout), // output wire [65 : 0] dout + .full(), // output wire full + .empty(TOE_rec_fifo_empty) // output wire empty +); + +reg [31:0]info_cache_fifo_din; +reg info_cache_fifo_wren; +reg info_cache_fifo_rden; +wire [31:0]info_cache_fifo_dout; +wire info_cache_fifo_full; +wire info_cache_fifo_empty; +//32 to 32 +fifo_generator_32to32 info_cache_fifo ( + .clk(clk), // input wire clk + .din(info_cache_fifo_din), // input wire [31 : 0] din + .wr_en(info_cache_fifo_wren), // input wire wr_en + .rd_en(info_cache_fifo_rden), // input wire rd_en + .dout(info_cache_fifo_dout), // output wire [31 : 0] dout + .full(info_cache_fifo_full), // output wire full + .empty(info_cache_fifo_empty) // output wire empty +); + +// =========================== 仲裁存储状态机 =========================== +always @(posedge clk or posedge reset) begin + if (reset)begin + A_state <= IDLE; + TOE_ready_Data <= 64'b0; + TOE_rec_fifo_rden <= 1'b0; + info_cache_fifo_din <= 32'b0; + info_cache_fifo_wren <= 1'b0; + info_recv_flag <= 1'b0; + Info_data_bytes_num <= 16'b0; + end + else + begin + case (A_state) + IDLE: begin + TOE_ready_Data <= 64'b0; + TOE_ready_Data_valid <=1'b0; + info_cache_fifo_wren <= 1'b0; + info_cache_fifo_din <= 32'b0; + info_recv_flag = 1'b0; + CMU_Status_Info_ready <=1'b0; + DAQ_Status_Info_ready <=1'b0; + XYZ_Status_Info_ready <=1'b0; + // 优先级仲裁:TOE >CMU > XYZ > DAQ + if((!TOE_rec_fifo_empty) &&(!send_busy))begin + A_state <= WAIT_READ; + TOE_rec_fifo_rden <= 1'b1; + end + else if (CMU_Status_Info_valid &&(!send_busy))begin + A_state <= RECV_CMU; + end + else if (XYZ_Status_Info_valid &&(!send_busy))begin + A_state <= RECV_XYZ; + end + + else if (DAQ_Status_Info_valid &&(!send_busy))begin + A_state <= RECV_DAQ; + end + else + A_state <= IDLE; + end + WAIT_READ : begin + A_state <= RECV_TOE; + TOE_rec_fifo_rden <= 1'b0; + end + + RECV_TOE: begin + //执行TOE发送操作 + TOE_ready_Data[53:52]<=TOE_rec_fifo_dout[65:64]; + TOE_ready_Data[48]<= 1'b1; + TOE_ready_Data[47:32]<=TOE_rec_fifo_dout[47:32]; + TOE_ready_Data[31:0] <= TOE_rec_fifo_dout[31:0]; + TOE_ready_Data_valid <= 1'b1; + send_busy <= 1'b1; //拿到数立马进行发送状态 + A_state <= IDLE; + + end + + RECV_CMU: begin + CMU_Status_Info_ready <=1'b1; + info_cache_fifo_wren <= 1'b1; + info_cache_fifo_din <= CMU_Status_Info_data; + Info_data_bytes_num <= Info_data_bytes_num + 3'd4; + if (CMU_Status_Info_last)begin + A_state <= IDLE; + send_busy <= 1'b1; //拿到数立马进行发送状态 + info_recv_flag = 1'b1; + end + + end + + RECV_XYZ: begin + XYZ_Status_Info_ready <=1'b1; + info_cache_fifo_wren <= 1'b1; + info_cache_fifo_din <= XYZ_Status_Info_data; + Info_data_bytes_num <= Info_data_bytes_num + 3'd4; + if (XYZ_Status_Info_last)begin + A_state <= IDLE; + send_busy <= 1'b1; //拿到数立马进行发送状态 + info_recv_flag = 1'b1; + end + + end + + RECV_DAQ: begin //5 + DAQ_Status_Info_ready <=1'b1; + info_cache_fifo_wren <= 1'b1; + info_cache_fifo_din <= DAQ_Status_Info_data; + Info_data_bytes_num <= Info_data_bytes_num + 3'd4; + if (DAQ_Status_Info_last)begin + A_state <= IDLE; + send_busy <= 1'b1; //拿到数立马进行发送状态 + info_recv_flag = 1'b1; + end + end + + default: A_state <= IDLE; + endcase + end +end + + //发送状态机 + + always @(posedge clk or posedge reset) begin + if(reset)begin + S_state <= SEND_IDLE; + send_busy <=1'b0; + fifo_wr_en<= 1'b0; + fifo_wr_data <= 32'b0; + crc32_calc <= 32'hFFFFFFFF; + info_cache_fifo_rden <= 1'b0; + TOE_payload <= 64'b0; + end + else begin + case(S_state) + SEND_IDLE : begin + fifo_wr_en <= 1'b0; + fifo_wr_data <= 32'b0; + crc32_calc <= 32'hFFFFFFFF; + if(TOE_ready_Data_valid) begin + TOE_payload <= TOE_ready_Data; + S_state <= SEND_TOE_HEAD_LENGTH; + end + else if(info_recv_flag) begin + S_state <= SEND_INFO_HEAD_LENGTH; + info_cache_fifo_rden <= 1; + end + + end + SEND_TOE_HEAD_LENGTH :begin + fifo_wr_en <=1; + fifo_wr_data <= 32'h45470008; + S_state <= SEND_TOE_DATA_1; + end + + SEND_TOE_DATA_1 : begin + fifo_wr_en <=1; + fifo_wr_data <= TOE_payload[63:32]; + crc32_calc <= calc_crc32(TOE_payload[63:32],crc32_calc); + S_state <= SEND_TOE_DATA_2; + end + SEND_TOE_DATA_2 : begin + fifo_wr_en <=1; + fifo_wr_data <= TOE_payload[31:0]; + crc32_calc <= calc_crc32(TOE_payload[31:0],crc32_calc); + S_state <= SEND_CRC; + end + SEND_CRC : begin // + fifo_wr_en <=1; + fifo_wr_data <= crc32_calc; + S_state <= SEND_IDLE; + send_busy <= 1'b0; + info_cache_fifo_rden <= 1'b0; + end + + SEND_INFO_HEAD_LENGTH : begin //5 + fifo_wr_en <=1; + fifo_wr_data[31:16] <= 32'h494e; + fifo_wr_data[15:0] <= Info_data_bytes_num; + Info_data_bytes_num <= 16'b0; //用完就清零 + S_state <= SEND_INFO_DATA; + end + + SEND_INFO_DATA : begin //6 + fifo_wr_en <=1; + fifo_wr_data <= info_cache_fifo_dout; + crc32_calc <= calc_crc32(info_cache_fifo_dout,crc32_calc); + if(info_cache_fifo_empty)begin + S_state <= SEND_CRC; + end + end + + + endcase + end + + end + + + + +// // =========================== FIFO写入控制 =========================== + +//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 + + +endmodule