概述
一.基础知识:
1.网络结构:计算机网络的层次结构如图所示。
2.以太网:以太网包括了数据链路层和物理层,数据链路层可以细分为LLC层和MAC层。
我们需要了解的是MAC层,它有两个作用:
①每一个网卡分配一个唯一的MAC地址(硬件地址),用以区分不同通信设备。
②对上层的数据进行封装,变成MAC帧,通过接口传到物理层,然后再通过物理介质传输到其他设备。
如图所示,mac与物理层的接口有多种:
①MII:支持10M和100Mbps。RMII是MII的简化版。
②GMII:支持1000Mbps,即千兆网,RGMII是MII的简化版。
至于接口的细节可以参见小梅哥的教程,日常我们只要知道有这些接口存在即可。
3.ARP帧:
简单地了解:
ARP帧是用来获取目的主机的硬件地址的(即MAC地址),利用已知的目的主机的IP地址和端口号来查找目的MAC地址。
工作时,源主机发出ARP数据包请求并广播,目的主机收到广播后发出一个ARP应答数据包告诉对方它的MAC地址。
ARP和IP是两个相互独立的协议,都属于网络层,ARP更底层,没有ARP提高的映射功能,IP 数据包无法在以太网上发送。
二.以太网MAC帧发送设计:fifo_mac_send
1.建立模型:
2.可以实现的功能:
通过数据采集模块采集的数据存于FIFO中,当FIFO中的数据量满足要求时,控制端向MAC_send模块发送一个ctr_tx_en脉冲信号,指示该模块开始把FIFO中的数据封装成一个MAC帧发送到PHY芯片上。
其中,目的mac地址dst_mac_add通过ARP帧广播获取,源mac地址在本机上,crc32为校验位。
3.代码实现:
module fifo_mac_send(
clk,
reset,
data_in,
write_en,
dst_mac_add,
src_mac_add,
type_length,
crc32,
ctrl_tx_en,
tx_en,//数据发送使能信号
tx_data//待发送的数据
);
input clk ;
input reset ;
input [7:0]data_in ;
input
write_en ;
input [47:0]dst_mac_add;//目的mac地址
input [47:0]src_mac_add;//本地mac地址
input [15:0]type_length;//类型/长度
input [31:0]crc32;//效验码
input ctrl_tx_en;
output tx_en ;
output [3:0]tx_data ;
wire data_req ;
wire [7:0]dout ;
wire full;
wire empty ;
wire [10:0]data_count ;
FIFO_ip_or_arp fifo (
.clk(clk),
// input wire clk
.srst(reset),
// input wire srst
.din(data_in),
// input wire [7 : 0] din
.wr_en(write_en),
// input wire wr_en
.rd_en(data_req),
// input wire rd_en
.dout(dout),
// output wire [7 : 0] dout
.full(full),
// output wire full
.empty(empty),
// output wire empty
.data_count(data_count)
// output wire [10 : 0] data_count
);
mac_send
mac_send(
.tx_clk(clk),//输入时钟
.reset(reset) ,
.ctrl_tx_en(ctrl_tx_en),//输入使能端
.data_in(dout),//输入数据
.dst_mac_add(dst_mac_add),//目的mac地址
.src_mac_add(src_mac_add),//本地mac地址
.type_length(type_length),//类型/长度
.crc32(crc32),//效验码
.data_req(data_req),//数据请求端口
.ctrl_done(empty),//数据接收完成
.tx_en(tx_en),//数据发送使能信号
.tx_data(tx_data)//待发送的数据
);
endmodule
module mac_send(
tx_clk,//输入时钟
reset ,
ctrl_tx_en,//输入使能端
data_in,//输入数据
dst_mac_add,//目的mac地址
src_mac_add,//本地mac地址
type_length,//类型/长度
crc32,//效验码
data_req,//数据请求端口
ctrl_done,//数据接收完成
tx_en,//数据发送使能信号
tx_data//待发送的数据
);
input tx_clk;
input reset ;
input ctrl_tx_en;
input [7:0]data_in;
input [47:0]dst_mac_add;
input [47:0]src_mac_add;
input [15:0]type_length;
input [31:0]crc32;
output reg data_req;
input ctrl_done;
output reg tx_en;
output reg [3:0]tx_data;
//用状态机来实现
//定义计时器
reg [5:0]cnt;//最大45
reg mac_done ;//发送到45时产生一个mac帧结束信号
always@(posedge tx_clk or negedge reset)
if (reset)
mac_done <= 0 ;
else if (cnt == 53)
mac_done <= 1 ;
else if (mac_done)
mac_done <= 0
;
reg send_en ;
always@(posedge tx_clk or negedge reset)
if (reset)
send_en <= 0 ;
else if (ctrl_tx_en)
send_en <= 1 ;
else if (mac_done)
send_en <= 0
;
//数据段发完信号
reg data_rec_done ;
always@(posedge tx_clk or negedge reset)
if (reset)
data_rec_done <= 0 ;
else if (ctrl_done)
data_rec_done <= 1 ;
else if (data_rec_done)
data_rec_done <= 0 ;
always@(posedge tx_clk or negedge reset)
if (reset)
cnt <= 0 ;
else if (send_en)
begin
if(( cnt < 53 )&&( cnt!=45 )&&(!mac_done) )
cnt <= cnt + 1 ;
else if ((cnt == 45) && (data_rec_done ))
cnt <= cnt + 1;
else if( cnt == 53 )
cnt <= 0 ;
else if (mac_done)
cnt <= 0;
end
always@(posedge tx_clk or negedge reset)
if (reset)
data_req <= 0 ;
else if (send_en)
begin
if(cnt == 43 )
data_req <= 1 ;
else if ( cnt == 44 )
data_req <= 0 ;
else if ( cnt == 45 )
data_req <= !data_req ;
end
always@(posedge tx_clk)
if (reset )
tx_data <= 4'h0 ;
else if(send_en)
case(cnt)
//发送mac帧
0:tx_data <= 4'h0;
//前导符
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 : tx_data <= 4'h5 ;
16:tx_data <= 4'hD ;
//目的mac地址
17:tx_data <= dst_mac_add[47:44];
18:tx_data <= dst_mac_add[43:40];
19:tx_data <= dst_mac_add[39:36];
20:tx_data <= dst_mac_add[35:32];
21:tx_data <= dst_mac_add[31:28];
22:tx_data <= dst_mac_add[27:24];
23:tx_data <= dst_mac_add[23:20];
24:tx_data <= dst_mac_add[19:16];
25:tx_data <= dst_mac_add[15:12];
26:tx_data <= dst_mac_add[11:8];
27:tx_data <= dst_mac_add[7:4];
28:tx_data <= dst_mac_add[3:0];
//源mac地址
29:tx_data <= src_mac_add[47:44];
30:tx_data <= src_mac_add[43:40];
31:tx_data <= src_mac_add[39:36];
32:tx_data <= src_mac_add[35:32];
33:tx_data <= src_mac_add[31:28];
34:tx_data <= src_mac_add[27:24];
35:tx_data <= src_mac_add[23:20];
36:tx_data <= src_mac_add[19:16];
37:tx_data <= src_mac_add[15:12];
38:tx_data <= src_mac_add[11:8];
39:tx_data <= src_mac_add[7:4];
40:tx_data <= src_mac_add[3:0];
//长度/类型
41:tx_data <= type_length[15:12];
42:tx_data <= type_length[11:8];
43:tx_data <= type_length[7:4];
44:tx_data <= type_length[3:0];
//数据填充
45: begin
if(!data_req)
tx_data <= data_in[7:4];
else if (data_req)
tx_data <= data_in[3:0];
end
//校验位
46: tx_data <= crc32[31:28];
47: tx_data <= crc32[27:24];
48: tx_data <= crc32[23:20];
49: tx_data <= crc32[19:16];
50: tx_data <= crc32[15:12];
51: tx_data <= crc32[11:8];
52: tx_data <= crc32[7:4];
53: tx_data <= crc32[3:0];
default: tx_data <= tx_data ;
endcase
always@(posedge tx_clk or negedge reset)
if (reset)
tx_en <= 0 ;
else if( mac_done )
tx_en <= 1 ;
else
tx_en <= 0 ;
endmodule
`timescale 1ns / 1ns
module fifo_mac_send_tb(
);
reg clk;
reg reset ;
reg [7:0]data_in ;
reg
write_en ;
reg [47:0]dst_mac_add;//目的mac地址
reg [47:0]src_mac_add;//本地mac地址
reg [15:0]type_length;//类型/长度
reg [31:0]crc32;//效验码
reg ctrl_tx_en;
wire tx_en ;
wire [3:0]tx_data ;
fifo_mac_send fifo_mac_send_sim(
clk,
reset,
data_in,
write_en,
dst_mac_add,
src_mac_add,
type_length,
crc32,
ctrl_tx_en,
tx_en,//数据发送使能信号
tx_data//待发送的数据
);
initial clk = 1 ;
always #10 clk = !clk ;
initial begin
reset = 1 ;
data_in = 0;
write_en = 0;
dst_mac_add = 0 ;
src_mac_add = 0 ;
type_length = 0 ;
crc32 = 0 ;
ctrl_tx_en = 0 ;
#201 ;
reset = 0 ;
#20 ;
//向FIFO写入随机数据
repeat(1024)begin
write_en = 1;
data_in = {$random} % 256 ;
#20 ;
end
write_en = 0 ;
data_in = 0 ;
#10000 ;
//读FIFO数据
ctrl_tx_en = 1 ;
dst_mac_add = 48'hff_ff_ff_ff_ff_ff ;
src_mac_add = 48'h08_8f_c3_41_af_2a ;
type_length = 16'd1024 ;
crc32 = 32'h55_55_55_dd ;
#20 ;
ctrl_tx_en = 0;
#100000;
//第二个mac帧
reset = 1 ;
data_in = 0;
write_en = 0;
dst_mac_add = 0 ;
src_mac_add = 0 ;
type_length = 0 ;
crc32 = 0 ;
ctrl_tx_en = 0 ;
#201 ;
reset = 0 ;
#20 ;
//向FIFO写入随机数据
repeat(1024)begin
write_en = 1;
data_in = {$random} % 256 ;
#20 ;
end
write_en = 0 ;
data_in = 0 ;
#10000 ;
//读FIFO数据
ctrl_tx_en = 1 ;
dst_mac_add = 48'h12_34_56_78_9a_bc ;
src_mac_add = 48'h08_8f_c3_41_af_2a ;
type_length = 16'd1024 ;
crc32 = 32'h5d_5d_5d_cb ;
#20 ;
ctrl_tx_en = 0;
#100000;
$stop;
end
endmodule
4.仿真结果
最后
以上就是开放薯片为你收集整理的以太网MAC帧发送设计:fifo_mac_send的全部内容,希望文章能够帮你解决以太网MAC帧发送设计:fifo_mac_send所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复