本文设计思想采用明德扬至简设计法。上一篇博文中定制了自定义MAC IP的结构,在用户侧需要位宽转换及数据缓存。本文以TX方向为例,设计并验证发送缓存模块。这里定义该模块可缓存4个最大长度数据包,用户根据需求改动即可。
该模块核心是利用异步FIFO进行跨时钟域处理,位宽转换由VerilogHDL实现。需要注意的是用户数据包位宽32bit,因此包尾可能有无效字节,而转换为8bit位宽数据帧后是要丢弃无效字节的。内部逻辑非常简单,直接上代码:
1 `timescale 1ns / 1ps 2 3 // Description: MAC IP TX方向用户数据缓存及位宽转换模块 4 // 整体功能:将TX方向用户32bit位宽的数据包转换成8bit位宽数据包 5 //用户侧时钟100MHZ,MAC侧125MHZ 6 //缓存深度:保证能缓存4个最长数据包,TX方向用户数据包包括 7 //目的MAC地址 源MAC地址 类型/长度 数据 最长1514byte 8 9 10 module tx_buffer#(parameter DATA_W = 32)//位宽不能改动 11 ( 12 13 //全局信号 14 input rst_n,//保证拉低三个时钟周期,否则FIF可能不会正确复位 15 16 //用户侧信号 17 input user_clk, 18 input [DATA_W-1:0] din, 19 input din_vld, 20 input din_sop, 21 input din_eop, 22 input [2-1:0] din_mod, 23 output rdy, 24 25 //MAC侧信号 26 input eth_tx_clk, 27 output reg [8-1:0] dout, 28 output reg dout_sop, 29 output reg dout_eop, 30 output reg dout_vld 31 ); 32 33 34 reg wr_en = 0; 35 reg [DATA_W+4-1:0] fifo_din = 0; 36 reg [ (2-1):0] rd_cnt = 0 ; 37 wire add_rd_cnt ; 38 wire end_rd_cnt ; 39 wire rd_en; 40 wire [DATA_W+4-1:0] fifo_dout; 41 wire rst; 42 reg [ (2-1):0] rst_cnt =0 ; 43 wire add_rst_cnt ; 44 wire end_rst_cnt ; 45 reg rst_flag = 0; 46 wire [11 : 0] wr_data_count; 47 wire empty; 48 wire full; 49 50 /****************************************写侧*************************************************/ 51 always @(posedge user_clk or negedge rst_n)begin 52 if(rst_n==1'b0)begin 53 wr_en <= 0; 54 end 55 else if(rdy) 56 wr_en <= din_vld; 57 end 58 59 always @(posedge user_clk or negedge rst_n)begin 60 if(rst_n==1'b0)begin 61 fifo_din <= 0; 62 end 63 else begin//[35] din_sop [34] din_eop [33:32] din_mod [31:0] din 64 fifo_din <= {din_sop,din_eop,din_mod,din}; 65 end 66 end 67 68 assign rdy = wr_data_count <= 1516 && !rst && !rst_flag && !full; 69 70 /****************************************读侧*************************************************/ 71 72 always @(posedge eth_tx_clk or negedge rst_n) begin 73 if (rst_n==0) begin 74 rd_cnt <= 0; 75 end 76 else if(add_rd_cnt) begin 77 if(end_rd_cnt) 78 rd_cnt <= 0; 79 else 80 rd_cnt <= rd_cnt+1 ; 81 end 82 end 83 assign add_rd_cnt = (!empty); 84 assign end_rd_cnt = add_rd_cnt && rd_cnt == (4)-1 ; 85 86 assign rd_en = end_rd_cnt; 87 88 always @(posedge eth_tx_clk or negedge rst_n)begin 89 if(rst_n==1'b0)begin 90 dout <= 0; 91 end 92 else if(add_rd_cnt)begin 93 dout <= fifo_dout[DATA_W-1-rd_cnt*8 -:8]; 94 end 95 end 96 97 always @(posedge eth_tx_clk or negedge rst_n)begin 98 if(rst_n==1'b0)begin 99 dout_vld <= 0; 100 end 101 else if(add_rd_cnt && ((rd_cnt <= 3 - fifo_dout[33:32] && fifo_dout[34]) || !fifo_dout[34]))begin 102 dout_vld <= 1; 103 end 104 else 105 dout_vld <= 0; 106 end 107 108 always @(posedge eth_tx_clk or negedge rst_n)begin 109 if(rst_n==1'b0)begin 110 dout_sop <= 0; 111 end 112 else if(add_rd_cnt && rd_cnt == 0 && fifo_dout[35])begin 113 dout_sop <= 1; 114 end 115 else 116 dout_sop <= 0 ; 117 end 118 119 always @(posedge eth_tx_clk or negedge rst_n)begin 120 if(rst_n==1'b0)begin 121 dout_eop <= 0; 122 end 123 else if(add_rd_cnt && rd_cnt == 3 - fifo_dout[33:32] && fifo_dout[34])b