文章目录
- 前言
- 一、模块功能
- 二、实现方式
- 三、仿真
- 四、上板测速
前言
MAC_RX的设计暂时告一段落,本节将开始进行MAC_TX的设计。
一、模块功能
- 接收上层用户的AXIS数据,将其转换为XGMII进接口的数据发送给IP核。
- 可接受AXIS数据流,可支持数据包之间的间隔最小为一个时钟周期
- 目的MAC以及源MAC等参数可动态配置
- 流控,万兆以太网帧间隔为9.6ns,用户时钟频率为156.25Mhz,周期为6.4ns,因此XGMII接口数据之前至少间隔2个时钟周期
模块接口如下:
module TEN_GIG_MAC_TX#(parameter P_SRC_MAC = 48'h00_00_00_00_00_00,parameter P_DST_MAC = 48'h00_00_00_00_00_00
)(input i_clk ,input i_rst ,input [47:0] i_dynamic_src_mac ,input i_dynamic_src_valid ,input [47:0] i_dynamic_dst_mac ,input i_dynamic_dst_valid ,input [63:0] s_axis_tdata ,input [79:0] s_axis_tuser ,input [7 :0] s_axis_tkeep ,input s_axis_tlast ,input s_axis_tvalid ,output s_axis_tready ,output [63:0] o_xgmii_txd ,output [7 :0] o_xgmii_txc
);
二、实现方式
- 将接收到的AXIS数据先存入FIFO,将包头组织完毕后从FIFO当中读取数据进行填充
- 组帧同时要进行CRC计算并且在末尾填充,需要注意,在尾端填充CRC数据时,根据尾端keep信号有多种情况,会存在数据额外需要一个时钟周期进行传输CRC数据。
包含子模块如下:
FIFO_64X256 FIFO_64X256_data_tx (.clk (i_clk ),.srst (i_rst ), .din (rs_axis_tdata ),.wr_en (rs_axis_tvalid ),.rd_en (r_fifo_data_rden ),.dout (w_fifo_data_dout ),.full (w_fifo_data_full ),.empty (w_fifo_data_empty )
);FIFO_32X32 FIFO_32X32_len_type (.clk (i_clk ), .srst (i_rst ), .din ({rs_axis_tuser[79:64],rs_axis_tuser[15:0]}), .wr_en (rs_axis_tlast ), .rd_en (r_fifo_len_type_rden ), .dout (w_fifo_len_type_dout ), .full (w_fifo_len_type_full ), .empty (w_fifo_len_type_empty )
);FIFO_8X32 FIFO_8X32_tail_keep (.clk (i_clk ), .srst (i_rst ), .din (rs_axis_tkeep ), .wr_en (rs_axis_tlast ), .rd_en (r_fifo_keep_rden ), .dout (w_fifo_keep_dout ), .full (w_fifo_keep_full ), .empty (w_fifo_keep_empty )
);CRC32_64bKEEP CRC32_64bKEEP_u0(.i_clk (i_clk ),.i_rst (i_rst ),.i_en (r_crc_en ),.i_data (r_crc_data[63:56] ),.i_data_1 (r_crc_data[55:48] ),.i_data_2 (r_crc_data[47:40] ),.i_data_3 (r_crc_data[39:32] ),.i_data_4 (r_crc_data[31:24] ),.i_data_5 (r_crc_data[23:16] ),.i_data_6 (r_crc_data[15: 8] ),.i_data_7 (r_crc_data[7 : 0] ),.o_crc_8 (w_crc_8_big ),.o_crc_1 (w_crc_1_big ),.o_crc_2 (w_crc_2_big ),.o_crc_3 (w_crc_3_big ),.o_crc_4 (w_crc_4_big ),.o_crc_5 (w_crc_5_big ),.o_crc_6 (w_crc_6_big ),.o_crc_7 (w_crc_7_big )
);
产生XGMII接口的核心代码如下:
//r_xgmii_txc还需要考虑最后多加4byte的CRC
always @(posedge i_clk or posedge i_rst)beginif(i_rst)r_xgmii_txc <= 8'b1111_1111;else if(r_fifo_len_type_rden)r_xgmii_txc <= 8'b1000_0000;else if(r_pkt_cnt == r_data_len + 3 && r_tail_keep >= 8'b1111_1000)case (r_tail_keep)8'b1111_1111 : r_xgmii_txc <= 8'b0001_1111;8'b1111_1110 : r_xgmii_txc <= 8'b0011_1111;8'b1111_1100 : r_xgmii_txc <= 8'b0111_1111;8'b1111_1000 : r_xgmii_txc <= 8'b1111_1111;default : r_xgmii_txc <= 8'b0000_0000;endcaseelse if(r_pkt_cnt == r_data_len + 2 && r_tail_keep < 8'b1111_1000)case (r_tail_keep) 8'b1111_0000 : r_xgmii_txc <= 8'b0000_0001;8'b1110_0000 : r_xgmii_txc <= 8'b0000_0011;8'b1100_0000 : r_xgmii_txc <= 8'b0000_0111;8'b1000_0000 : r_xgmii_txc <= 8'b0000_1111;default : r_xgmii_txc <= 8'b0000_0000;endcaseelse if(r_send_data)r_xgmii_txc <= 8'b0000_0000;elser_xgmii_txc <= 8'b1111_1111;
endalways @(posedge i_clk or posedge i_rst)beginif(i_rst)r_send_data <= 'd0;else if(r_pkt_cnt == r_data_len + 3 && r_tail_keep >= 8'b1111_1000)r_send_data <= 'd0;else if(r_pkt_cnt == r_data_len + 2 && r_tail_keep < 8'b1111_1000)r_send_data <= 'd0;else if(r_fifo_len_type_rden)r_send_data <= 'd1;elser_send_data <= r_send_data;
endalways @(posedge i_clk or posedge i_rst)beginif(i_rst)ro_xgmii_txd <= {8{P_FRAME_IDLE}};else if(r_pkt_cnt_3d == r_data_len + 2)case (r_tail_keep_1d)8'b1111_1111 : ro_xgmii_txd <= {r_xgmii_txd_2d[63: 8],r_crc_result[31:24]};8'b1111_1110 : ro_xgmii_txd <= {r_xgmii_txd_2d[63:16],r_crc_result[31:16]};8'b1111_1100 : ro_xgmii_txd <= {r_xgmii_txd_2d[63:24],r_crc_result[31: 8]};8'b1111_1000 : ro_xgmii_txd <= {r_xgmii_txd_2d[63:32],r_crc_result[31: 0]};8'b1111_0000 : ro_xgmii_txd <= {r_xgmii_txd_2d[63:40],r_crc_result[31: 0],P_FRAME_END};8'b1110_0000 : ro_xgmii_txd <= {r_xgmii_txd_2d[63:48],r_crc_result[31: 0],P_FRAME_END,P_FRAME_IDLE};8'b1100_0000 : ro_xgmii_txd <= {r_xgmii_txd_2d[63:56],r_crc_result[31: 0],P_FRAME_END,P_FRAME_IDLE,P_FRAME_IDLE};8'b1000_0000 : ro_xgmii_txd <= {r_crc_result[31: 0],P_FRAME_END,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE};default : ro_xgmii_txd <= {8{P_FRAME_IDLE}};endcase else if(r_pkt_cnt_3d == r_data_len + 3 && r_tail_keep >= 8'b1111_1000)case (r_tail_keep_1d) 8'b1111_1111 : ro_xgmii_txd <= {r_crc_result[23:0],P_FRAME_END,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE}; 8'b1111_1110 : ro_xgmii_txd <= {r_crc_result[15:0],P_FRAME_END,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE}; 8'b1111_1100 : ro_xgmii_txd <= {r_crc_result[7 :0],P_FRAME_END,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE}; 8'b1111_1000 : ro_xgmii_txd <= {P_FRAME_END,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE,P_FRAME_IDLE};default : ro_xgmii_txd <= {8{P_FRAME_IDLE}};endcase elsero_xgmii_txd <= r_xgmii_txd_2d;
end
三、仿真
模块AXIS_test_module会产生各种不同尾端keep的数据包,用于测试发送端的各种情况,包长为1488byte,间隔为6个时钟周期(AXIS用户端包间隔为6,则XGMII处数据间隔为2,俩者之间相差4),通过查看主机侧网卡接收带宽检查FPGA侧发送是否符合要求。
always @(posedge i_clk or posedge i_rst) beginif(i_rst)rm_axis_tkeep <= 8'hff;else if(r_send_cnt == P_SEND_LEN - 1 && w_axis_active)rm_axis_tkeep <= 8'hff;else if(r_send_cnt == P_SEND_LEN - 2 && w_axis_active)case (r_pkt_cnt)0 : rm_axis_tkeep <= 8'b1111_1111;1 : rm_axis_tkeep <= 8'b1111_1110;2 : rm_axis_tkeep <= 8'b1111_1100;3 : rm_axis_tkeep <= 8'b1111_1000;4 : rm_axis_tkeep <= 8'b1111_0000;5 : rm_axis_tkeep <= 8'b1110_0000;6 : rm_axis_tkeep <= 8'b1100_0000;7 : rm_axis_tkeep <= 8'b1000_0000;default: rm_axis_tkeep <= 8'b1111_1111;endcaseelserm_axis_tkeep <= 8'hff;
end
四、上板测速
接收带宽可达9.9G