(归纳整理)一、Kintex7实现以太网通信(UDP通信)
一、代码结构

二、代码解析
顶层模块(目前代码实现是回环)
// 模块主要功能是实现以太网通信的RGMII接口
module rgmii_b(
// 输入信号
input sys_nrst, // 系统复位信号,低电平有效
input sys_clk, // 系统时钟
// 输出信号
output e_reset, // 以太网复位信号
output e_mdc, // 以太网MII管理数据时钟
inout e_mdio, // 以太网MII管理数据输入输出线
// 以太网GMII接收相关信号
input e_rxc, // 125MHz以太网GMII接收时钟
input e_rxdv, // 以太网GMII接收数据有效信号
input e_rxer, // 以太网GMII接收错误信号
input [7 : 0] e_rxd, // 以太网GMII接收数据[7:0]
// 以太网GMII发送相关信号
output e_gtxc, // 125MHz以太网GMII发送时钟
output e_txen, // 以太网GMII发送使能信号
output e_txer, // 以太网GMII发送错误信号
output [7 : 0] e_txd // 以太网GMII发送数据[7:0]
);
// 内部信号声明
wire [31 : 0] ram_wr_data; // RAM写入数据
wire [31 : 0] ram_rd_data; // RAM读取数据
wire [8 : 0] ram_wr_addr; // RAM写入地址
wire [8 : 0] ram_rd_addr; // RAM读取地址
wire [3 : 0] tx_state; // 发送状态
wire [3 : 0] rx_state; // 接收状态
wire [15 : 0] rx_total_length; // 接收到的总长度
wire [15 : 0] tx_total_length; // 要发送的总长度
wire [15 : 0] rx_data_length; // 接收数据长度
wire [15 : 0] tx_data_length; // 发送数据长度
wire data_receive; // 数据接收完成信号
reg ram_wr_finish; // RAM写完成标志
reg ram_wren_i; // RAM写使能中间变量
reg [8 : 0] ram_addr_i; // 写RAM的地址中间变量
reg [31 : 0] ram_data_i; // 写RAM的数据中间变量
reg [4 : 0] i; // 循环计数变量
wire data_o_valid; // 输出数据有效信号
wire wea; // RAM写使能信号
wire [8 : 0] addra; // RAM的地址
wire [31 : 0] dina; // 写入RAM的数据
// 初始化UDP包数据内容
reg [31 : 0] udp_data [4 : 0]; // UDP数据内容数组
// 以太网MDC和MDIO信号常态赋值为1
assign e_mdc = 1'b1;
assign e_mdio = 1'b1;
// 根据RAM写完成标志和数据输出有效信号来控制RAM写使能和相关地址数据的赋值
assign wea = ram_wr_finish ? data_o_valid : ram_wren_i;
assign addra = ram_wr_finish ? ram_wr_addr : ram_addr_i;
assign dina = ram_wr_finish ? ram_wr_data : ram_data_i;
// 判断是否接收到数据并相应地设置发送数据长度
assign tx_data_length = data_receive ? rx_data_length : 16'd28;
assign tx_total_length = data_receive ? rx_total_length : 16'd48;
//////////////////////////////////////////////////////////////////////////
// GMII PLL相关控制信号,用于时钟信号的生成和复位信号的控制
wire gmii_ctrl_nrst;
wire e_gtxc_local;
// GMII发送时钟赋值
assign e_gtxc = e_gtxc_local;
// 以太网复位信号赋值
assign e_reset = gmii_ctrl_nrst;
// GMII PLL实例化
gmii_pll gmii_pll_inst0(
.gmii_clk (e_gtxc_local),
.locked (gmii_ctrl_nrst),
.resetn (sys_nrst),
.clk_in1 (sys_clk)
);
//////////////////////////////////////////////////////////////////////////
udp udp_inst(
.reset_n (gmii_ctrl_nrst),
.g_clk (e_gtxc_local),
.e_rxc (e_rxc),
.e_rxd (e_rxd),
.e_rxdv (e_rxdv),
.e_txen (e_txen),
.e_txd (e_txd),
.e_txer (e_txer),
.data_o_valid (data_o_valid),
.ram_wr_data (ram_wr_data),
.rx_total_length (rx_total_length),
.rx_state (rx_state),
.rx_data_length (rx_data_length),
.ram_wr_addr (ram_wr_addr),
.data_receive (data_receive),
.ram_rd_data (ram_rd_data),
// debug use
.tx_state (tx_state),
.tx_data_length (tx_data_length),
.tx_total_length (tx_total_length),
.ram_rd_addr (ram_rd_addr)
);
ram ram_inst(
.clka (e_rxc), // input wrclock_sig
.wea (wea), // input wren_sig
.addra (addra), // input [8:0] wraddress_sig
.dina (dina), // input [31:0] data_sig
.clkb (e_rxc), // input rdclock_sig
.addrb (ram_rd_addr), // input [8:0] rdaddress_sig
.doutb (ram_rd_data) // output [31:0] q_sig
);
// UDP数据初始化
always@(*)begin
// 将一些固定的字符串赋值到UDP数据缓存数组中
udp_data[0] <= {"K","I","N","T"}; // 字符串"KINT"
udp_data[1] <= {"E","X","7"," "}; // 字符串"EX7 "
udp_data[2] <= {"U","D","P"," "}; // 字符串"UDP "
udp_data[3] <= {"T","e","s","t"}; // 字符串"Test"
udp_data[4] <= {" ","!","\r","\n"};// 字符串" !\r\n"
end
// 在每个以太网GMII接收时钟上升沿进行的操作
always@(posedge e_rxc)begin
// 如果以太网重置信号有效,则初始化写RAM的控制信号
if(gmii_ctrl_nrst == 1'b0)begin
ram_wr_finish <= 1'b0; // 写完成标志复位
ram_addr_i <= 0; // 写地址归零
ram_data_i <= 0; // 写数据归零
i <= 0; // 计数器归零
end else begin
// 如果全部数据块已经写入完成,则标记写完成
if(i == 5)begin
ram_wr_finish <= 1'b1; // 写完成标志置1
ram_wren_i <= 1'b0; // 禁止写入
end else begin
// 否则继续写入数据到RAM
ram_wren_i <= 1'b1;
ram_addr_i <= ram_addr_i+1'b1; // 写地址递增
ram_data_i <= udp_data[i]; // 从UDP数据数组中取值写入
i <= i+1'b1;
end
end
end
endmoduleUDP模块
// 定义UDP模块 module udp( // 输入,异步复位信号,低电平有效 input wire reset_n, // 输入,全局时钟信号 input wire g_clk, // 输入,以太网接收时钟信号 input wire e_rxc, // 输入,以太网接收的数据(8位宽) input wire [7 : 0] e_rxd, // 输入,标识以太网接收数据有效 input wire e_rxdv, // 输出,以太网发送使能信号 output wire e_txen, // 输出,以太网发送数据(8位宽) output wire [7 : 0] e_txd, // 输出,以太网发送错误信号 output wire e_txer, // 输出,数据输出有效信号 output wire data_o_valid, // 输出,写入RAM的数据(32位宽) output wire [31 : 0] ram_wr_data, // 输出,接收到的总长度(16位宽) output wire [15 : 0] rx_total_length, // 输出,接收状态(4位宽) output wire [3 : 0] rx_state, // 输出,接收数据长度(16位宽) output wire [15 : 0] rx_data_length, // 输出,写入RAM的地址(9位宽) output wire [8 : 0] ram_wr_addr, // 输入,读取RAM的数据(32位宽) input wire [31 : 0] ram_rd_data, // 输出,发送状态(4位宽) output wire [3 : 0] tx_state, // 输入,要发送的数据长度(16位宽) input wire [15 : 0] tx_data_length, // 输入,要发送的总长度(16位宽) input wire [15 : 0] tx_total_length, // 输出,读取RAM的地址(9位宽) output wire [8 : 0] ram_rd_addr, // 输出,表示接收到数据的信号 output wire data_receive ); // 内部连线,用于CRC校验模块,提供下一个CRC值 wire [31 : 0] crcnext; // 内部连线,当前CRC值 wire [31 : 0] crc32; // 内部连线,CRC复位信号 wire crcreset; // 内部连线,CRC使能信号 wire crcen; // 发送模块实例化 ipsend ipsend_inst( // 输入,全局时钟信号 .clk (g_clk), // 输出,以太网发送使能信号 .txen (e_txen), // 输出,以太网发送错误信号 .txer (e_txer), // 输出,以太网发送数据 .dataout (e_txd), // 输入,当前CRC值 .crc (crc32), // 输入,从RAM读取的数据 .datain (ram_rd_data), // 输入,CRC使能信号 .crcen (crcen), // 输入,CRC复位信号 .crcre (crcreset), // 输出,发送状态 .tx_state (tx_state), // 输入,要发送的数据长度 .tx_data_length (tx_data_length), // 输入,要发送的总长度 .tx_total_length (tx_total_length), // 输出,读取RAM的地址 .ram_rd_addr (ram_rd_addr) ); // CRC校验模块实例化 crc crc_inst( // 输入,全局时钟信号 .Clk (g_clk), // 输入,CRC复位信号 .Reset (crcreset), // 输入,CRC使能信号 .Enable (crcen), // 输入,接收到的以太网数据 .Data_in (e_txd), // 输出,当前CRC值 .Crc (crc32), // 输出,下一个CRC值 .CrcNext (crcnext) ); // 接收模块实例化 iprecieve iprecieve_inst( // 输入,以太网接收时钟信号 .clk (e_rxc), // 输入,以太网接收的数据 .datain (e_rxd), // 输入,标识以太网接收数据有效 .e_rxdv (e_rxdv), // 输入,异步复位信号,低电平有效 .clr (reset_n), // 以下端口未接线,一般是配置参数,如MAC地址、协议类型等 .board_mac (), .pc_mac (), .IP_Prtcl (), .IP_layer (), .pc_IP (), .board_IP (), .UDP_layer (), // 输出,向RAM写入的数据 .data_o (ram_wr_data), // 输出,标识有效的IP协议 .valid_ip_P (), // 输出,接收到的总长度 .rx_total_length (rx_total_length), // 输出,数据输出有效信号 .data_o_valid (data_o_valid), // 输出,接收状态 .rx_state (rx_state), // 输出,接收数据长度 .rx_data_length (rx_data_length), // 输出,写入RAM的地址 .ram_wr_addr (ram_wr_addr), // 输出,表示接收到数据的信号 .data_receive (data_receive) ); endmodule // 结束UDP模块定义
数据接收模块
module iprecieve(
input clk,
input [7 : 0] datain, // 输入数据
input e_rxdv, // 数据有效信号
input clr, // 清除信号
output reg [47 : 0] board_mac, // 板卡MAC地址
output reg [47 : 0] pc_mac, // PC MAC地址
output reg [15 : 0] IP_Prtcl, // IP协议类型
output reg valid_ip_P, // IP协议是否有效
output reg [159 : 0] IP_layer, // IP层数据
output reg [31 : 0] pc_IP, // PC IP地址
output reg [31 : 0] board_IP, // 板卡IP地址
output reg [63 : 0] UDP_layer, // UDP层数据
output reg [31 : 0] data_o, // 输出数据
output reg [15 : 0] rx_total_length, // 接收数据总长度
output reg data_o_valid, // 输出数据是否有效
output reg [3 : 0] rx_state, // 接收状态
output reg [15 : 0] rx_data_length, // 接收数据长度
output reg [8 : 0] ram_wr_addr, // RAM写地址
output reg data_receive // 是否接收到数据
);
reg [15 : 0] myIP_Prtcl; // 存储IP协议类型
reg [159 : 0] myIP_layer; // 存储IP层数据
reg [63 : 0] myUDP_layer; // 存储UDP层数据
reg [31 : 0] mydata; // 存储数据
reg [2 : 0] byte_counter; // 字节计数器
reg [4 : 0] state_counter; // 状态计数器
reg [95 : 0] mymac; // 存储MAC地址
reg [15 : 0] data_counter; // 数据计数器
localparam idle = 4'd0; // 空闲状态
localparam six_55 = 4'd1; // 接收6个55状态
localparam spd_d5 = 4'd2; // 接收1个d5状态
localparam rx_mac = 4'd3; // 接收MAC地址状态
localparam rx_IP_Protocol = 4'd4; // 接收IP协议类型状态
localparam rx_IP_layer = 4'd5; // 接收IP层数据状态
localparam rx_UDP_layer = 4'd6; // 接收UDP层数据状态
localparam rx_data = 4'd7; // 接收数据状态
localparam rx_finish = 4'd8; // 接收完成状态
// 初始化
initial begin
rx_state <= idle;
end
// UDP数据接收程序
always@(posedge clk)begin
if(!clr)begin
rx_state <= idle;
data_receive <= 1'b0;
end else begin
case(rx_state)
idle: begin
valid_ip_P <= 1'b0;
byte_counter <= 3'd0;
data_counter <= 10'd0;
mydata <= 32'd0;
state_counter <= 5'd0;
data_o_valid <= 1'b0;
ram_wr_addr <= 0;
// 接收数据信号高电平,开始接收数据
if(e_rxdv == 1'b1)begin
// 接收首个55
if(datain[7:0] == 8'h55)begin
rx_state <= six_55;
mydata <= {mydata[23:0],datain[7:0]};
end else
rx_state <= idle;
end
end
// 接收6个55
six_55: begin
if((datain[7:0] == 8'h55) && (e_rxdv == 1'b1))begin
if(state_counter == 5)begin
state_counter <= 0;
rx_state <= spd_d5;
end else
state_counter <= state_counter + 1'b1;
end else
rx_state <= idle;
end
// 接收1个d5
spd_d5: begin
if((datain[7:0] == 8'hd5) && (e_rxdv == 1'b1))
rx_state <= rx_mac;
else
rx_state <= idle;
end
// 接收目标MAC地址和源MAC地址
rx_mac: begin
if(e_rxdv == 1'b1)begin
if(state_counter<5'd11)begin
mymac <= {mymac[87:0],datain};
state_counter <= state_counter + 1'b1;
end else begin
board_mac <= mymac[87:40];
pc_mac <= {mymac[39:0],datain};
state_counter <= 5'd0;
// 源MAC地址 01-60-6E-11-02-0F 写死的,为了减少FPGA的面积
if((mymac[87:72] == 16'h0160) && (mymac[71:56] == 16'h6E11) && (mymac[55:40] == 16'h020F))
rx_state <= rx_IP_Protocol;
else
rx_state <= idle;
end
end else
rx_state <= idle;
end
// 接收2字节的IP协议类型
rx_IP_Protocol: begin
if(e_rxdv == 1'b1)begin
if(state_counter<5'd1)begin
myIP_Prtcl <= {myIP_Prtcl[7:0],datain[7:0]};
state_counter <= state_counter + 1'b1;
end else begin
IP_Prtcl <= {myIP_Prtcl[7:0],datain[7:0]};
valid_ip_P <= 1'b1;
state_counter <= 5'd0;
rx_state <= rx_IP_layer;
end
end else
rx_state <= idle;
end
// 接收20字节的UDP, IP地址
rx_IP_layer: begin
valid_ip_P <= 1'b0;
if(e_rxdv == 1'b1)begin
if(state_counter<5'd19)begin
myIP_layer <= {myIP_layer[151:0],datain[7:0]};
state_counter <= state_counter + 1'b1;
end else begin
IP_layer <= {myIP_layer[151:0],datain[7:0]};
state_counter <= 5'd0;
rx_state <= rx_UDP_layer;
end
end else
rx_state <= idle;
end
// 接收8字节的UDP端口和长度
rx_UDP_layer: begin
rx_total_length <= IP_layer[143:128];
pc_IP <= IP_layer[63:32];
board_IP <= IP_layer[31:0];
if(e_rxdv == 1'b1)begin
if(state_counter<5'd7)begin
myUDP_layer <= {myUDP_layer[55:0],datain[7:0]};
state_counter <= state_counter + 1'b1;
end else begin
UDP_layer <= {myUDP_layer[55:0],datain[7:0]};
// UDP长度
rx_data_length <= myUDP_layer[23:8];
state_counter <= 5'd0;
rx_state <= rx_data;
end
end else
rx_state <= idle;
end
// 接收UDP数据
rx_data: begin
if(e_rxdv == 1'b1)begin
// 保存最后一个数据,UDP数据总长度 = -8字节的UDP头
if(data_counter == rx_data_length-9)begin
data_counter <= 0;
rx_state <= rx_finish;
ram_wr_addr <= ram_wr_addr + 1'b1;
// 写入RAM
data_o_valid <= 1'b1;
if(byte_counter == 3'd3)begin
data_o <= {mydata[23:0],datain[7:0]};
byte_counter <= 0;
// 不足32位时填充0
end else if(byte_counter == 3'd2)begin
data_o <= {mydata[15:0],datain[7:0],8'h00};
byte_counter <= 0;
// 不足32位时填充0
end else if(byte_counter == 3'd1)begin
data_o <= {mydata[7:0],datain[7:0],16'h0000};
byte_counter <= 0;
// 不足32位时填充0
end else if(byte_counter == 3'd0)begin
data_o <= {datain[7:0],24'h000000};
byte_counter <= 0;
end
end else begin
data_counter <= data_counter + 1'b1;
if(byte_counter<3'd3)begin
mydata <= {mydata[23:0],datain[7:0]};
byte_counter <= byte_counter + 1'b1;
data_o_valid <= 1'b0;
end else begin
data_o <= {mydata[23:0],datain[7:0]};
byte_counter <= 3'd0;
data_o_valid <= 1'b1;
ram_wr_addr <= ram_wr_addr + 1'b1;
end
end
end else
rx_state <= idle;
end
rx_finish: begin
data_o_valid <= 1'b0;
data_receive <= 1'b1;
rx_state <= idle;
end
default: rx_state <= idle;
endcase
end
end
endmodule数据发送模块
timescale 1ns / 1ps // 设置时钟精度为1ns/1ps
module ipsend(
input clk, // 输入时钟信号
output reg txen, // 输出发送使能信号
output reg txer, // 输出发送错误信号
output reg [7 : 0] dataout, // 输出数据位,8位宽
input [31 : 0] crc, // 输入CRC数据,32位宽
input [31 : 0] datain, // 输入数据,32位宽
output reg crcen, // 输出CRC使能信号
output reg crcre, // 输出CRC使能复位信号
output reg [3 : 0] tx_state, // 输出发送状态,4位宽
input [15 : 0] tx_data_length, // 输入数据长度,16位宽
input [15 : 0] tx_total_length, // 输入总长度,16位宽
output reg [8 : 0] ram_rd_addr // 输出RAM读地址,9位宽
);
reg [31 : 0] datain_reg; // 数据暂存寄存器
reg [31 : 0] ip_header [6 : 0]; // IP头信息
reg [7 : 0] preamble [7 : 0]; // 帧前导码
reg [7 : 0] mac_addr [13 : 0]; // MAC地址
reg [4 : 0] i, j; // 计数器
reg [31 : 0] check_buffer; // 校验缓冲器
reg [31 : 0] time_counter; // 时间计数器
reg [15 : 0] tx_data_counter; // 发送数据计数器
localparam idle = 4'b0000; // 空闲状态
localparam start = 4'b0001; // 启动状态
localparam make = 4'b0010; // 生成状态
localparam send55 = 4'b0011; // 发送55状态
localparam sendmac = 4'b0100; // 发送MAC地址状态
localparam sendheader = 4'b0101; // 发送IP头状态
localparam senddata = 4'b0110; // 发送数据状态
localparam sendcrc = 4'b0111; // 发送CRC状态
initial begin
tx_state <= idle; // 初始状态为空闲
// 设置帧前导码 7 x 55, 1 x d5
preamble[0] <= 8'h55;
preamble[1] <= 8'h55;
preamble[2] <= 8'h55;
preamble[3] <= 8'h55;
preamble[4] <= 8'h55;
preamble[5] <= 8'h55;
preamble[6] <= 8'h55;
preamble[7] <= 8'hD5;
//目标MAC地址 ff-ff-ff-ff-ff-ff
mac_addr[0] <= 8'hFF;
mac_addr[1] <= 8'hFF;
mac_addr[2] <= 8'hFF;
mac_addr[3] <= 8'hFF;
mac_addr[4] <= 8'hFF;
mac_addr[5] <= 8'hFF;
// 源MAC地址 01-60-6E-11-02-0F
mac_addr[6] <= 8'h01;
mac_addr[7] <= 8'h60;
mac_addr[8] <= 8'h6E;
mac_addr[9] <= 8'h11;
mac_addr[10] <= 8'h02;
mac_addr[11] <= 8'h0F;
// 0800: IP类型
mac_addr[12] <= 8'h08;
mac_addr[13] <= 8'h00;
i <= 0;
end
reg unsigned [16 : 0] temp_a; // 临时变量a
reg unsigned [16 : 0] temp_b; // 临时变量b
reg unsigned [16 : 0] temp_c; // 临时变量c
reg unsigned [16 : 0] temp_d; // 临时变量d
reg unsigned [16 : 0] temp_e; // 临时变量e
reg unsigned [17 : 0] temp_f; // 临时变量f
reg unsigned [17 : 0] temp_g; // 临时变量g
reg unsigned [18 : 0] temp_h; // 临时变量h
always @(negedge clk) begin
case(tx_state)
idle: begin
txer <= 1'b0; // 发送错误信号复位
txen <= 1'b0; // 发送使能信号复位
crcen <= 1'b0; // CRC使能信号复位
crcre <= 1; // CRC使能复位信号设为1
j <= 0; // 计数器j复位
dataout <= 8'h00; // 数据输出信号复位
ram_rd_addr <= 9'h01; // RAM读地址复位
tx_data_counter <= 0; // 发送数据计数器复位
// 经过一段时间后再发送
if(time_counter == 32'h04000000) begin
tx_state <= start; // 状态转换到start
time_counter <= 0; // 时间计数器复位
end else
time_counter <= time_counter + 1'b1; // 时间计数器递增
end
// IP头
start: begin
ip_header[0] <= {16'h4500,tx_total_length}; // 版本号4,头长度20,IP
ip_header[1][31:16] <= ip_header[1][31:16] + 1'b1; // 顺序号递增
ip_header[1][15:0] <= 16'h4000; // 分片偏移
ip_header[2] <= 32'h80110000; // 协议字段为17(UDP)
ip_header[3] <= {8'd192, 8'd168, 8'd1, 8'd183}; // 源IP地址,192.168.1.xx
ip_header[4] <= {8'd192, 8'd168, 8'd1, 8'd37}; // 目标IP地址,192.168.1.xx
ip_header[5] <= {16'd8080, 16'd8080}; // 端口号
ip_header[6] <= {tx_data_length,16'h0000}; // 数据长度
tx_state <= make; // 状态转换到make
end
// 计算校验和
make: begin
if(i == 0) begin
temp_a <= ip_header[0][15:0] + ip_header[0][31:16];
temp_b <= ip_header[1][15:0] + ip_header[1][31:16];
temp_c <= ip_header[2][15:0] + ip_header[2][31:16];
temp_d <= ip_header[3][15:0] + ip_header[3][31:16];
temp_e <= ip_header[4][15:0] + ip_header[4][31:16];
i <= i + 1'b1;
end else if(i == 1) begin
temp_f <= temp_a + temp_b;
temp_g <= temp_c + temp_d;
i <= i + 1'b1;
end else if(i == 2) begin
temp_h <= temp_f + temp_g;
i <= i + 1'b1;
end else if(i == 3) begin
check_buffer <= temp_h + temp_e;
i <= i + 1'b1;
end else if(i == 4) begin
check_buffer[15:0] <= check_buffer[31:16] + check_buffer[15:0];
i <= i + 1'b1;
end else begin
// 校验和
ip_header[2][15:0] <= ~check_buffer[15:0];
i <= 0;
tx_state <= send55;
end
end
// 发送7个55和1个d5
send55: begin
txen <= 1'b1; // GMII发送数据有效
crcre <= 1'b1; // 复位CRC
if(i == 7) begin
dataout[7:0] <= preamble[i][7:0];
i <= 0;
tx_state <= sendmac;
end else begin
dataout[7:0] <= preamble[i][7:0];
i <= i + 1;
end
end
// 发送目标MAC地址、源MAC地址和IP类型
sendmac: begin
// 启用CRC,计算32位的CRC
crcen <= 1'b1;
crcre <= 1'b0;
if(i == 13) begin
dataout[7:0] <= mac_addr[i][7:0];
i <= 0;
tx_state <= sendheader;
end else begin
dataout[7:0] <= mac_addr[i][7:0];
i <= i + 1'b1;
end
end
// 发送7个32位的IP头
sendheader: begin
// 发送数据
datain_reg <= datain;
if(j == 6) begin
if(i == 0) begin
dataout[7:0] <= ip_header[j][31:24];
i <= i + 1'b1;
end else if(i == 1) begin
dataout[7:0] <= ip_header[j][23:16];
i <= i + 1'b1;
end else if(i == 2) begin
dataout[7:0] <= ip_header[j][15:8];
i <= i + 1'b1;
end else if(i == 3) begin
dataout[7:0] <= ip_header[j][7:0];
i <= 0;
j <= 0;
tx_state <= senddata;
end else
txer <= 1'b1;
end else begin
if(i == 0) begin
dataout[7:0] <= ip_header[j][31:24];
i <= i + 1'b1;
end else if(i == 1) begin
dataout[7:0] <= ip_header[j][23:16];
i <= i + 1'b1;
end else if(i == 2) begin
dataout[7:0] <= ip_header[j][15:8];
i <= i + 1'b1;
end else if(i == 3) begin
dataout[7:0] <= ip_header[j][7:0];
i <= 0;
j <= j + 1'b1;
end else
txer <= 1'b1;
end
end
// 发送UDP数据
senddata: begin
// 发送最后一个数据
if(tx_data_counter == tx_data_length-9) begin
tx_state <= sendcrc;
if(i == 0) begin
dataout[7:0] <= datain_reg[31:24];
i <= 0;
end else if(i == 1) begin
dataout[7:0] <= datain_reg[23:16];
i <= 0;
end else if(i == 2) begin
dataout[7:0] <= datain_reg[15:8];
i <= 0;
end else if(i == 3) begin
dataout[7:0] <= datain_reg[7:0];
// 准备新的数据
datain_reg <= datain;
i <= 0;
end
// 发送其他数据
end else begin
tx_data_counter <= tx_data_counter + 1'b1;
if(i == 0) begin
dataout[7:0] <= datain_reg[31:24];
i <= i + 1'b1;
// RAM + 1,RAM读数据
ram_rd_addr <= ram_rd_addr + 1'b1;
end else if(i == 1) begin
dataout[7:0] <= datain_reg[23:16];
i <= i + 1'b1;
end else if(i == 2) begin
dataout[7:0] <= datain_reg[15:8];
i <= i + 1'b1;
end else if(i == 3) begin
dataout[7:0] <= datain_reg[7:0];
// 准备新的数据
datain_reg <= datain;
i <= 0;
end
end
end
// 发送32位的CRC
sendcrc: begin
crcen <= 1'b0;
if(i == 0) begin
dataout[7:0] <= {~crc[24], ~crc[25], ~crc[26], ~crc[27], ~crc[28], ~crc[29], ~crc[30], ~crc[31]};
i <= i + 1'b1;
end else begin
if(i == 1) begin
dataout[7:0] <= {~crc[16], ~crc[17], ~crc[18], ~crc[19], ~crc[20], ~crc[21], ~crc[22], ~crc[23]};
i <= i + 1'b1;
end else if(i == 2) begin
dataout[7:0] <= {~crc[8], ~crc[9], ~crc[10], ~crc[11], ~crc[12], ~crc[13], ~crc[14], ~crc[15]};
i <= i + 1'b1;
end else if(i == 3) begin
dataout[7:0] <= {~crc[0], ~crc[1], ~crc[2], ~crc[3], ~crc[4], ~crc[5], ~crc[6], ~crc[7]};
i <= 0;
tx_state <= idle;
end else begin
txer <= 1'b1;
end
end
end
default:tx_state <= idle;
endcase
end
endmoduleCRC校验模块(没啥好说的,就是CRC)
timescale 1ns / 1ps
// CRC Module Definition
module crc(
input Clk, // Clock input
input Reset, // Reset input
input [7 : 0] Data_in, // Data input
input Enable, // Enable input
output reg [31 : 0] Crc, // CRC output
output [31 : 0] CrcNext // Next CRC output
);
wire [7 : 0] Data;
assign Data = {Data_in[0],Data_in[1],Data_in[2],Data_in[3],Data_in[4],Data_in[5],Data_in[6],Data_in[7]};
// CRC Calculation
assign CrcNext[0] = Crc[24] ^ Crc[30] ^ Data[0] ^ Data[6];
assign CrcNext[1] = Crc[24] ^ Crc[25] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[6] ^ Data[7];
assign CrcNext[2] = Crc[24] ^ Crc[25] ^ Crc[26] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[2] ^ Data[6] ^ Data[7];
assign CrcNext[3] = Crc[25] ^ Crc[26] ^ Crc[27] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[7];
assign CrcNext[4] = Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[6];
assign CrcNext[5] = Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[6] ^ Data[7];
assign CrcNext[6] = Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5] ^ Data[6] ^ Data[7];
assign CrcNext[7] = Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Crc[31] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[5] ^ Data[7];
assign CrcNext[8] = Crc[0] ^ Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4];
assign CrcNext[9] = Crc[1] ^ Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5];
assign CrcNext[10] = Crc[2] ^ Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[5];
assign CrcNext[11] = Crc[3] ^ Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4];
assign CrcNext[12] = Crc[4] ^ Crc[24] ^ Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Data[0] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5] ^ Data[6];
assign CrcNext[13] = Crc[5] ^ Crc[25] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[5] ^ Data[6] ^ Data[7];
assign CrcNext[14] = Crc[6] ^ Crc[26] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Crc[31] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[6] ^ Data[7];
assign CrcNext[15] = Crc[7] ^ Crc[27] ^ Crc[28] ^ Crc[29] ^ Crc[31] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[7];
assign CrcNext[16] = Crc[8] ^ Crc[24] ^ Crc[28] ^ Crc[29] ^ Data[0] ^ Data[4] ^ Data[5];
assign CrcNext[17] = Crc[9] ^ Crc[25] ^ Crc[29] ^ Crc[30] ^ Data[1] ^ Data[5] ^ Data[6];
assign CrcNext[18] = Crc[10] ^ Crc[26] ^ Crc[30] ^ Crc[31] ^ Data[2] ^ Data[6] ^ Data[7];
assign CrcNext[19] = Crc[11] ^ Crc[27] ^ Crc[31] ^ Data[3] ^ Data[7];
assign CrcNext[20] = Crc[12] ^ Crc[28] ^ Data[4];
assign CrcNext[21] = Crc[13] ^ Crc[29] ^ Data[5];
assign CrcNext[22] = Crc[14] ^ Crc[24] ^ Data[0];
assign CrcNext[23] = Crc[15] ^ Crc[24] ^ Crc[25] ^ Crc[30] ^ Data[0] ^ Data[1] ^ Data[6];
assign CrcNext[24] = Crc[16] ^ Crc[25] ^ Crc[26] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[7];
assign CrcNext[25] = Crc[17] ^ Crc[26] ^ Crc[27] ^ Data[2] ^ Data[3];
assign CrcNext[26] = Crc[18] ^ Crc[24] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Data[0] ^ Data[3] ^ Data[4] ^ Data[6];
assign CrcNext[27] = Crc[19] ^ Crc[25] ^ Crc[28] ^ Crc[29] ^ Crc[31] ^ Data[1] ^ Data[4] ^ Data[5] ^ Data[7];
assign CrcNext[28] = Crc[20] ^ Crc[26] ^ Crc[29] ^ Crc[30] ^ Data[2] ^ Data[5] ^ Data[6];
assign CrcNext[29] = Crc[21] ^ Crc[27] ^ Crc[30] ^ Crc[31] ^ Data[3] ^ Data[6] ^ Data[7];
assign CrcNext[30] = Crc[22] ^ Crc[28] ^ Crc[31] ^ Data[4] ^ Data[7];
assign CrcNext[31] = Crc[23] ^ Crc[29] ^ Data[5];
// Sequential Logic
always@(posedge Clk or posedge Reset)begin
if (Reset)begin
Crc <= {32{1'b1}}; // Reset CRC to all ones
end else if (Enable)begin
Crc <= CrcNext; // Update CRC with next CRC value
end
end
endmodule资源占用情况




