module status_to_udp ( input clk, input reset, input status_report_en, 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, // UDP0发送FIFO接口(负责TOE) 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接口(负责3块板子) 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 ); // =========================== 参数定义 =========================== reg [3:0] A_state; // 需要4位,因为增加了WAIT_CMU_VALID等状态 localparam IDLE = 4'd0; localparam WAIT_READ = 4'd1; localparam RECV_TOE = 4'd2; localparam WAIT_CMU_VALID = 4'd3; // 新增:等待CMU valid localparam RECV_CMU = 4'd4; localparam WAIT_XYZ_VALID = 4'd5; // 新增:等待XYZ valid localparam RECV_XYZ = 4'd6; localparam WAIT_DAQ_VALID = 4'd7; // 新增:等待DAQ valid localparam RECV_DAQ = 4'd8; reg [3:0] S_state; localparam SEND_IDLE = 4'd0; localparam SEND_TOE_HEAD_LENGTH = 4'd1; localparam SEND_TOE_DATA_1 = 4'd2; localparam SEND_TOE_DATA_LENGTH = 4'd3; localparam SEND_TOE_DATA_2 = 4'd4; localparam SEND_CRC_TOE = 4'd5; localparam SEND_INFO_HEAD_LENGTH = 4'd6; localparam SEND_INFO_DATA = 4'd7; localparam SEND_CRC_INFO = 4'd8; // =========================== 寄存器定义 =========================== reg [31:0] data_buffer; reg [1:0] byte_counter; reg buffer_valid; // FIFO相关信号 reg fifo_wr_en; //udp1 reg [31:0] fifo_wr_data; reg fifo_wr_en_TOE; //udp0 reg [31:0] fifo_wr_data_TOE; 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 send_finish; reg [31:0] crc32_calc; reg info_recv_flag; reg [15:0] Info_data_bytes_num; reg [15:0] Info_data_bytes_num_reg; // 超时计数器 reg [7:0] wait_timeout_cnt; // 轮询计数器 reg [1:0] poll_counter; 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; // =========================== FIFO =========================== //512 depth 32to8 --responsible for UDP0(TOE) fifo_generator_32to8 fifo_32to8_TOE ( .clk(clk), // input wire clk .rst(reset), // input wire rst .wr_en(fifo_wr_en_TOE), // input wire wr_en .din(fifo_wr_data_TOE), // input wire [31 : 0] din .full(), // output wire full .rd_en(udp_app_send_fifo_rden_0), // input wire rd_en .dout(udp_app_send_fifo_rddata_0), // output wire [7 : 0] dout .empty(udp_app_send_fifo_empty_0), // output wire empty .rd_data_count(udp_app_send_fifo_rdcnt_0), // output wire [11 : 0] rd_data_count .wr_rst_busy(), // output wire wr_rst_busy .rd_rst_busy() // output wire rd_rst_busy ); //512 depth 32to8 --responsible for UDP1(state_info) fifo_generator_32to8 fifo_32to8_INFO ( .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_1), // input wire rd_en .dout(udp_app_send_fifo_rddata_1), // output wire [7 : 0] dout .empty(udp_app_send_fifo_empty_1), // output wire empty .rd_data_count(udp_app_send_fifo_rdcnt_1), // 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 .srst(reset), // input wire srst .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 ); //32 to 32 fifo_generator_32to32 info_cache_fifo ( .clk(clk), // input wire clk .srst(reset), // input wire srst .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 ); // ILA实例化(调试用) ila_00 ila_udp_data ( .clk(clk), // input wire clk .probe0({ reset, fifo_wr_en, fifo_wr_data, TOE_reg_dout, TOE_reg_out_valid, TOE_rec_fifo_rden, TOE_rec_fifo_dout, TOE_rec_fifo_empty, info_cache_fifo_din, info_cache_fifo_wren, info_cache_fifo_rden, info_cache_fifo_dout, info_cache_fifo_empty, TOE_ready_Data, TOE_ready_Data_valid, info_recv_flag, send_busy, A_state, S_state, crc32_calc, TOE_payload, Info_data_bytes_num, Info_data_bytes_num_reg, wait_timeout_cnt, poll_counter }) ); // =========================== 仲裁存储状态机 =========================== always @(posedge clk) begin if (reset) begin A_state <= IDLE; TOE_ready_Data <= 64'b0; TOE_ready_Data_valid <= 1'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; send_busy <= 1'b0; CMU_Status_Info_ready <= 1'b0; XYZ_Status_Info_ready <= 1'b0; DAQ_Status_Info_ready <= 1'b0; wait_timeout_cnt <= 8'b0; poll_counter <= 2'b00; end else begin case (A_state) IDLE: begin //0 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; XYZ_Status_Info_ready <= 1'b0; DAQ_Status_Info_ready <= 1'b0; Info_data_bytes_num <= 16'b0; wait_timeout_cnt <= 8'b0; if (send_finish) begin send_busy <= 1'b0; end // 优先级仲裁:TOE > 状态信息板卡 if ((!TOE_rec_fifo_empty) && (!send_busy)) begin A_state <= WAIT_READ; TOE_rec_fifo_rden <= 1'b1; end else if (status_report_en && (!send_busy)) begin // 轮询不同的板卡:按照CMU->XYZ->DAQ的顺序 case (poll_counter) 2'b00: begin // CMU A_state <= WAIT_CMU_VALID; CMU_Status_Info_ready <= 1'b1; end 2'b01: begin // XYZ A_state <= WAIT_XYZ_VALID; XYZ_Status_Info_ready <= 1'b1; end 2'b10: begin // DAQ A_state <= WAIT_DAQ_VALID; DAQ_Status_Info_ready <= 1'b1; end default: begin A_state <= IDLE; poll_counter <= 2'b00; end endcase end else begin A_state <= IDLE; end end WAIT_READ: begin //1 A_state <= RECV_TOE; TOE_rec_fifo_rden <= 1'b0; end RECV_TOE: begin //2 TOE_ready_Data[63] <= 1'b1; // 读标志位 TOE_ready_Data[56:52] <= 5'h02; // 新增 TOE_ready_Data[49:48] <= TOE_rec_fifo_dout[65:64]; // CID 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; poll_counter <= 2'b00; // 重置轮询计数器 end WAIT_CMU_VALID: begin //3 wait_timeout_cnt <= wait_timeout_cnt + 1; if (CMU_Status_Info_valid) begin wait_timeout_cnt <= 8'b0; A_state <= RECV_CMU; info_cache_fifo_wren <= 1'b1; info_cache_fifo_din <= CMU_Status_Info_data; Info_data_bytes_num <= Info_data_bytes_num + 4; end else if (wait_timeout_cnt > 8'd10) begin // 超时10个周期 wait_timeout_cnt <= 8'b0; CMU_Status_Info_ready <= 1'b0; poll_counter <= poll_counter + 1; // 尝试下一个板卡 A_state <= IDLE; end end RECV_CMU: begin //4 // 保持ready为高,直到last信号到来 CMU_Status_Info_ready <= 1'b1; if(CMU_Status_Info_valid) info_cache_fifo_wren <= 1'b1; else info_cache_fifo_wren <= 1'b0; info_cache_fifo_din <= CMU_Status_Info_data; if (CMU_Status_Info_valid) begin /////valid可能为高低高低交替,所以计数也要加判断逻辑,以免多计数。 Info_data_bytes_num <= Info_data_bytes_num + 4; end if (CMU_Status_Info_last) begin A_state <= IDLE; CMU_Status_Info_ready <= 1'b0; // info_cache_fifo_wren <= 1'b0; send_busy <= 1'b1; // 拿到数立马进行发送状态 info_recv_flag <= 1'b1; poll_counter <= 2'b00; // 重置轮询计数器 end end WAIT_XYZ_VALID: begin //5 wait_timeout_cnt <= wait_timeout_cnt + 1; if (XYZ_Status_Info_valid) begin wait_timeout_cnt <= 8'b0; A_state <= RECV_XYZ; info_cache_fifo_wren <= 1'b1; info_cache_fifo_din <= XYZ_Status_Info_data; Info_data_bytes_num <= Info_data_bytes_num + 4; end else if (wait_timeout_cnt > 8'd10) begin // 超时10个周期 wait_timeout_cnt <= 8'b0; XYZ_Status_Info_ready <= 1'b0; poll_counter <= poll_counter + 1; // 尝试下一个板卡 A_state <= IDLE; end end RECV_XYZ: begin //6 XYZ_Status_Info_ready <= 1'b1; if(XYZ_Status_Info_valid) info_cache_fifo_wren <= 1'b1; else info_cache_fifo_wren <= 1'b0; info_cache_fifo_din <= XYZ_Status_Info_data; if (XYZ_Status_Info_valid) begin /////valid可能为高低高低交替,所以计数也要加判断逻辑,以免多计数。 Info_data_bytes_num <= Info_data_bytes_num + 4; end if (XYZ_Status_Info_last) begin A_state <= IDLE; XYZ_Status_Info_ready <= 1'b0; // info_cache_fifo_wren <= 1'b0; send_busy <= 1'b1; info_recv_flag <= 1'b1; poll_counter <= 2'b00; // 重置轮询计数器 end end WAIT_DAQ_VALID: begin //7 wait_timeout_cnt <= wait_timeout_cnt + 1; if (DAQ_Status_Info_valid) begin wait_timeout_cnt <= 8'b0; A_state <= RECV_DAQ; info_cache_fifo_wren <= 1'b1; info_cache_fifo_din <= DAQ_Status_Info_data; Info_data_bytes_num <= Info_data_bytes_num + 4; end else if (wait_timeout_cnt > 8'd10) begin // 超时10个周期 wait_timeout_cnt <= 8'b0; DAQ_Status_Info_ready <= 1'b0; poll_counter <= 2'b00; // 轮询回到CMU A_state <= IDLE; end end RECV_DAQ: begin //8 DAQ_Status_Info_ready <= 1'b1; if(DAQ_Status_Info_valid) info_cache_fifo_wren <= 1'b1; else info_cache_fifo_wren <= 1'b0; info_cache_fifo_din <= DAQ_Status_Info_data; if (DAQ_Status_Info_valid) begin /////valid可能为高低高低交替,所以计数也要加判断逻辑,以免多计数。 Info_data_bytes_num <= Info_data_bytes_num + 4; end if (DAQ_Status_Info_last) begin A_state <= IDLE; DAQ_Status_Info_ready <= 1'b0; // info_cache_fifo_wren <= 1'b0; send_busy <= 1'b1; info_recv_flag <= 1'b1; poll_counter <= 2'b00; // 重置轮询计数器 end end default: A_state <= IDLE; endcase end end // =========================== 发送状态机 =========================== always @(posedge clk or posedge reset) begin if(reset) begin S_state <= SEND_IDLE; fifo_wr_en <= 1'b0; fifo_wr_data <= 32'b0; fifo_wr_en_TOE <= 1'b0;//udp0 fifo_wr_data_TOE <= 32'b0; crc32_calc <= 32'hFFFFFFFF; info_cache_fifo_rden <= 1'b0; TOE_payload <= 64'b0; send_finish <= 1'b0; Info_data_bytes_num_reg <= 1'b0; end else begin case(S_state) SEND_IDLE: begin //0 fifo_wr_en <= 1'b0; fifo_wr_data <= 32'b0; fifo_wr_en_TOE <= 1'b0;//udp0 fifo_wr_data_TOE <= 32'b0; crc32_calc <= 32'hFFFFFFFF; send_finish <= 1'b0; Info_data_bytes_num_reg <= 1'b0; info_cache_fifo_rden <= 1'b0; 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'b1; Info_data_bytes_num_reg <= Info_data_bytes_num; end end SEND_TOE_HEAD_LENGTH: begin //1 fifo_wr_en_TOE <= 1'b1; fifo_wr_data_TOE <= 32'h4547000c; S_state <= SEND_TOE_DATA_1; end SEND_TOE_DATA_1: begin //2 fifo_wr_en_TOE <= 1'b1; fifo_wr_data_TOE <= TOE_payload[63:32]; crc32_calc <= calc_crc32(TOE_payload[63:32], crc32_calc); S_state <= SEND_TOE_DATA_LENGTH; end SEND_TOE_DATA_LENGTH: begin //3 fifo_wr_en_TOE <= 1'b1; fifo_wr_data_TOE <= 32'd4; // 固定四字节长度 crc32_calc <= calc_crc32(32'd4, crc32_calc); S_state <= SEND_TOE_DATA_2; end SEND_TOE_DATA_2: begin //4 fifo_wr_en_TOE <= 1'b1; fifo_wr_data_TOE <= TOE_payload[31:0]; crc32_calc <= calc_crc32(TOE_payload[31:0], crc32_calc); S_state <= SEND_CRC_TOE; end SEND_CRC_TOE: begin //5 fifo_wr_en_TOE <= 1'b1; fifo_wr_data_TOE <= crc32_calc; S_state <= SEND_IDLE; send_finish <= 1'b1; info_cache_fifo_rden <= 1'b0; end SEND_INFO_HEAD_LENGTH: begin //6 fifo_wr_en <= 1'b1; fifo_wr_data[31:16] <= 16'h494e; // "IN" fifo_wr_data[15:0] <= Info_data_bytes_num_reg; crc32_calc <= 32'hFFFFFFFF; //be ready to caculate crc S_state <= SEND_INFO_DATA; end SEND_INFO_DATA: begin //7 fifo_wr_en <= 1'b1; fifo_wr_data <= info_cache_fifo_dout; crc32_calc <= calc_crc32(info_cache_fifo_dout, crc32_calc); if(info_cache_fifo_empty) begin info_cache_fifo_rden <= 1'b0; S_state <= SEND_CRC_INFO; end else begin info_cache_fifo_rden <= 1'b1; end end SEND_CRC_INFO: begin //8 fifo_wr_en <= 1'b1; fifo_wr_data <= crc32_calc; S_state <= SEND_IDLE; send_finish <= 1'b1; info_cache_fifo_rden <= 1'b0; end default: S_state <= SEND_IDLE; endcase end end // =========================== CRC32计算函数 =========================== 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