当前位置:   article > 正文

FPGA千兆以太网UDP收发状态机实现_fpga千兆以太网通信

fpga千兆以太网通信

一.UDP发送模块

1.1模块框图

在这里插入图片描述
接口描述
//输入接口:
gmii_clk:发送时钟。
sys_rst_n:系统复位。
send_en:发送使能。
send_data:发送的数据,位宽为32位。
send_data_num:发送数据的字节数,单位是byte。
crc_data/crc_next:crc检验数据。
//输出接口
send_end:发送结束使能。
read_data_req:fifo读数据请求。
eth_tx_en:发送字节数据有效信号。
eth_tx_data:发送的数据,单位是字节。
crc_en/crc_clr:crc使能和清空信号。

1.2.波形图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3逻辑实现思路

开始状态是空闲状态;当trig_tx_en信号为高电平时,进入CHECK_SUM状态,在这个状态进行IP_UDP校验,当计数器cnt计数到3的时候,跳转到下一个状态,PACKET_HEAD,在这这个状态下进行以太网帧头的发送。由于发送的帧头为七个8‘h55加一个8’hd5,所以计数器计数到7时,跳转到下一个状态EHT_HEAD,在这个状态下,发送的数据为目的地址(6个个字节),源地址(6个字节),加两个字节的ETH类型。所以计数到13时跳转到下一个IP_UDP_HEAD状态。在IP_UDP_HEAD状态下,发送IP_UDP头部,以4个字节为单位,一个7个四个字节,所以帧计数器frame_cnt计数到6,这时候跳转到SEND_DATA状态,在这个状态下,data_cnt为实际发送数据的计数值,又设置变量send_data_len,此变量为实际要发送的数据值,值得注意的是,又上一篇博客可知,以太网数据发送部分最低为46个字节,而IP_UDP头部数据就占用了28个字节,所以带发送的数据最少为18个字节,为了满足实际情况的合理性,故考虑实际发送的数据少于18个字节的情况,设置add_cnt变量,此变量为少于18个最小字节的,待补充字节的个数。当add_cnt和data_cnt两者相加的值等于send_data_len-1时,状态跳转到CRC状态,在此状态接受四个字节的crc校验数据,cnt等于3时,跳转到IDLE状态,至此一帧的以太网数据发送完成。

1.4 发送状态机代码


//时序逻辑表示状态寄存

always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        current_state <= IDLE;
    else 
        current_state <= next_state;
end
//组合逻辑表示状态转移
always @(*) begin
    case(current_state)
        IDLE:begin
            if(sw_en)
                next_state = CHECK_SUM;
            else 
                next_state = IDLE;
        end
        CHECK_SUM:begin
            if(sw_en)
                next_state = PACKET_HEAD;
            else 
                next_state = CHECK_SUM;
        end
        PACKET_HEAD:begin
            if(sw_en)
                next_state = ETH_HEAD;
            else 
                next_state = PACKET_HEAD;
        end
        ETH_HEAD:begin
            if(sw_en)
                next_state = IP_UDP_HEAD;
            else 
                next_state = ETH_HEAD;        
        end
        IP_UDP_HEAD:begin
            if(sw_en)
                next_state = SEND_DATA;
            else 
                next_state = IP_UDP_HEAD;   
        end
        SEND_DATA:begin
            if(sw_en)
                next_state = CRC;
            else 
                next_state = SEND_DATA;        
        end 
        CRC:begin
            if(sw_en)
                next_state = IDLE;
            else 
                next_state = CRC;           
        end
        default: next_state = IDLE;
    endcase
end
//时序逻辑表示状态输出
//send_end
always @(posedge gmii_clk or negedge sys_rst_n ) begin
    if(!sys_rst_n)
        send_end<='d0;
    else if(next_state == CRC &&cnt == 'd3) 
        send_end<='d1;
    else 
        send_end<='d0;
end
//read_data_req
always @(posedge gmii_clk or negedge sys_rst_n ) begin
    if(!sys_rst_n)
        read_data_req <= 'd0;
    else if(next_state == IP_UDP_HEAD &&cnt == 'd2&&frame_cnt =='d6)
        read_data_req <= 'd1;
    else if(next_state == SEND_DATA &&cnt_send_state == 'd2&&(data_cnt!=data_len-'d1))
        read_data_req <= 'd1;
    else 
        read_data_req <= 'd0;
end
//eth_tx_en
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        eth_tx_en <= 1'b0;
    else if(next_state != IDLE && next_state != CHECK_SUM)
        eth_tx_en <= 1'b1;
    else 
        eth_tx_en <= 1'b0;
end
//eth_tx_data
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        eth_tx_data <= 'd0;
    else if(next_state == PACKET_HEAD)
            eth_tx_data <= packet_head[cnt];
    else if(next_state == ETH_HEAD)
            eth_tx_data <= eth_head[cnt];
    else if(next_state == IP_UDP_HEAD) begin
        case(cnt)
            0:eth_tx_data <= ip_udp_head[frame_cnt][31:24];
            1:eth_tx_data <= ip_udp_head[frame_cnt][23:16];
            2:eth_tx_data <= ip_udp_head[frame_cnt][15:8];
            3:eth_tx_data <= ip_udp_head[frame_cnt][7:0];
            default:eth_tx_data <= eth_tx_data;
        endcase 
    end
    else if(next_state == SEND_DATA ) begin
        case(cnt_send_state)
            0:eth_tx_data <= send_data[31:24];
            1:eth_tx_data <= send_data[23:16];
            2:eth_tx_data <= send_data[15:8];
            3:eth_tx_data <= send_data[7:0];
            default:eth_tx_data <= eth_tx_data;
        endcase
    end
    else if(next_state == CRC) begin
        case(cnt)
            0:eth_tx_data <= {~crc_next[0],~crc_next[1],~crc_next[2],~crc_next[3],~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};
            1:eth_tx_data <= {~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19],~crc_data[20], ~crc_data[21], ~crc_data[22],~crc_data[23]};
                             
            2:eth_tx_data <= {~crc_data[8], ~crc_data[9], ~crc_data[10],~crc_data[11],~crc_data[12], ~crc_data[13], ~crc_data[14],~crc_data[15]};
                              
            3:eth_tx_data <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};

            default:eth_tx_data <= eth_tx_data;
        endcase 
    end
    else 
        eth_tx_data <= eth_tx_data;
end
//crc_en
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        crc_en <= 'd0;
    else if(next_state == ETH_HEAD||next_state == IP_UDP_HEAD || next_state == SEND_DATA)
        crc_en <= 'd1;
    else 
        crc_en <= 'd0;
end
//crc_clr   
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        crc_clr <= 'd0;
    else 
        crc_clr <= send_end;

end

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146

1.5.仿真波形图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二.UDP接受模块

2.1 模块框图

在这里插入图片描述
#输入接口
gmii_clk:接受时钟。
sys_rst_n:系统复位。
gmii_rxdv:接受使能。
gmii_rx_data:接受数据,单位是字节。
#输出接口
rec_data_en:数据有效使能。
rec_data:接受的数据。
rec_end:接受完成标志。
rec_data_num:接受数据的个数。

2.2.波形图

在这里插入图片描述
在这里插入图片描述

2.3逻辑实现思路

首先将输入的rxdv和rx_data数据同步在时钟沿下,在开始状态时,当gmii_rxdv_reg和gmii_rx_data分别为高电平和8‘h55时,进入PACK_HEAD状态,当cnt计数到6且此时的数据是8’hd5时,进入下一个状态ETH_HEAD状态,在这个状态下,要接受目的mac地址,源mac地址,和eth类型,将目的mac地址寄存在des_mac变量中,当des_mac和输入的目的地址相同时,拉高mac_flag信号,同时当cnt等于13的条件下,进入IP_HEAD状态,在此状态下,将目的ip号寄存在des-ip变量下,当des_ip和输入的目的ip相同时,拉高ip_flag信号,同时当cnt等于19的时候,进入UDP_HEAD状态,在此状态下,当cnt计数到7的时候,进入REC_DATA状态,当data_cnt等于dala_len时,进入REC_END状态,当gmii_rxdv_reg为低时,进入IDLE状态。以此循环。

2.4 接受状态机代码

//时序逻辑表示状态寄存
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        current_state <= IDLE;
    else 
        current_state <= next_state;
end
//组合逻辑表示状态转移
always @(*) begin
    next_state = IDLE;
    case(current_state)
        IDLE:begin
            if(sw_en)
                next_state = PACKET_HEAD;
            else 
                next_state = IDLE;
        end
        PACKET_HEAD:begin
            if(sw_en)
                next_state = ETH_HEAD;
            else 
                next_state = PACKET_HEAD;
        end
        ETH_HEAD:begin
            if(sw_en)
                next_state = IP_HEAD;
            else 
                next_state = ETH_HEAD;
        end
        IP_HEAD:begin
            if(sw_en)
                next_state = UDP_HEAD;
            else 
                next_state = IP_HEAD;        
        end
        UDP_HEAD:begin
            if(sw_en)
                next_state = REC_DATA;
            else 
                next_state = UDP_HEAD;   
        end
        REC_DATA:begin
            if(sw_en)
                next_state = REC_END;
            else 
                next_state = REC_DATA;        
        end 
        REC_END:begin
            if(sw_en)
                next_state = IDLE;
            else 
                next_state = REC_END;           
        end
    endcase
end
//时序逻辑表示状态输出
//rec_data_en
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rec_data_en <= 'd0;
    else if(next_state == REC_DATA && cnt_rec_data == 'd3)
        rec_data_en <= 'd1;
    else 
        rec_data_en <= 'd0;
end
//rec_data
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rec_data <= 'd0;
    else if(next_state == REC_DATA && cnt_rec_data <= 'd3)
        rec_data <= {rec_data[23:0],gmii_rx_data_reg};
end
//rec_end
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rec_end <= 'd0;
    else if(next_state == REC_DATA && (cnt_data ==data_len-'d1))
        rec_end <= 'd1;
    else 
        rec_end <= 'd0;
end
//rec_data_num
always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rec_data_num <= 'd0;
    else if(next_state == REC_DATA && (cnt_data ==data_len-'d1))
        rec_data_num <= data_len;
end

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

2.5 仿真波形

在这里插入图片描述
仿真整体波形
在这里插入图片描述
仿真局部波形
在这里插入图片描述

三.rgmii接口和gmii接口

3.1rgmii_to_gmii

在这里插入图片描述
模块框图
在这里插入图片描述
波形图
注:双沿采样边成单沿采样,同步到clk时钟的上升沿。

3.2gmii_to_rgmii

在这里插入图片描述
模块框图
在这里插入图片描述
波形图
注:单沿采样同步到双沿采样。
总结:千早以太网就到这里了,以后有机会更新ddr或者万兆以太网。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/984850
推荐阅读
相关标签
  

闽ICP备14008679号