FPGA——以太网MAC层数据发送协议实现及验证

更新时间:2023-05-18 19:34:39 阅读: 评论:0

FPGA——以太⽹MAC层数据发送协议实现及验证
⼀、设计思路
FPGA实现MAC层(数据链路层)的功能并连接到RTL8211物理层(PHY)芯⽚实现以太⽹数据的发送
使⽤GMII接⼝时钟是125MHz,⼀次发8bit数据 8bit * 125M = 1000Mbit 所以叫做千兆以太⽹
RTL8211时序来⼀个时钟上升沿就发⼀个字节的数据
数据链路层(MAC帧协议)发送过程
前同步码 0x55,发七次
帧开始符 0xD5
⽬的MAC地址(6字节)
源MAC地址(6字节)
类型:0x800 使⽤IP上层协议,代表下⾯发送的数据是IP数据报
数据
IP报⽂⾸部
IP版本 0x4 IPv4
⾸部长度
服务类型
总长度
分段标识
保留位
DF
市民公园MF
段偏移
⽣存周期TTL
上层协议 0x11 UDP
报⽂校验和
源IP地址
⽬的IP地址
可选字段(0字节不需要)
IP报⽂数据(UDP报⽂)
中国抗日战争UDP报⽂⾸部
16位源端⼝号
16位⽬的端⼝号
16位UDP长度
16位UDP校验和(可以直接置0)
UDP报⽂数据
CRC校验
IP报⽂校验和将IP报⽂⾸部,从前到后拼成⼀个⼀个的2字节的数据相加(其中报⽂校验和置0)然后将所加的32bit数据的⾼16位于低16位相加,直到⾼16bit为0 将16bit取反,则为校验和
虽然⽣成了函数,但是具体使⽤函数还是要做更改的注意:CRC校验是从发送⽬的MAC地址开始校验的
IP⾸部长度单位是/32bit(4字节) 如果没有可选⾃动,⾸部长度就是 5(⾏)
IP总长度总长度 = IP⾸部长度 + IP报⽂数据长度单位是/字节
MAC帧协议的数据和填充数据和填充那个位置,⾄少要46个字节,如果要发送的UDP报⽂数据加起来没有46字节的话,就要在后⾯填0x00直到有46个字节为⽌ IP报⽂头部(20字节)+ UDP报⽂(8字节)+ 发送的数据 >= 46 发送的数据 >= 18字节
FPGA状态机实现每⼀个状态都配套⼀个计数器
⼆、以太⽹GMIII发送代码实现
module eth_udp_tx_gmii(
clk      ,
rst_n    ,
tx_en    ,
tx_done  ,
dst_mac  ,
src_mac  ,
dst_ip  ,
src_ip  ,
dst_port ,
gmii_clk ,
data_len ,
data_vld ,
gmii_en  ,
gmii_tx  ,
data_in
);
localparam MAC_W          =  48;
localparam IP_W            =  32;
localparam PORT_W          =  16;
localparam DATA_LEN_W      =  16;
localparam GMII_W          =  8;
localparam PREAMBLE        =  8'h55;  //前导码
localparam SFD            =  8'hD5;  //帧开始符
localparam ETH_TYPE        =  16'h0800;//上层协议类型,IP协议localparam IP_VER          =  4'h4;    //IPV4
localparam IP_HDR_LEN      =  4'h5;    //⾸部长度有5个32bit localparam IP_TOS          =  8'h00;  //服务类型,未⽤
localparam IP_HED_LEN      =  20;      //IP头部长度
localparam UDP_HED_LEN    =  8;      //UDP头部长度localparam IP_ID          =  16'h0000;//分段标识
localparam IP_RSV          =  1'b0;    //保留
localparam IP_DF          =  1'b0;    //是否分段
localparam IP_MF          =  1'b0;    //是否有后续分段
localparam IP_FRAG_OFFSET  =  13'h0;  //段偏移(以8字节为单位)localparam IP_TTL          =  8'h40;  //⽣存周期,能经过40个路由器localparam IP_PROTOCOL    =  8'h11;  //上层协议(UDP)localparam MIN_DATA        =  46;      //UDP数据最⼩长度localparam DATA_W          =  8;
//状态机参数
localparam IDLE            =  7'b0000001;
localparam TX_ETH_HED      =  7'b0000010;
localparam TX_IP_HED      =  7'b0000100;
localparam TX_UDP_HED      =  7'b0001000;
localparam TX_UDP_DATA    =  7'b0010000;
localparam TX_FILL_DATA    =  7'b0100000;
localparam TX_CRC          =  7'b1000000;
localparam STATE_W        =  7;
//计数器参数
localparam ETH_HED_W      =  5;
localparam ETH_HED_N      =  22;
localparam IP_HED_W        =  5;
localparam IP_HED_N        =  20;
localparam UDP_HED_N      =  8;
localparam UDP_HED_W      =  4;
localparam CNT_DATA_W      =  11;
localparam FILL_W          =  6;
理智与情感读后感
localparam CNT_CRC_W      =  3;
localparam CNT_CRC_N      =  4;
/
/模块参数
localparam CHEC_W          =  16;
localparam CRC_OUT_W      =  32;
input                      clk;
input                      rst_n;
input                      tx_en;      //发送使能
input    [MAC_W-1:0]      dst_mac;    //⽬的Mac地址
input    [MAC_W-1:0]      src_mac;    //源Mac地址
input    [IP_W-1:0]        dst_ip;    //⽬的ip地址
input    [IP_W-1:0]        src_ip;    //源ip地址
input    [PORT_W-1:0]      dst_port;  //⽬的端⼝
input    [PORT_W-1:0]      src_port;  //源端⼝
input    [DATA_LEN_W-1:0]  data_len;  //发送数据长度
input    [DATA_W-1:0]      data_in;    //输⼊数据
output                    gmii_clk;  //以太⽹接⼝时钟
output                    gmii_en;  //以太⽹使能
output  [GMII_W-1:0]      gmii_tx;  //以太⽹数据
output                    tx_done;  //发送完成
output                    data_vld;  //数据有效标志信号
wire                      gmii_clk;  //以太⽹接⼝时钟
reg                        gmii_en;  //以太⽹使能
reg      [GMII_W-1:0]      gmii_tx;  //以太⽹数据
reg                        tx_done;  //发送完成
reg                        data_vld;  //数据有效标志信号
reg      [STATE_W-1:0]    state_c;
reg      [STATE_W-1:0]    state_n;
wire                      idle2tx_eth_hed;
wire                      tx_eth_hed2tx_ip_hed;
wire                      tx_ip_hed2tx_udp_hed;
wire                      tx_udp_hed2tx_udp_data;
wire                      tx_udp_data2tx_fill_data;
wire                      tx_udp_data2tx_crc;
wire                      tx_fill_data2tx_crc;
wire                      tx_crc2idle;
//计数器变量
reg      [ETH_HED_W-1:0]  cnt_eth_hed;
wire                      add_cnt_eht_hed;
wire                      end_cnt_eth_hed;
reg      [IP_HED_W-1:0]    cnt_ip_hed;
wire                      add_cnt_ip_hed;
wire                      end_cnt_ip_hed;
reg      [UDP_HED_W-1:0]  cnt_udp_hed;
天狗望月写话wire                      add_cnt_udp_hed;
wire                      end_cnt_udp_hed;
reg      [CNT_DATA_W-1:0]  cnt_data;
wire                      add_cnt_data;
wire                      end_cnt_data;
reg      [FILL_W-1:0]      cnt_fill;
wire                      add_cnt_fill;
wire                      end_cnt_fill;
reg      [CNT_CRC_W-1:0]  cnt_crc;
wire                      add_cnt_crc;
wire                      end_cnt_crc;
//中间变量
reg                        tx_flag;
reg      [MAC_W-1:0]      dst_mac_tmp;    //⽬的Mac地址reg      [MAC_W-1:0]      src_mac_tmp;    //源Mac地址reg      [IP_W-1:0]        dst_ip_tmp;    //⽬的ip地址
reg      [IP_W-1:0]        src_ip_tmp;    //源ip地址
reg      [PORT_W-1:0]      dst_port_tmp;  //⽬的端⼝
reg      [PORT_W-1:0]      src_port_tmp;  //源端⼝西塘旅游
reg      [DATA_LEN_W-1:0]  data_len_tmp;  //发送数据长度reg      [DATA_LEN_W-1:0]  ip_total_len;  //IP总长度
reg      [DATA_LEN_W-1:0]  udp_total_len;  //UDP总长度wire    [16-1:0]          udp_check_sum;  //UDP校验和
reg      [DATA_W-1:0]      data_out;      //以太⽹数据
reg                        tx_nocrc_flag;
//模块变量
wire    [CHEC_W-1:0]      check_sum;      //IP报头校验和reg                        sum_en;
reg                        crc_init;
reg                        crc_en;
wire    [CRC_OUT_W-1:0]  crc_out;
always @(podge clk or negedge rst_n)begin
if(!rst_n)
state_c <= IDLE;
el
state_c <= state_n;
end
always @(*)begin
ca(state_c)
IDLE:begin
if(idle2tx_eth_hed)
state_n = TX_ETH_HED;
el
state_n = state_c;
end
TX_ETH_HED:begin
if(tx_eth_hed2tx_ip_hed)
state_n = TX_IP_HED;
el
state_n = state_c;
end
TX_IP_HED:begin
if(tx_ip_hed2tx_udp_hed)
state_n = TX_UDP_HED;
state_n = state_c;
end
TX_UDP_HED:begin
if(tx_udp_hed2tx_udp_data)
state_n = TX_UDP_DATA;
el
state_n = state_c;
end
TX_UDP_DATA:begin
if(tx_udp_data2tx_fill_data)
state_n = TX_FILL_DATA;
el if(tx_udp_data2tx_crc)
state_n = TX_CRC;
el
state_n = state_c;
end
TX_FILL_DATA:begin
if(tx_fill_data2tx_crc)
state_n = TX_CRC;
el
state_n = state_c;
end
TX_CRC:begin
if(tx_crc2idle)
state_n = IDLE;
el
state_n = state_c;
end
default:state_n = IDLE;
endca
end
assign idle2tx_eth_hed          =  state_c == IDLE && tx_en;
assign tx_eth_hed2tx_ip_hed      =  state_c == TX_ETH_HED && end_cnt_eth_hed;
assign tx_ip_hed2tx_udp_hed      =  state_c == TX_IP_HED && end_cnt_ip_hed;
assign tx_udp_hed2tx_udp_data    =  state_c == TX_UDP_HED && end_cnt_udp_hed;
assign tx_udp_data2tx_fill_data  =  state_c == TX_UDP_DATA && end_cnt_data && (data_len_tmp > 0 && data_len_tmp < (MIN_DATA - IP_HED_LEN - UDP_HED_LEN)); assign tx_udp_data2tx_crc        =  state_c == TX_UDP_DATA && end_cnt_data && data_len_tmp >= (MIN_DATA - IP_HED_LEN - UDP_HED_LEN);
assign tx_fill_data2tx_crc      =  state_c == TX_FILL_DATA && end_cnt_fill;
assign tx_crc2idle              =  state_c == TX_CRC && end_cnt_crc;
always@(podge clk or negedge rst_n)begin
木兰诗作者if(!rst_n)
data_out <= 0;
el if(state_c == TX_ETH_HED)begin
ca(cnt_eth_hed)
0,1,2,3,4,5,6:data_out <= PREAMBLE;
7 :data_out <= SFD;
8 :data_out <= dst_mac_tmp[47:40];
9 :data_out <= dst_mac_tmp[39:32];
10:data_out <= dst_mac_tmp[31:24];
11:data_out <= dst_mac_tmp[23:16];
12:data_out <= dst_mac_tmp[15:8];
13:data_out <= dst_mac_tmp[7:0];
14:data_out <= src_mac_tmp[47:40];
15:data_out <= src_mac_tmp[39:32];
16:data_out <= src_mac_tmp[31:24];
17:data_out <= src_mac_tmp[23:16];
18:data_out <= src_mac_tmp[15:8];
19:data_out <= src_mac_tmp[7:0];
20:data_out <= ETH_TYPE[15:8];
21:data_out <= ETH_TYPE[7:0];
default:data_out <= 8'h00;
endca
end
el if(state_c == TX_IP_HED)begin
ca(cnt_ip_hed)
0 :data_out <= {IP_VER,IP_HDR_LEN};
1 :data_out <= IP_TOS;
2 :data_out <= ip_total_len[15:8];
3 :data_out <= ip_total_len[7:0];
4 :data_out <= IP_ID[15:8];
5 :data_out <= IP_ID[7:0];
6 :data_out <= {IP_RSV,IP_DF,IP_MF,IP_FRAG_OFFSET[12:8]};
7 :data_out <= IP_FRAG_OFFSET[7:0];
8 :data_out <= IP_TTL;
9 :data_out <= IP_PROTOCOL;
10:data_out <= check_sum[15:8];
11:data_out <= check_sum[7:0];
12:data_out <= src_ip_tmp[31:24];
13:data_out <= src_ip_tmp[23:16];
14:data_out <= src_ip_tmp[15:8];
15:data_out <= src_ip_tmp[7:0];
16:data_out <= dst_ip_tmp[31:24];
17:data_out <= dst_ip_tmp[23:16];
18:data_out <= dst_ip_tmp[15:8];
19:data_out <= dst_ip_tmp[7:0];
default:data_out <= 8'h00;
endca
end
el if(state_c == TX_UDP_HED)begin
ca(cnt_udp_hed)
0:data_out <= src_port_tmp[15:8];
1:data_out <= src_port_tmp[7:0];
2:data_out <= dst_port_tmp[15:8];
3:data_out <= dst_port_tmp[7:0];
4:data_out <= udp_total_len[15:8];
5:data_out <= udp_total_len[7:0];
6:data_out <= udp_check_sum[15:8];
7:data_out <= udp_check_sum[7:0];
default:data_out <= 8'h00;
endca
end
el if(state_c == TX_UDP_DATA)begin
data_out <= data_in;
end
el if(state_c == TX_FILL_DATA)begin
data_out <= 8'h00;
end
el if(state_c == TX_CRC)begin
data_out <= 0;
end
end
//以太⽹头部计数器
always @(podge clk or negedge rst_n)begin
if(!rst_n)
cnt_eth_hed <= 0;
最美的季节
el if(add_cnt_eht_hed)begin
if(end_cnt_eth_hed)
cnt_eth_hed <= 0;
el
cnt_eth_hed <= cnt_eth_hed + 1'b1;
end
end
assign add_cnt_eht_hed = state_c == TX_ETH_HED;
assign end_cnt_eth_hed = add_cnt_eht_hed && cnt_eth_hed == ETH_HED_N - 1; //IP头计数器
always @(podge clk or negedge rst_n)begin
if(!rst_n)
cnt_ip_hed <= 0;
el if(add_cnt_ip_hed)begin
if(end_cnt_ip_hed)
cnt_ip_hed <= 0;
el
cnt_ip_hed <= cnt_ip_hed + 1;
end
end
assign add_cnt_ip_hed = state_c == TX_IP_HED;
assign end_cnt_ip_hed = add_cnt_ip_hed && cnt_ip_hed == IP_HED_N - 1;
//udp头部计数器
always @(podge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_udp_hed <= 0;
end
el if(add_cnt_udp_hed)begin
gta5怎么全屏if(end_cnt_udp_hed)
cnt_udp_hed <= 0;
el
cnt_udp_hed <= cnt_udp_hed + 1;
end
end
assign add_cnt_udp_hed = state_c == TX_UDP_HED;
assign end_cnt_udp_hed = add_cnt_udp_hed && cnt_udp_hed == UDP_HED_N - 1; //UDP数据计数器
always @(podge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_data <= 0;
end
el if(add_cnt_data)begin
if(end_cnt_data)
cnt_data <= 0;
el
cnt_data <= cnt_data + 1;
end

本文发布于:2023-05-18 19:34:39,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/685296.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数据   发送   字节   协议   实现   校验   分段   长度
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图