UDP_data_process/UDP_data_process.v

459 lines
14 KiB
Verilog
Raw 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'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 <= 1'b0;
else if(udp_app_recv_fifo_rdcnt == 12'b1) //上板后不得注释!!记得取消注释 //实际应该是读计数为1时候就要拉低了不然板子会多读一个。 仿真又坑了我。跑一次比特流要15分钟呢 //仿真需要 udp_app_recv_fifo_rdcnt == 12'b0 时才拉低
udp_app_recv_fifo_rden <= 1'b0;
else if((~udp_app_recv_fifo_empty) && udp_app_recv_fifo_ready && (~deal_busy) && eth_linked) //如果连接成功才会去读,连接失败不能去读fifo。
udp_app_recv_fifo_rden <= 1'b1;
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 (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(udp_app_send_fifo_rden),
.udp_app_send_fifo_rddata(udp_app_send_fifo_rddata),
.udp_app_send_fifo_rdcnt(udp_app_send_fifo_rdcnt),
.udp_app_send_fifo_empty(udp_app_send_fifo_empty)
);
endmodule