第一文中介绍了以太网的各层协议;链接:https://blog.csdn.net/weixin_41838250/article/details/114686428?spm=1001.2014.3001.5502
第二文中对使用的10Gbase-R和MAC使用做了简单描述;链接:https://blog.csdn.net/weixin_41838250/article/details/114691373
这里做一个简单的千兆网络设计,使用RGMII接口。
1,架构设计
2 发送端
UDP发送模块,完成UDP数据报,IP数据报,MAC帧组装;代码如下
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/08/28 13:37:07
// Design Name:
// Module Name: network_tx_design
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module network_tx_design #(
parameter [15:0] src_port = 16'h5000,
parameter [15:0] dest_port = 16'h6000,
parameter [31:0] src_ip = 32'h01010101,
parameter [31:0] dest_ip = 32'h05050505,
parameter [47:0] src_mac_addr = 48'hAAAABBBBCC,
parameter [47:0] dest_mac_addr = 48'hDDDDEEEEFFFF
)(
input sys_clk,
input sys_rst,
input udp_tx_sof,
input udp_tx_en,
input [7:0] udp_tx_data,
input [15:0] udp_tx_byte_num,
output udp_tx_ready,
output udp_tx_ok,
input mac_enable,
output mac_tx_sof,
output mac_tx_eof,
output mac_tx_en,
output [7:0] mac_tx_data,
input mac_tx_ready
);
localparam [15:0] total_length = 14+20+8; //mac_header_length + ip_header_length + udp_header_length;
//ip header
localparam [15:0] ver_len_tos = 16'h4500;
localparam [15:0] logo_flag = 16'd0;
localparam [15:0] mf_offest = 16'd0;
localparam [7:0] ip_protocol = 8'd17;
localparam [7:0] ttl_time = 8'd0;
//mac header
localparam [15:0] mac_type = 16'h0800;
//state
localparam [3:0] idle_state = 4'd0;
localparam [3:0] sof_state = 4'd1;
localparam [3:0] header_state = 4'd2;
localparam [3:0] data_state = 4'd3;
localparam [3:0] end_state = 4'd4;
wire [19:0] ip_check_num;
wire [15:0] ip_check_sum;
reg fifo_wr_en = 0;
reg [7:0] fifo_wr_data = 0;
wire fifo_wr_ready;
reg fifo_rd_en = 0;
wire [7:0] fifo_rd_data;
wire fifo_rd_ready;
reg [15:0] rx_data_cnt = 0;
reg [15:0] tx_header_cnt = 0;
reg [15:0] tx_data_cnt = 0;
reg tx_sof = 0;
reg tx_eof = 0;
reg tx_ok = 0;
reg tx_en = 0;
reg [7:0] tx_data = 0;
wire [15:0] ip_total_num;
wire [15:0] udp_total_num;
reg [3:0] tx_current_state = idle_state;
reg [3:0] tx_next_state = idle_state;
assign udp_total_num = udp_tx_byte_num + 8;
assign ip_total_num = udp_tx_byte_num + 28;
assign ip_check_num = ver_len_tos + {ttl_time,ip_protocol} + (udp_tx_byte_num + 28) + src_ip[31:16] + src_ip[15:0] + dest_ip[31:16] + dest_ip[15:0];
assign ip_check_sum = ~(ip_check_num[19:16] + ip_check_num[15:0]);
//----------------------------rx data----------------------------------------------------
always @ (posedge sys_clk) begin
if(sys_rst)
rx_data_cnt <= 0;
else if(udp_tx_sof && udp_tx_en)
rx_data_cnt <= 1;
else if(udp_tx_en)
rx_data_cnt <= rx_data_cnt + 1;
else
rx_data_cnt <= rx_data_cnt;
end
always @ (posedge sys_clk) begin //写FIFO
if(sys_rst) begin
fifo_wr_en <= 0;
fifo_wr_data <= 0;
end
else begin
fifo_wr_en <= udp_tx_en;
fifo_wr_data <= udp_tx_data;
end
end
data_fifo udp_data_fifo(
.s_aclk (sys_clk ),
.s_aresetn (!sys_rst ),
.wr_rst_busy ( ),
.rd_rst_busy ( ),
.s_axis_tready (fifo_wr_ready),
.s_axis_tvalid (fifo_wr_en ),
.s_axis_tdata (fifo_wr_data ),
.m_axis_tready (fifo_rd_en ),
.m_axis_tdata (fifo_rd_data ),
.m_axis_tvalid (fifo_rd_ready)
);
//----------------------------tx data state-------------------------------------------
always @ (posedge sys_clk) begin
if(sys_rst)
tx_current_state <= idle_state;
else
tx_current_state <= tx_next_state;
end
always @ (*) begin
if(sys_rst)
tx_next_state = idle_state;
else case(tx_current_state)
idle_state : if(udp_tx_sof) tx_next_state = sof_state;
else tx_next_state = idle_state;
sof_state : tx_next_state = header_state;
header_state : if(tx_header_cnt >= total_length) tx_next_state = data_state;
else tx_next_state = header_state;
data_state : if(tx_data_cnt >= udp_tx_byte_num) tx_next_state = end_state;
else tx_next_state = data_state;
end_state : tx_next_state = idle_state;
default : tx_next_state = idle_state;
endcase
end
always @ (posedge sys_clk) begin
if(sys_rst) begin
tx_sof <= 0;
tx_eof <= 0;
tx_ok <= 0;
tx_en <= 0;
tx_data <= 0;
tx_data_cnt <= 0;
tx_header_cnt <= 0;
fifo_rd_en <= 0;
end
else case(tx_current_state)
idle_state : begin
tx_sof <= 0;
tx_eof <= 0;
tx_ok <= 0;
tx_en <= 0;
tx_data <= 0;
tx_header_cnt <= 0;
tx_data_cnt <= 0;
fifo_rd_en <= 0;
end
sof_state : begin
tx_sof <= 1;
tx_eof <= 0;
tx_ok <= 0;
tx_en <= 1;
tx_data <= dest_mac_addr[47:40];
tx_header_cnt <= 1;
tx_data_cnt <= 0;
fifo_rd_en <= 0;
end
header_state : if(mac_tx_ready) begin
tx_sof <= 0;
tx_header_cnt <= tx_header_cnt + 1;
case(tx_header_cnt)
//MAC
0 : begin tx_en <= 1; tx_data <= dest_mac_addr[47:40]; end
1 : begin tx_en <= 1; tx_data <= dest_mac_addr[39:32]; end
2 : begin tx_en <= 1; tx_data <= dest_mac_addr[31:24]; end
3 : begin tx_en <= 1; tx_data <= dest_mac_addr[23:16]; end
4 : begin tx_en <= 1; tx_data <= dest_mac_addr[15:8]; end
5 : begin tx_en <= 1; tx_data <= dest_mac_addr[7:0]; end
6 : begin tx_en <= 1; tx_data <= src_mac_addr[47:40]; end
7 : begin tx_en <= 1; tx_data <= src_mac_addr[39:32]; end
8 : begin tx_en <= 1; tx_data <= src_mac_addr[31:24]; end
9 : begin tx_en <= 1; tx_data <= src_mac_addr[23:16]; end
10: begin tx_en <= 1; tx_data <= src_mac_addr[15:8]; end
11: begin tx_en <= 1; tx_data <= src_mac_addr[7:0]; end
12: begin tx_en <= 1; tx_data <= mac_type[15:8]; end
13: begin tx_en <= 1; tx_data <= mac_type[7:0]; end
//IP
14: begin tx_en <= 1; tx_data <= ver_len_tos[15:8]; end
15: begin tx_en <= 1; tx_data <= ver_len_tos[7:0]; end
16: begin tx_en <= 1; tx_data <= ip_total_num[15:8]; end
17: begin tx_en <= 1; tx_data <= ip_total_num[7:0]; end
18: begin tx_en <= 1; tx_data <= logo_flag[15:8]; end
19: begin tx_en <= 1; tx_data <= logo_flag[7:0]; end
20: begin tx_en <= 1; tx_data <= mf_offest[15:8]; end
21: begin tx_en <= 1; tx_data <= mf_offest[7:0]; end
22: begin tx_en <= 1; tx_data <= ttl_time; end
23: begin tx_en <= 1; tx_data <= ip_protocol; end
24: begin tx_en <= 1; tx_data <= ip_check_sum[15:8]; end
25: begin tx_en <= 1; tx_data <= ip_check_sum[7:0]; end
26: begin tx_en <= 1; tx_data <= src_ip[31:24]; end
27: begin tx_en <= 1; tx_data <= src_ip[23:16]; end
28: begin tx_en <= 1; tx_data <= src_ip[15:8]; end
29: begin tx_en <= 1; tx_data <= src_ip[7:0]; end
30: begin tx_en <= 1; tx_data <= dest_ip[31:24]; end
31: begin tx_en <= 1; tx_data <= dest_ip[23:16]; end
32: begin tx_en <= 1; tx_data <= dest_ip[15:8]; end
33: begin tx_en <= 1; tx_data <= dest_ip[7:0]; end
//UDP
34: begin tx_en <= 1; tx_data <= src_port[15:8]; end
35: begin tx_en <= 1; tx_data <= src_port[7:0]; end
36: begin tx_en <= 1; tx_data <= dest_port[15:8]; end
37: begin tx_en <= 1; tx_data <= dest_port[7:0]; end
38: begin tx_en <= 1; tx_data <= udp_total_num[15:8]; end
39: begin tx_en <= 1; tx_data <= udp_total_num[7:0]; end
40: begin tx_en <= 1; tx_data <= 8'd0; end
41: begin tx_en <= 1; tx_data <= 8'd0; end
42: begin tx_en <= 0; end
endcase
end
else begin
tx_sof <= tx_sof;
tx_en <= tx_en;
tx_header_cnt <= tx_header_cnt;
end
data_state :begin
if(fifo_rd_ready == 1 && tx_data_cnt < udp_tx_byte_num && mac_tx_ready)
fifo_rd_en <= 1;
else
fifo_rd_en <= 0;
if(fifo_rd_en && fifo_rd_ready && tx_data_cnt == udp_tx_byte_num - 1) begin
tx_eof <= 1;
tx_en <= 1;
tx_data_cnt <= tx_data_cnt + 1;
tx_data <= fifo_rd_data;
end
else if(fifo_rd_en && fifo_rd_ready) begin
tx_eof <= 0;
tx_en <= 1;
tx_data_cnt <= tx_data_cnt + 1;
tx_data <= fifo_rd_data;
end
else begin
tx_eof <= 0;
tx_en <= 0;
tx_data_cnt <= tx_data_cnt;
tx_data <= 0;
end
end
end_state : begin
tx_sof <= 0;
tx_eof <= 0;
tx_ok <= 1;
tx_en <= 0;
tx_data <= 0;
tx_header_cnt <= 0;
tx_data_cnt <= 0;
fifo_rd_en <= 0;
end
endcase
end
assign mac_tx_sof = tx_sof;
assign mac_tx_eof = tx_eof;
assign mac_tx_en = tx_en;
assign mac_tx_data = tx_data;
assign udp_tx_ok = tx_ok;
assign udp_tx_ready = fifo_wr_ready;//&& mac_enable;
endmodule
2.2 接收端
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/09/01 10:29:44
// Design Name:
// Module Name: network_rx_design
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module network_rx_design#(
parameter [15:0] src_port = 16'h5000,
parameter [15:0] dest_port = 16'h6000,
parameter [31:0] src_ip = 32'h01010101,
parameter [31:0] dest_ip = 32'h05050505,
parameter [47:0] src_mac_addr = 48'hAAAABBBBCC,
parameter [47:0] dest_mac_addr = 48'hDDDDEEEEFFFF
)(
input sys_clk,
input sys_rst,
input mac_enable,
input mac_rx_en,
input mac_rx_eof,
input [7:0] mac_rx_data,
output udp_rx_error,
output udp_rx_sof,
output udp_rx_eof,
output udp_rx_en,
output [7:0] udp_rx_data,
output [15:0] udp_byte_num
);
//state
localparam [3:0] idle_state = 4'd0;
localparam [3:0] header_state = 4'd1;
localparam [3:0] data_state = 4'd2;
localparam [3:0] end_state = 4'd3;
reg [3:0] rx_current_state = idle_state;
reg [3:0] rx_next_state = idle_state;
reg rx_en = 0;
reg rx_sof = 0;
reg rx_eof = 0;
reg [7:0] rx_data = 0;
reg [15:0] rx_data_cnt = 0;
reg [7:0] rx_header_cnt = 0;
reg rx_error = 0;
//mac
reg [47:0] rx_dest_mac_addr = 0;
reg [47:0] rx_src_mac_addr = 0;
//ip
reg [15:0] rx_ip_total_length = 0;
reg [7:0] rx_ip_protocol = 0;
reg [15:0] rx_ip_check_sum = 0;
reg [31:0] rx_src_ip = 0;
reg [31:0] rx_dest_ip = 0;
//udp
reg [15:0] rx_dest_port = 0;
reg [15:0] rx_src_port = 0;
reg [15:0] rx_udp_total_length = 0;
//---------------------------------------------------------------------------------------
always @ (posedge sys_clk) begin
if(sys_rst)
rx_current_state <= idle_state;
else
rx_current_state <= rx_next_state;
end
always @ (*) begin
if(sys_rst)
rx_next_state = idle_state;
else case(rx_current_state)
idle_state : if(mac_enable) rx_next_state = header_state;
else rx_next_state = idle_state;
header_state : if(mac_rx_en && rx_header_cnt == 41) rx_next_state = data_state;
else rx_next_state = header_state;
data_state : if(mac_rx_en && mac_rx_eof) rx_next_state = end_state;
else rx_next_state = data_state;
end_state : rx_next_state = idle_state;
default : rx_next_state = idle_state;
endcase
end
always @ (posedge sys_clk) begin
if(sys_rst) begin
rx_en <= 0;
rx_sof <= 0;
rx_eof <= 0;
rx_data <= 0;
rx_data_cnt <= 0;
rx_error <= 0;
rx_header_cnt <= 0;
rx_dest_mac_addr <= 0;
rx_src_mac_addr <= 0;
rx_ip_total_length <= 0;
rx_ip_protocol <= 0;
rx_ip_check_sum <= 0;
rx_src_ip <= 0;
rx_dest_ip <= 0;
rx_dest_port <= 0;
rx_src_port <= 0;
rx_udp_total_length <= 0;
end
else case(rx_current_state)
idle_state : begin
rx_en <= 0;
rx_sof <= 0;
rx_eof <= 0;
rx_data <= 0;
rx_data_cnt <= 0;
rx_header_cnt <= 0;
rx_error <= 0;
rx_dest_mac_addr <= 0;
rx_src_mac_addr <= 0;
rx_ip_total_length <= 0;
rx_ip_protocol <= 0;
rx_ip_check_sum <= 0;
rx_src_ip <= 0;
rx_dest_ip <= 0;
rx_src_port <= 0;
rx_dest_port <= 0;
rx_udp_total_length <= 0;
end
header_state : begin
if(mac_rx_en) begin
rx_header_cnt <= rx_header_cnt + 1;
case(rx_header_cnt)
0 : rx_dest_mac_addr[47:40] <= mac_rx_data;
1 : rx_dest_mac_addr[39:32] <= mac_rx_data;
2 : rx_dest_mac_addr[31:24] <= mac_rx_data;
3 : rx_dest_mac_addr[23:16] <= mac_rx_data;
4 : rx_dest_mac_addr[15:8] <= mac_rx_data;
5 : rx_dest_mac_addr[7:0] <= mac_rx_data;
6 : rx_src_mac_addr[47:40] <= mac_rx_data;
7 : rx_src_mac_addr[39:32] <= mac_rx_data;
8 : rx_src_mac_addr[31:24] <= mac_rx_data;
9 : rx_src_mac_addr[23:16] <= mac_rx_data;
10 : rx_src_mac_addr[15:8] <= mac_rx_data;
11 : rx_src_mac_addr[7:0] <= mac_rx_data;
16 : rx_ip_total_length[15:8] <= mac_rx_data;
17 : rx_ip_total_length[7:0] <= mac_rx_data;
23 : rx_ip_protocol <= mac_rx_data;
24 : rx_ip_check_sum[15:8] <= mac_rx_data;
25 : rx_ip_check_sum[7:0] <= mac_rx_data;
26 : rx_src_ip[31:24] <= mac_rx_data;
27 : rx_src_ip[23:16] <= mac_rx_data;
28 : rx_src_ip[15:8] <= mac_rx_data;
29 : rx_src_ip[7:0] <= mac_rx_data;
30 : rx_dest_ip[31:24] <= mac_rx_data;
31 : rx_dest_ip[23:16] <= mac_rx_data;
32 : rx_dest_ip[15:8] <= mac_rx_data;
33 : rx_dest_ip[7:0] <= mac_rx_data;
34 : rx_src_port[15:8] <= mac_rx_data;
35 : rx_src_port[7:0] <= mac_rx_data;
36 : rx_dest_port[15:8] <= mac_rx_data;
37 : rx_dest_port[7:0] <= mac_rx_data;
38 : rx_udp_total_length[15:8] <= mac_rx_data;
39 : rx_udp_total_length[7:0] <= mac_rx_data;
default : ;
endcase
end
else begin
rx_header_cnt <= rx_header_cnt;
end
end
data_state : begin
if(mac_rx_en && mac_rx_eof) begin
rx_en <= 1;
rx_sof <= 0;
rx_eof <= 1;
rx_data <= mac_rx_data;
rx_data_cnt <= rx_data_cnt + 1;
end
else if(mac_rx_en && rx_data_cnt == 0) begin
rx_en <= 1;
rx_sof <= 1;
rx_eof <= 0;
rx_data <= mac_rx_data;
rx_data_cnt <= rx_data_cnt + 1;
end
else if(mac_rx_en) begin
rx_en <= 1;
rx_sof <= 0;
rx_eof <= 0;
rx_data <= mac_rx_data;
rx_data_cnt <= rx_data_cnt + 1;
end
else begin
rx_en <= 0;
rx_sof <= 0;
rx_eof <= 0;
rx_data <= mac_rx_data;
rx_data_cnt <= rx_data_cnt;
end
end
end_state : begin
rx_en <= 0;
rx_sof <= 0;
rx_eof <= 0;
rx_data <= 0;
rx_data_cnt <= 0;
if(rx_data_cnt != rx_udp_total_length - 8)
rx_error <= 1;
else
rx_error <= 0;
end
endcase
end
assign udp_rx_sof = rx_sof;
assign udp_rx_eof = rx_eof;
assign udp_rx_en = rx_en;
assign udp_rx_data = rx_data;
assign udp_byte_num = rx_udp_total_length - 8;
assign udp_rx_error = rx_error;
endmodule