以太网数据通信
物理层:网线+网卡(PHY芯片)
数据链路层:Mac层(数据有效传输)
如图所示:FPGA中的Mac层中的MII接口负责控制PHY芯片,PHY芯片通过网线与PC端进行以太网数据传输。
FPGA中Mac与PHY通信MII接口
FPGA通过MAC层发送ARP协议
发送ARP协议目的:知道IP地址后,得到MAC(主机硬件地址)
MAC层模块原理设计图:
使用MAC层发送ARP命令原理如图所示:
ARP模块设计
模块设计图
ARP发送模块设计时序
根据图上的ARP通信原理,设计时序图如下。
MAC层模块代码
module mac_mii_send(input [47:0] mac_source , //Mac_source
input [47:0] mac_goal , //other_Mac
input rst_n ,
input mac_send_en , //pulse width > 40ns
input [15:0] data_type , //agreement type
input [10:0] data_length , //main data field length
input [31:0] crc_result , //Frame check sequence
// mii Interface
input mii_tx_clk , //mii interface clk
output reg mii_tx_en , //mii interface enable
output reg [3:0] mii_txd , //mii interface data
output mii_tx_error , //error signal high level effective
// fifo Interface
input [3:0] mac_send_data , //data read from fifo
output fifo_rd_clk , //read fifo clock
output data_req , //read requestoutput reg send_done //pulse signal = 40ns);reg [5:0] cnt ;
wire en_tx_data ;
reg [10:0] data_cnt ;
reg en ;always @(posedge mii_tx_clk or negedge rst_n)if(!rst_n)en <= 1'b0;elseif(mac_send_en)en <= 1'b1;elseif(cnt == 'h35) //'d53en <= 1'b0;always @(posedge mii_tx_clk or negedge rst_n)if(!rst_n)cnt <= 1'b0;elseif(en)beginif(!en_tx_data)beginif(cnt <= 6'h36) //'d54cnt <= cnt + 1'b1;elsecnt <= 1'b0;endelsecnt <= cnt ;endelsecnt <= 1'b0;assign en_tx_data = (cnt == 'h2D)&&(data_cnt < data_length - 1'b1) ; //'d45
assign data_req = en_tx_data; //fifo request signalalways @(posedge mii_tx_clk or negedge rst_n)if(!rst_n)data_cnt <= 1'b0;elseif(en_tx_data)data_cnt <= data_cnt + 1'b1;elseif(data_cnt == data_length - 1'b1)data_cnt <= 1'b0;// mian Sequencer
always @(posedge mii_tx_clk or negedge rst_n)if(!rst_n)beginmii_txd <= 1'b0;send_done <= 1'b0;endelsebegincase(cnt)6'h0: beginmii_txd <= 1'b0;send_done <= 1'b0;end6'h1,6'h2,6'h3,6'h4,6'h5,6'h6,6'h7,6'h8,6'h9,6'ha,6'hb,6'hc,6'hd,6'he,6'hf:mii_txd <= 4'h5; //前导码6'h10: mii_txd <= 4'hD; //帧开始符6'h11:mii_txd <= mac_goal[43:40] ; //目的MAC地址6'h12: mii_txd <= mac_goal[47:44] ;6'h13:mii_txd <= mac_goal[35:32] ; 6'h14: mii_txd <= mac_goal[39:36] ;6'h15: mii_txd <= mac_goal[27:24] ;6'h16: mii_txd <= mac_goal[31:28] ;6'h17: mii_txd <= mac_goal[19:16] ; 6'h18: mii_txd <= mac_goal[23:20] ;6'h19:mii_txd <= mac_goal[11:8] ; 6'h1a: mii_txd <= mac_goal[15:12] ;6'h1b: mii_txd <= mac_goal[3:0] ;6'h1c: mii_txd <= mac_goal[7:4] ;6'h1d:mii_txd <= mac_source [43:40] ; 6'h1e: mii_txd <= mac_source [47:44] ; //源MAC地址6'h1f: mii_txd <= mac_source [35:32] ; 6'h20: mii_txd <= mac_source [39:36] ;6'h21: mii_txd <= mac_source [27:24] ;6'h22: mii_txd <= mac_source [31:28] ;6'h23: mii_txd <= mac_source [19:16] ;6'h24: mii_txd <= mac_source [23:20] ;6'h25: mii_txd <= mac_source [11:8] ;6'h26: mii_txd <= mac_source [15:12] ;6'h27: mii_txd <= mac_source [3:0] ;6'h28: mii_txd <= mac_source [7:4] ;6'h29: mii_txd <= data_type[11:8] ; //长度/类型6'h2a: mii_txd <= data_type[15:12] ;6'h2b: mii_txd <= data_type[3:0] ;6'h2c: mii_txd <= data_type[7:4] ;6'h2d: //'d45mii_txd <= mac_send_data ;6'h2e: //'d46mii_txd <= crc_result [27:24] ;6'h2f: mii_txd <= crc_result [31:28] ;6'h30: mii_txd <= crc_result [19:16] ;6'h31: mii_txd <= crc_result [23:20] ;6'h32: mii_txd <= crc_result [11:8] ;6'h33: mii_txd <= crc_result [15:12] ;6'h34: mii_txd <= crc_result [3:0] ;6'h35: mii_txd <= crc_result [7:4] ;6'h36: //'d54 beginsend_done <= 1'b1;mii_txd <= 1'b0 ;enddefault: beginsend_done <= 1'b0;mii_txd <= 1'b0 ;endendcaseendalways @(posedge mii_tx_clk or negedge rst_n)if(!rst_n)mii_tx_en <= 1'b0;elseif(en && (cnt == 'h1)) //'d1mii_tx_en <= 1'b1;else if(cnt == 'h36) //'d54mii_tx_en <= 1'b0;elsemii_tx_en <= mii_tx_en ;assign fifo_rd_clk = mii_tx_clk;endmodule
使用ARP工具生成Mac层传输的数据(不包含前导码和帧开始符),将数据复制到CRC生成工具,产生CRC校验值。
源主机通过广播形式发出 ARP 请求,以太网帧首部的硬件地址(目的MAC地址)填 FF:FF:FF:FF:FF:FF 表示广播。
发送ARP请求模块
使用case语句模拟FIFO写入数据。手动计算CRC码。
module mac_mii_send_test(input rst_n ,
input eth_tx_clk ,output eth_tx_er ,
output eth_tx_en ,
output [3:0] eth_tx_data ,
output eth_rst_n );parameter CRC = 32'h79D9D41B; //h42853ABE EA1C2E26 (PC IP 192.168.1.1 : h4DB06FEE) (PC IP 192.168.56.1 : hD892D6E1)wire mac_send_en ;
wire [31:0] crc_result ;
wire data_req ;
wire send_done ;
wire fifo_rd_clk ;
reg [20:0] data_cnt ;
reg [31:0] time_cnt ;
reg [3:0] mac_send_data ;mac_mii_send mac_mii_send_inst(.mac_source (48'h17_31_81_ca_3c_7a), //Mac_source
.mac_goal (48'hff_ff_ff_ff_ff_ff), //other_Mac radio
.rst_n (rst_n),
.mac_send_en (mac_send_en), //pulse width > 40ns
.data_type (16'h08_06), //agreement type
.data_length ('d112), //main data field length ARP字段与填充数据 data_length/2个字节
.crc_result (crc_result), //Frame check sequence
// mii Interfac
.mii_tx_clk (eth_tx_clk), //mii interface clk
.mii_tx_en (eth_tx_en), //mii interface enable
.mii_txd (eth_tx_data), //mii interface data
.mii_tx_error (), //error signal high level effective
// fifo Interface fifo 设置为 showahead 模式
.mac_send_data (mac_send_data), //data read from fifo
.fifo_rd_clk (fifo_rd_clk), //read fifo clock
.data_req (data_req), //read request.send_done (send_done) //pulse signal = 40ns);assign eth_rst_n = 1;
assign crc_result = {CRC[7:0],CRC[15:8],CRC[23:16],CRC[31:24]};always @(posedge eth_tx_clk or negedge rst_n)if(!rst_n)data_cnt <= 1'b0;elseif(data_req)data_cnt <= data_cnt + 1'b1;elsedata_cnt <= 1'b0;always @(posedge eth_tx_clk or negedge rst_n)if(!rst_n)time_cnt <= 'd0;elseif(time_cnt == 'd80000) // time_cnt <= 1'b0;elsetime_cnt <= time_cnt + 1'b1;assign mac_send_en = (time_cnt == 'd50); //d2_499_999always @(*) //ARP字段与填充数据begincase(data_cnt)0, 1, 3 : mac_send_data = 4'h0;2 : mac_send_data = 4'h1; 4 : mac_send_data = 4'h8;5 : mac_send_data = 4'h0;6 : mac_send_data = 4'h0; 7 : mac_send_data = 4'h0; 8 : mac_send_data = 4'h6; //MAC地址长度9 : mac_send_data = 4'h0; 10 : mac_send_data = 4'h4; //IP地址长度11 : mac_send_data = 4'h0; 12 : mac_send_data = 4'h0; //操作码 请求包13 : mac_send_data = 4'h0;14 : mac_send_data = 4'h1;15 : mac_send_data = 4'h0;16 : mac_send_data = 4'h7; //源MAC地址17 : mac_send_data = 4'h1;18 : mac_send_data = 4'h1;19 : mac_send_data = 4'h3;20 : mac_send_data = 4'h1;21 : mac_send_data = 4'h8;22 : mac_send_data = 4'ha;23 : mac_send_data = 4'hc;24 : mac_send_data = 4'hc;25 : mac_send_data = 4'h3;26 : mac_send_data = 4'ha;27 : mac_send_data = 4'h7; 28 : mac_send_data = 4'h0; //源IP地址 192.168.1.20129 : mac_send_data = 4'hc;30 : mac_send_data = 4'h8;31 : mac_send_data = 4'ha;32 : mac_send_data = 4'h1;33 : mac_send_data = 4'h0;34 : mac_send_data = 4'h9;35 : mac_send_data = 4'hc;36 : mac_send_data = 4'h0; //目标MAC地址 37 : mac_send_data = 4'h0;38 : mac_send_data = 4'h0;39 : mac_send_data = 4'h0;40 : mac_send_data = 4'h0;41 : mac_send_data = 4'h0;42 : mac_send_data = 4'h0;43 : mac_send_data = 4'h0;44 : mac_send_data = 4'h0;45 : mac_send_data = 4'h0;46 : mac_send_data = 4'h0;47 : mac_send_data = 4'h0; 48 : mac_send_data = 4'h0; //目标IP 192.168.1.4 49 : mac_send_data = 4'hc;50 : mac_send_data = 4'h8;51 : mac_send_data = 4'ha;52 : mac_send_data = 4'h1; // 53 : mac_send_data = 4'h0; //54 : mac_send_data = 4'h4; //55 : mac_send_data = 4'h0; //56 : mac_send_data = 4'h0; //填充57 : mac_send_data = 4'h0; 58 : mac_send_data = 4'h0; 59 : mac_send_data = 4'h0; 60 : mac_send_data = 4'hf; 61 : mac_send_data = 4'hf; 62 : mac_send_data = 4'hf; 63 : mac_send_data = 4'hf; 64 : mac_send_data = 4'hf; 65 : mac_send_data = 4'hf; 66 : mac_send_data = 4'hf; 67 : mac_send_data = 4'hf; 68 : mac_send_data = 4'hf; 69 : mac_send_data = 4'hf; 70 : mac_send_data = 4'hf; 71 : mac_send_data = 4'hf; 72 : mac_send_data = 4'h0; 73 : mac_send_data = 4'h0; 74 : mac_send_data = 4'h3; 75 : mac_send_data = 4'h2; 76 : mac_send_data = 4'hd; 77 : mac_send_data = 4'hc; 78 : mac_send_data = 4'h6; 79 : mac_send_data = 4'h7; 80 : mac_send_data = 4'h3; 81 : mac_send_data = 4'h6; 82 : mac_send_data = 4'ha; 83 : mac_send_data = 4'h1; 84 : mac_send_data = 4'h8; 85 : mac_send_data = 4'h0; 86 : mac_send_data = 4'h6; 87 : mac_send_data = 4'h0; 88 : mac_send_data = 4'h0; 89 : mac_send_data = 4'h0; 90 : mac_send_data = 4'h1; 91 : mac_send_data = 4'h0; 92 : mac_send_data = 4'h3;93 : mac_send_data = 4'h7;94 : mac_send_data = 4'h4;95 : mac_send_data = 4'h7;96 : mac_send_data = 4'h5;97 : mac_send_data = 4'h7;98 : mac_send_data = 4'h6;99 : mac_send_data = 4'h7; 100 : mac_send_data = 4'h7;101 : mac_send_data = 4'h7;102 : mac_send_data = 4'h1;103 : mac_send_data = 4'h6;104 : mac_send_data = 4'h2;105 : mac_send_data = 4'h6;106 : mac_send_data = 4'h3;107 : mac_send_data = 4'h6;108 : mac_send_data = 4'h4;109 : mac_send_data = 4'h6;110 : mac_send_data = 4'h5;111 : mac_send_data = 4'h6;default : mac_send_data = 4'h0;endcaseendendmodule
使用Wireshark软件查看ARP字段与应答。
FPGA通过MAC层发送UDP协议
IP报头检验和计算模块
将IP报头以2字节为单位相加(此时IP报头检验和为零),求和结果将数据高位溢出位加低16位,求和结果取反为IP报头检验和。
module ip_check(input [3:0] edition , //版本
input [3:0] head_length , //首部长度
input [7:0] service_type , //服务类型
input [15:0] ip_message_length , //ip报文长度
input [30:0] block_logo , //分段标识 + 偏移
input [7:0] life_cycle , //生存周期
input [7:0] agreement_type , //上层协议类型
// input [15:0] ip_checkout_0 , //计算时IP报头检验和为零
input [31:0] source_ip_address , //源IP地址
input [31:0] goal_ip_address , //目的IP地址output [15:0] ip_checkout //IP报头检验和 );wire [31:0] ip_check_sum ;
wire [31:0] ip_check_sum_reg ;assign ip_check_sum_reg = ({edition,head_length,service_type} + ip_message_length + block_logo + {life_cycle,agreement_type} + source_ip_address[31:16] + source_ip_address[15:0] + goal_ip_address[31:16] + goal_ip_address[15:0]);assign ip_check_sum = ~(ip_check_sum_reg[31:16] + ip_check_sum_reg[15:0]);assign ip_checkout = ip_check_sum;endmodule
发送DUP顶层模块
module mac_udp_send_test(input rst_n ,
input eth_tx_clk ,output eth_tx_er ,
output eth_tx_en ,
output [3:0] eth_tx_data ,
output eth_rst_n );parameter CRC = 32'hFE3A3426; //h42853ABE EA1C2E26 (PC IP 192.168.1.1 : h4DB06FEE) (PC IP 192.168.56.1 : hD892D6E1)
parameter DATA_LENFTH = 11'd92; //46字节wire mac_send_en ;
wire [31:0] crc_result ;
wire data_req ;
wire send_done ;
wire fifo_rd_clk ;
reg [20:0] data_cnt ;
reg [31:0] time_cnt ;
reg [3:0] mac_send_data ;
wire crc_en ;
wire [31:0] crc ;
wire [15:0] ip_checkout ;assign eth_rst_n = 1;
assign crc_result = {CRC[7:0],CRC[15:8],CRC[23:16],CRC[31:24]};
// assign crc_result = CRC ;mac_udp_send mac_udp_send_inst(.mac_source (48'h17_31_81_CA_3C_7A), //Mac_source
.mac_goal (48'h58_11_22_A0_E9_61), //目的MAC地址
.rst_n (rst_n),
.mac_send_en (mac_send_en), //pulse width > 40ns
.data_type (16'h08_00), // 长度/类型 UDP
.data_length (DATA_LENFTH), // 数据与填充 data_length/2个字节
.crc_result (crc_result), //Frame check sequence
// mii Interfac
.mii_tx_clk (eth_tx_clk), //mii interface clk
.mii_tx_en (eth_tx_en), //mii interface enable
.mii_txd (eth_tx_data), //mii interface data
.mii_tx_error (), //error signal high level effective
// fifo Interface fifo 设置为 showahead 模式
.mac_send_data (mac_send_data), //data read from fifo input
.fifo_rd_clk (fifo_rd_clk), //read fifo clock
.data_req (data_req), //read request
.crc_en (crc_en), .send_done (send_done) //pulse signal = 40ns);ip_check ip_check_inst(.edition (4'h4) , //版本 .head_length (4'h5) , //首部长度.service_type (0) , //服务类型.ip_message_length (16'h002E) , //ip报文长度.block_logo (0) , //分段标识等.life_cycle (8'h40) , //生存周期.agreement_type ('d17) , //上层协议类型 .source_ip_address ('hC0_A8_01_C9) , //源IP地址.goal_ip_address ('hC0_A8_01_04) , //目的IP地址.ip_checkout (ip_checkout) //IP报头检验和
);always @(posedge eth_tx_clk or negedge rst_n)if(!rst_n)data_cnt <= 1'b0;elseif(data_req)data_cnt <= data_cnt + 1'b1;elsedata_cnt <= 1'b0;always @(posedge eth_tx_clk or negedge rst_n)if(!rst_n)time_cnt <= 'd0;elseif(time_cnt == 'd80000) // time_cnt <= 1'b0;elsetime_cnt <= time_cnt + 1'b1;assign mac_send_en = (time_cnt == 'd50); //d2_499_999always @(*) //ARP字段与填充数据begincase(data_cnt)0 : mac_send_data = 4'h5; //IP首部长度1 : mac_send_data = 4'h4; //IPV42 : mac_send_data = 4'h0; //服务类型3 : mac_send_data = 4'h0; 4 : mac_send_data = 4'h0; //IP报文长度 5 : mac_send_data = 4'h0;6 : mac_send_data = 4'he; 7 : mac_send_data = 4'h2; 8 : mac_send_data = 4'h0; //分段表示 设置0 9 : mac_send_data = 4'h0; 10 : mac_send_data = 4'h0; 11 : mac_send_data = 4'h0; 12 : mac_send_data = 4'h0; 13 : mac_send_data = 4'h0;14 : mac_send_data = 4'h0;15 : mac_send_data = 4'h0;16 : mac_send_data = 4'h0; //周期 6417 : mac_send_data = 4'h4;18 : mac_send_data = 4'h1; //上层协议类型19 : mac_send_data = 4'h1;// 算20 : mac_send_data = ip_checkout[11:8]; //IP报头检验和 逻辑模块算出 忽略 ip_checkout[11:8]21 : mac_send_data = ip_checkout[15:12]; //IP版本+....+目的IP地址 ip_checkout[15:12]22 : mac_send_data = ip_checkout[3:0]; //测试校验和 图7.5-11 ip_checkout[3:0]23 : mac_send_data = ip_checkout[7:4]; //ip_checkout[7:4]24 : mac_send_data = 4'h0; //源IP地址 192.168.1.20125 : mac_send_data = 4'hc;26 : mac_send_data = 4'h8;27 : mac_send_data = 4'ha; 28 : mac_send_data = 4'h1; 29 : mac_send_data = 4'h0;30 : mac_send_data = 4'h9;31 : mac_send_data = 4'hc;32 : mac_send_data = 4'h0; //目的IP地址 4字节 192.168.1.433 : mac_send_data = 4'hc;34 : mac_send_data = 4'h8;35 : mac_send_data = 4'ha;36 : mac_send_data = 4'h1; 37 : mac_send_data = 4'h0;38 : mac_send_data = 4'h4;39 : mac_send_data = 4'h0;//UDP协议层40 : mac_send_data = 4'h9; //源端口号 2字节 650041 : mac_send_data = 4'h1;42 : mac_send_data = 4'h4;43 : mac_send_data = 4'h6;44 : mac_send_data = 4'h5; //目的端口号 2字节 550045 : mac_send_data = 4'h1;46 : mac_send_data = 4'hc;47 : mac_send_data = 4'h7; 48 : mac_send_data = 4'h0; //UDP报文长度 26 2字节 49 : mac_send_data = 4'h0;50 : mac_send_data = 4'ha;51 : mac_send_data = 4'h1;52 : mac_send_data = 4'h0; // UDP校验和 2字节 忽略全零53 : mac_send_data = 4'h0; 54 : mac_send_data = 4'h0; 55 : mac_send_data = 4'h0; 56 : mac_send_data = 4'h8; //填充和数据57 : mac_send_data = 4'h4; 58 : mac_send_data = 4'h5; 59 : mac_send_data = 4'h6; 60 : mac_send_data = 4'hc; 61 : mac_send_data = 4'h6; 62 : mac_send_data = 4'hc; 63 : mac_send_data = 4'h6; 64 : mac_send_data = 4'hf; 65 : mac_send_data = 4'h6; 66 : mac_send_data = 4'hc; 67 : mac_send_data = 4'h2; 68 : mac_send_data = 4'h7; 69 : mac_send_data = 4'h6; 70 : mac_send_data = 4'hf; 71 : mac_send_data = 4'h6; 72 : mac_send_data = 4'hf; 73 : mac_send_data = 4'h6; 74 : mac_send_data = 4'h4; 75 : mac_send_data = 4'h6; 76 : mac_send_data = 4'h0; 77 : mac_send_data = 4'h2; 78 : mac_send_data = 4'h4; 79 : mac_send_data = 4'h7; 80 : mac_send_data = 4'hf; 81 : mac_send_data = 4'h6; 82 : mac_send_data = 4'h0; 83 : mac_send_data = 4'h2; 84 : mac_send_data = 4'h6; 85 : mac_send_data = 4'h4; 86 : mac_send_data = 4'h0; 87 : mac_send_data = 4'h5; 88 : mac_send_data = 4'h7; 89 : mac_send_data = 4'h4; 90 : mac_send_data = 4'h1; 91 : mac_send_data = 4'h4;default : mac_send_data = 4'h0;endcaseendendmodule
可以看到IP校验和无误,并且成功发送字母。