`timescale 1ns/1ns
////////////////////////////////////////////////////////////////////////
// Author : EmbedFire
// 实验平台: 野火FPGA系列开发板
// 公司 : http://www.embedfire.com
// 论坛 : http://www.firebbs.cn
// 淘宝 : https://fire-stm32.taobao.com
////////////////////////////////////////////////////////////////////////module udp_rx(input clk , //时钟信号input rst_n , //复位信号,低电平有效input gmii_rx_dv , //GMII输入数据有效信号input [7:0] gmii_rxd , //GMII输入数据output reg rec_pkt_done, //以太网单包数据接收完成信号output reg rec_en , //以太网接收的数据使能信号output reg [31:0] rec_data , //以太网接收的数据output reg [15:0] rec_byte_num //以太网接收的有效字数 单位:byte);//parameter define
//开发板MAC地址
parameter BOARD_MAC = 48'hff_ff_ff_ff_ff_ff;
//开发板IP地址
parameter BOARD_IP = {8'd0,8'd0,8'd0,8'd0};localparam st_idle = 7'b000_0001; //初始状态,等待接收前导码
localparam st_preamble = 7'b000_0010; //接收前导码状态
localparam st_eth_head = 7'b000_0100; //接收以太网帧头
localparam st_ip_head = 7'b000_1000; //接收IP首部
localparam st_udp_head = 7'b001_0000; //接收UDP首部
localparam st_rx_data = 7'b010_0000; //接收有效数据
localparam st_rx_end = 7'b100_0000; //接收结束localparam ETH_TYPE = 16'h0800 ; //以太网协议类型 IP协议//reg define
reg [6:0] cur_state ;
reg [6:0] next_state ;reg skip_en ; //控制状态跳转使能信号
reg error_en ; //解析错误使能信号
reg [4:0] cnt ; //解析数据计数器
reg [47:0] des_mac ; //目的MAC地址
reg [15:0] eth_type ; //以太网类型
reg [31:0] des_ip ; //目的IP地址
reg [5:0] ip_head_byte_num; //IP首部长度
reg [15:0] udp_byte_num ; //UDP长度
reg [15:0] data_byte_num ; //数据长度
reg [15:0] data_cnt ; //有效数据计数
reg [1:0] rec_en_cnt ; //8bit转32bit计数器//*****************************************************
//** main code
//*****************************************************//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle;elsecur_state <= next_state;
end//组合逻辑判断状态转移条件
always @(*) beginnext_state = st_idle;case(cur_state)st_idle : begin //等待接收前导码if(skip_en)next_state = st_preamble;elsenext_state = st_idle;endst_preamble : begin //接收前导码if(skip_en)next_state = st_eth_head;else if(error_en)next_state = st_rx_end;elsenext_state = st_preamble;endst_eth_head : begin //接收以太网帧头if(skip_en)next_state = st_ip_head;else if(error_en)next_state = st_rx_end;elsenext_state = st_eth_head;endst_ip_head : begin //接收IP首部if(skip_en)next_state = st_udp_head;else if(error_en)next_state = st_rx_end;elsenext_state = st_ip_head;endst_udp_head : begin //接收UDP首部if(skip_en)next_state = st_rx_data;elsenext_state = st_udp_head;endst_rx_data : begin //接收有效数据if(skip_en)next_state = st_rx_end;elsenext_state = st_rx_data;endst_rx_end : begin //接收结束if(skip_en)next_state = st_idle;elsenext_state = st_rx_end;enddefault : next_state = st_idle;endcase
end//时序电路描述状态输出,解析以太网数据
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac <= 48'd0;eth_type <= 16'd0;des_ip <= 32'd0;ip_head_byte_num <= 6'd0;udp_byte_num <= 16'd0;data_byte_num <= 16'd0;data_cnt <= 16'd0;rec_en_cnt <= 2'd0;rec_en <= 1'b0;rec_data <= 32'd0;rec_pkt_done <= 1'b0;rec_byte_num <= 16'd0;endelse beginskip_en <= 1'b0;error_en <= 1'b0;rec_en <= 1'b0;rec_pkt_done <= 1'b0;case(next_state)st_idle : beginif((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55))skip_en <= 1'b1;endst_preamble : beginif(gmii_rx_dv) begin //解析前导码cnt <= cnt + 5'd1;if((cnt < 5'd6) && (gmii_rxd != 8'h55)) //7个8'h55error_en <= 1'b1;else if(cnt==5'd6) begincnt <= 5'd0;if(gmii_rxd==8'hd5) //1个8'hd5skip_en <= 1'b1;elseerror_en <= 1'b1;endendendst_eth_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'b1;if(cnt < 5'd6)des_mac <= {des_mac[39:0],gmii_rxd}; //目的MAC地址else if(cnt == 5'd12)eth_type[15:8] <= gmii_rxd; //以太网协议类型else if(cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;//判断MAC地址是否为开发板MAC地址或者公共地址if(((des_mac == BOARD_MAC) ||(des_mac == 48'hff_ff_ff_ff_ff_ff))&& eth_type[15:8] == ETH_TYPE[15:8] && gmii_rxd == ETH_TYPE[7:0])skip_en <= 1'b1;elseerror_en <= 1'b1;endendendst_ip_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'd1;if(cnt == 5'd0)ip_head_byte_num <= {gmii_rxd[3:0],2'd0};else if((cnt >= 5'd16) && (cnt <= 5'd18))des_ip <= {des_ip[23:0],gmii_rxd}; //目的IP地址else if(cnt == 5'd19) begindes_ip <= {des_ip[23:0],gmii_rxd};//判断IP地址是否为开发板IP地址if((des_ip[23:0] == BOARD_IP[31:8])&& (gmii_rxd == BOARD_IP[7:0])) beginif(cnt == ip_head_byte_num - 1'b1) beginskip_en <=1'b1;cnt <= 5'd0;endendelse begin//IP错误,停止解析数据error_en <= 1'b1;cnt <= 5'd0;endendelse if(cnt == ip_head_byte_num - 1'b1) beginskip_en <=1'b1; //IP首部解析完成cnt <= 5'd0;endendendst_udp_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'd1;if(cnt == 5'd4)udp_byte_num[15:8] <= gmii_rxd; //解析UDP字节长度else if(cnt == 5'd5)udp_byte_num[7:0] <= gmii_rxd;else if(cnt == 5'd7) begin//有效数据字节长度,(UDP首部8个字节,所以减去8)data_byte_num <= udp_byte_num - 16'd8;skip_en <= 1'b1;cnt <= 5'd0;endendendst_rx_data : begin//接收数据,转换成32bitif(gmii_rx_dv) begindata_cnt <= data_cnt + 16'd1;rec_en_cnt <= rec_en_cnt + 2'd1;if(data_cnt == data_byte_num - 16'd1) beginskip_en <= 1'b1; //有效数据接收完成data_cnt <= 16'd0;rec_en_cnt <= 2'd0;rec_pkt_done <= 1'b1;rec_en <= 1'b1;rec_byte_num <= data_byte_num;end//先收到的数据放在了rec_data的高位,所以当数据不是4的倍数时,//低位数据为无效数据,可根据有效字节数来判断(rec_byte_num)if(rec_en_cnt == 2'd0)rec_data[31:24] <= gmii_rxd;else if(rec_en_cnt == 2'd1)rec_data[23:16] <= gmii_rxd;else if(rec_en_cnt == 2'd2)rec_data[15:8] <= gmii_rxd;else if(rec_en_cnt==2'd3) beginrec_en <= 1'b1;rec_data[7:0] <= gmii_rxd;endendendst_rx_end : begin //单包数据接收完成if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)skip_en <= 1'b1;enddefault : ;endcaseend
endendmodule
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态