FPGA以太网篇之MDIO协议

FPGA以太网篇之MDIO协议最近开始做关于以太网接口传输的FPGA项目,算是初次接触吧,以往用的FPGA都是由PS端完成以太网的传输。刚接触以太网接口很多东西都是不熟悉的,只能通过网络查找相关的信息,事实上网上很多文章写得都很好,不过我这里也做下简单的记录,记录自己的调试过程以及一些心得。以太网的概述以太网(Etherne

大家好,欢迎来到IT知识分享网。

  最近开始做关于以太网接口传输的FPGA项目,算是初次接触吧,以往用的FPGA都是由PS端完成以太网的传输。刚接触以太网接口很多东西都是不熟悉的,只能通过网络查找相关的信息,事实上网上很多文章写得都很好,不过我这里也做下简单的记录,记录自己的调试过程以及一些心得。

  以太网的概述

  以太网(Ethernet)最早是由Xerox(施乐)公司创建的局域网组网规范,1980年DEC、Intel和Xeox三家公司联合开发了初版Ethernet规范—DIX 1.0,1982年这三家公司又推出了修改版本DIX 2.0,并将其提交给EEE 802工作组,经IEEEE成员修改并通过后,成为IEEE的正式标准,并编号为IEEE 802.3。虽然Ethernet规范和IEEE 802.3规范并不完全相同,但一般认为Ethernet和正IEEE 802.3是兼容的。

  以太网的分类有标准以太网(10Mbit/s) ,快速以太网(100Mbit/s)和千兆以太网(1000Mbit/s) 。随着以太网技术的飞速发展, 市场上也出现了万兆以太网(10Gbit/s) ,它扩展了 IEEE802.3 协议和 MAC 规范,使其技术支持 10Gbit/s 的传输速率。 在实际应用中, 千兆以太网理论上最高通信速率为 1000Mbit/s,可以胜任大部分的使用场景。

  以太网的接口类型有RJ11,RJ45,SC光纤等,而RJ45是最常见使用也是最广泛的一种以太网接口。这些接口属于以太网PHY层与线缆的连接部分,这里不做详细介绍,有需要可自行检索。

   MDIO总线

  MDIO接口,全称Management Data Input/Output,管理数据的进出,同时也被称为SMI (Serial Management Interface) 和 MIIM(Media Independent Interface Management)。MDIO接口包含在IEEE802.3协议中,是专用于以太PHY的管理的串行总线接口。

  MDIO接口主要有两个信号实现

  MDC:由MAC产生,MDIO数据要与MDC保持同步。

  MDIO:双向数据线,用于对PHY芯片的寄存器读写操作,在MDC的上升沿进行数据采集。

这个MDIO总线跟I2C总线有点像,也是时钟带数据,而且都是半双工的。不过两者还是有区别的,主要是传输的位宽不一样,MDIO要传的数据更多。

MDIO完整的通信协议如下:

FPGA以太网篇之MDIO协议

 

 

 Preamble32 位前导码,由 MAC 端发送 32 位逻辑“1”,用于同步 PHY 芯片。
STStart of Frame): 2 位帧开始信号,用 01 表示。
OPOperation Code): 2 位操作码,读: 10 写: 01
PHYADPHY Address): 5 PHY 地址,用于表示与哪个 PHY 芯片通信,因此一个 MAC 上可以连接多个 PHY 芯片。
REGADRegister Address): 5 位寄存器地址,可以表示共 32 位寄存器。
TATurnaround): 2 位转向,在读命令中, MDIO 在此时由 MAC 驱动改为 PHY 驱动,在第一个 TA位, MDIO 引脚为高阻状态,第二个 TA 位, PHY MDIO 引脚拉低,准备发送数据;在写命令中,不需要 MDIO 方向发生变化, MAC 固定输出 2’b10,随后开始写入数据。
DATA16 位数据,在读命令中, PHY 芯片将读到的对应 PHYAD REGAD 寄存器的数据写到DATA 中;在写命令中, PHY 芯片将接收到的 DATA 写入 REGAD 寄存器中。需要注意的是,在 DATA 传输的过程中,高位在前,低位在后。
IDLE:空闲状态,此时 MDIO 为无源驱动,处于高阻状态,但一般用上拉电阻使其上拉至高电平。

读时序:

FPGA以太网篇之MDIO协议

 

 写时序:

FPGA以太网篇之MDIO协议

 

       根据以上的时序我们就可以,按照时序规范写Verilog代码了。但是我们还要看看具体PHY芯片的时钟速率要求,这里的代码是偏向于通用型,因此速率为可调节。这里只做MDIO接口,具体寄存器如何配置需要编写相关驱动。

       最近花了2~3天时间把IP核给写出来的,仿真貌似没啥问题,SDK的代码挺麻烦就不再上板调试。可能会存在笔者未发现的问题,笔者只是心血来潮练练手,代码比较粗糙,好的代码是需要反复磨练修改的,下面的代码仅供参考。具体寄存器如何配置请看ctrl模块的代码,代码量不大,很多模块前面的文章已经提及过,这里不做详细说明。

  以下的代码个人认为最核心的就是MDIO_if.v模块,这个模块是把并行数据转成串行输出的过程。这里的数据发送变化在MDC的下降沿完成,输入数据的采集先是进行了2拍的时钟域同步,然后对MDC的上升沿信号进行延时可配调节,多数情况由于输出时钟与输入数据不同步存在延时需要根据实际的情况调节延时时间。另外笔者这里把上面时序中前导码及帧开始信号作为同一状态机的状态下执行,因为无论是读还是写操作,该部分都是不变的。而后面的30bit的数据则通过fifo的形式作为数据缓存,这样做能最快实现多寄存器参数配置。不过把30bit放一块可能会引起误解,读操作只有前面的12bit为有效,但代码里头是做了一些处理,对于读操作后面的18bit数据可以随便填,Turn Around位最好在软件驱动上做处理,判断为0说明通信正常否则数据无效。这里的IP核只是作为接口,具体驱动过程笔者大致流程已经在tb文件上注释,软件驱动可以参考。

顶层文件AXI4_MDIO.v:

  1 //**************************************************************************
  2 // *** file name      : AXI4_MDIO.v
  3 // *** version        : 1.0
  4 // *** Description    : AXI4_MDIO
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.4.27
  8 // *** Changes        : Initial
  9 //**************************************************************************
 10 `timescale  1ns/1ps 
 11 
 12 module AXI4_MDIO
 13 #(
 14     parameter                        FIFO_DEPTH    = 256,
 15     parameter                        DELAY         = 3,
 16     parameter                        SYS_FRE       = 200_000_000
 17 )
 18 (
 19     input        wire                i_s_axi_aclk             ,
 20     input        wire                i_s_axi_aresetn          ,
 21     input        wire    [31:0]      i_s_axi_awaddr           ,
 22     input        wire    [2:0]       i_s_axi_awprot           ,
 23     input        wire                i_s_axi_awvalid          ,
 24     output       wire                o_s_axi_awready          ,
 25     input        wire    [31:0]      i_s_axi_wdata            ,
 26     input        wire    [3:0]       i_s_axi_wstrb            ,
 27     input        wire                i_s_axi_wvalid           ,
 28     output       wire                o_s_axi_wready           ,
 29     output       wire     [1:0]      o_s_axi_bresp            ,
 30     output       wire                o_s_axi_bvalid           ,
 31     input        wire                i_s_axi_bready           ,
 32     input        wire    [31:0]      i_s_axi_araddr           ,
 33     input        wire    [2:0]       i_s_axi_arprot           ,
 34     input        wire                i_s_axi_arvalid          ,
 35     output       wire                o_s_axi_arready          ,
 36     output       wire    [31:0]      o_s_axi_rdata            ,
 37     output       wire    [1:0]       o_s_axi_rresp            ,
 38     output       wire                o_s_axi_rvalid           ,
 39     input        wire                i_s_axi_rready           ,
 40     output       wire                o_mdio_mdc               ,
 41     output       wire                o_mdio_if_o              ,
 42     output       wire                o_mdio_if_t              ,
 43     input        wire                i_mdio_if_i                
 44 );
 45 
 46     wire                        w_module_en       ;
 47     wire                        w_mdio_en         ;
 48     wire    [31:0]              w_fre_cnt         ;
 49     wire                        w_tx_ready        ;
 50     wire    [29:0]              w_tx_data         ;
 51     wire                        w_tx_valid        ;
 52     wire    [16:0]              w_rx_data         ;
 53     wire                        w_rx_valid        ;
 54     
 55 
 56 /******************************************************************************\
 57 MDIO control 
 58 \******************************************************************************/
 59     Mdio_ctrl
 60     #(
 61         .FIFO_DEPTH                (FIFO_DEPTH                )
 62     )
 63     u_Mdio_ctrl
 64     (
 65         .i_s_axi_aclk              (i_s_axi_aclk              ),
 66         .i_s_axi_aresetn           (i_s_axi_aresetn           ),
 67         .i_s_axi_awaddr            (i_s_axi_awaddr            ),
 68         .i_s_axi_awprot            (i_s_axi_awprot            ),
 69         .i_s_axi_awvalid           (i_s_axi_awvalid           ),
 70         .o_s_axi_awready           (o_s_axi_awready           ),
 71         .i_s_axi_wdata             (i_s_axi_wdata             ),
 72         .i_s_axi_wstrb             (i_s_axi_wstrb             ),
 73         .i_s_axi_wvalid            (i_s_axi_wvalid            ),
 74         .o_s_axi_wready            (o_s_axi_wready            ),
 75         .o_s_axi_bresp             (o_s_axi_bresp             ),
 76         .o_s_axi_bvalid            (o_s_axi_bvalid            ),
 77         .i_s_axi_bready            (i_s_axi_bready            ),
 78         .i_s_axi_araddr            (i_s_axi_araddr            ),
 79         .i_s_axi_arprot            (i_s_axi_arprot            ),
 80         .i_s_axi_arvalid           (i_s_axi_arvalid           ),
 81         .o_s_axi_arready           (o_s_axi_arready           ),
 82         .o_s_axi_rdata             (o_s_axi_rdata             ),
 83         .o_s_axi_rresp             (o_s_axi_rresp             ),
 84         .o_s_axi_rvalid            (o_s_axi_rvalid            ),
 85         .i_s_axi_rready            (i_s_axi_rready            ),
 86         .o_mode_enable             (w_module_en               ),
 87         .o_mdio_en                 (w_mdio_en                 ),
 88         .o_fre_cnt                 (w_fre_cnt                 ),
 89         .i_tx_req                  (w_tx_ready                ),
 90         .o_tx_data                 (w_tx_data                 ),
 91         .o_tx_valid                (w_tx_valid                ),
 92         .i_rx_data                 (w_rx_data                 ),
 93         .i_rx_valid                (w_rx_valid                )
 94 
 95     );    
 96 /******************************************************************************\
 97 MDIO interface 
 98 \******************************************************************************/
 99     MDIO_if 
100     #(
101         .DELAY                   (DELAY                     )
102     )
103     u_MDIO_if
104     (
105         .i_sys_clk               (i_s_axi_aclk              ),
106         .i_sys_rstn              (w_module_en & i_s_axi_aresetn),
107         .i_mdio_en               (w_mdio_en                 ),
108         .o_tx_req                (w_tx_ready                ),
109         .i_tx_data               (w_tx_data                 ),
110         .i_tx_valid              (w_tx_valid                ),
111         .i_fre_cnt               (w_fre_cnt                 ),
112         .o_rx_data               (w_rx_data                 ),
113         .o_rx_valid              (w_rx_valid                ),
114         .o_mdio_mdc              (o_mdio_mdc                ),
115         .o_mdio_o                (o_mdio_if_o               ),
116         .o_mdio_t                (o_mdio_if_t               ),
117         .i_mdio_i                (i_mdio_if_i               )
118     );
119 
120 endmodule

寄存器控制模块Mdio_ctrl.v

  1 //**************************************************************************
  2 // *** file name      : Mdio_ctrl.v
  3 // *** version        : 1.0
  4 // *** Description    : Mdio_ctrl
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.4.27
  8 // *** Changes        : Initial
  9 //**************************************************************************
 10 `timescale  1ns/1ps 
 11 
 12 module Mdio_ctrl
 13 #(
 14     parameter                FIFO_DEPTH = 256
 15 )
 16 (
 17     input        wire                i_s_axi_aclk            ,
 18     input        wire                i_s_axi_aresetn         ,
 19     input        wire    [31:0]      i_s_axi_awaddr          ,
 20     input        wire    [2:0]       i_s_axi_awprot          ,
 21     input        wire                i_s_axi_awvalid         ,
 22     output       wire                o_s_axi_awready         ,
 23     input        wire    [31:0]      i_s_axi_wdata           ,
 24     input        wire    [3:0]       i_s_axi_wstrb           ,
 25     input        wire                i_s_axi_wvalid          ,
 26     output       wire                o_s_axi_wready          ,
 27     output       wire     [1:0]      o_s_axi_bresp           ,
 28     output       wire                o_s_axi_bvalid          ,
 29     input        wire                i_s_axi_bready          ,
 30     input        wire    [31:0]      i_s_axi_araddr          ,
 31     input        wire    [2:0]       i_s_axi_arprot          ,
 32     input        wire                i_s_axi_arvalid         ,
 33     output       wire                o_s_axi_arready         ,
 34     output       wire    [31:0]      o_s_axi_rdata           ,
 35     output       wire    [1:0]       o_s_axi_rresp           ,
 36     output       wire                o_s_axi_rvalid          ,
 37     input        wire                i_s_axi_rready          ,
 38     output       reg                 o_mode_enable           ,
 39     output       reg                 o_mdio_en               ,
 40     output       reg     [31:0]      o_fre_cnt               ,
 41     input        wire                i_tx_req                ,
 42     output       wire    [29:0]      o_tx_data               ,
 43     output       wire                o_tx_valid              ,
 44     input        wire    [16:0]      i_rx_data               ,
 45     input        wire                i_rx_valid                
 46 );
 47 
 48     wire        [31:0]            w_ctrl_wr_addr        ;
 49     wire                          w_ctrl_wr_en          ;
 50     wire        [31:0]            w_ctrl_wr_data        ;
 51     wire        [3:0]             w_ctrl_wr_mask        ;
 52     wire        [31:0]            w_ctrl_rd_addr        ;
 53     reg         [31:0]            w_ctrl_rd_data        ;
 54     wire                          w_fifo_rstn           ;
 55     
 56     wire        [31:0]            w_reg_00_rd           ;
 57     wire        [31:0]            w_reg_01_rd           ;
 58     wire        [31:0]            w_reg_02_rd           ;
 59     wire        [31:0]            w_reg_03_rd           ;
 60     wire        [31:0]            w_reg_04_rd           ;
 61     
 62     wire                          w_tx_fifo_wr          ;
 63     wire                          w_rx_fifo_rd          ;
 64     wire        [15:0]            w_tx_wr_cnt           ;
 65     wire        [15:0]            w_rx_rd_cnt           ;
 66     wire        [15:0]            w_rx_fifo_dout        ;
 67     wire                         w_tx_fifo_empty        ;
 68     
 69     function integer log;
 70         input    [31:0]    i_data;
 71         begin
 72             for(log=0;i_data >0; log = log + 1)
 73             begin
 74                 i_data = i_data >> 1;
 75             end
 76         end
 77     endfunction    
 78 /******************************************************************************\
 79 Axi4_lite_slave interface
 80 \******************************************************************************/
 81     Mdio_Axi4_lite_slave u_Mdio_Axi4_lite_slave
 82     (
 83         .i_s_axi_aclk           (i_s_axi_aclk              ),
 84         .i_s_axi_aresetn        (i_s_axi_aresetn           ),
 85         .i_s_axi_awaddr         (i_s_axi_awaddr            ),
 86         .i_s_axi_awprot         (i_s_axi_awprot            ),
 87         .i_s_axi_awvalid        (i_s_axi_awvalid           ),
 88         .o_s_axi_awready        (o_s_axi_awready           ),
 89         .i_s_axi_wdata          (i_s_axi_wdata             ),
 90         .i_s_axi_wstrb          (i_s_axi_wstrb             ),
 91         .i_s_axi_wvalid         (i_s_axi_wvalid            ),
 92         .o_s_axi_wready         (o_s_axi_wready            ),
 93         .o_s_axi_bresp          (o_s_axi_bresp             ),
 94         .o_s_axi_bvalid         (o_s_axi_bvalid            ),
 95         .i_s_axi_bready         (i_s_axi_bready            ),
 96         .i_s_axi_araddr         (i_s_axi_araddr            ),
 97         .i_s_axi_arprot         (i_s_axi_arprot            ),
 98         .i_s_axi_arvalid        (i_s_axi_arvalid           ),
 99         .o_s_axi_arready        (o_s_axi_arready           ),
100         .o_s_axi_rdata          (o_s_axi_rdata             ),
101         .o_s_axi_rresp          (o_s_axi_rresp             ),
102         .o_s_axi_rvalid         (o_s_axi_rvalid            ),
103         .i_s_axi_rready         (i_s_axi_rready            ),
104         .o_ctrl_wr_addr         (w_ctrl_wr_addr            ),
105         .o_ctrl_wr_en           (w_ctrl_wr_en              ),
106         .o_ctrl_wr_data         (w_ctrl_wr_data            ),
107         .o_ctrl_wr_mask         (w_ctrl_wr_mask            ),
108         .o_ctrl_rd_addr         (w_ctrl_rd_addr            ),
109         .i_ctrl_rd_data         (w_ctrl_rd_data            )
110     );
111 /******************************************************************************\
112 Register 0x00~0x03
113 \******************************************************************************/        
114     always @ (posedge i_s_axi_aclk)
115     begin
116         if(~i_s_axi_aresetn)
117         begin
118             o_mode_enable     <= 'd0;
119         end
120         else if(w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h00) & w_ctrl_wr_mask[0])
121         begin
122             o_mode_enable     <= w_ctrl_wr_data[0];
123         end            
124     end
125     
126     always @ (posedge i_s_axi_aclk)
127     begin
128         if(~i_s_axi_aresetn)
129         begin
130             o_mdio_en     <= 'd0;
131         end
132         else if(w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h00) & w_ctrl_wr_mask[1])
133         begin
134             o_mdio_en     <= w_ctrl_wr_data[8];
135         end
136     end
137     
138     assign w_reg_00_rd = {23'd0,o_mdio_en,7'd0,o_mode_enable};
139 /******************************************************************************\
140 Register 0x04~0x07
141 \******************************************************************************/        
142     always @ (posedge i_s_axi_aclk)
143     begin
144         if(~i_s_axi_aresetn)
145         begin
146             o_fre_cnt[7:0]     <= 'd0;
147         end
148         else if(w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h01) & w_ctrl_wr_mask[0])
149         begin
150             o_fre_cnt[7:0]     <= w_ctrl_wr_data[7:0];
151         end            
152     end
153     always @ (posedge i_s_axi_aclk)
154     begin
155         if(~i_s_axi_aresetn)
156         begin
157             o_fre_cnt[15:8]     <= 'd0;
158         end
159         else if(w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h01) & w_ctrl_wr_mask[1])
160         begin
161             o_fre_cnt[15:8]     <= w_ctrl_wr_data[15:8];
162         end            
163     end
164     always @ (posedge i_s_axi_aclk)
165     begin
166         if(~i_s_axi_aresetn)
167         begin
168             o_fre_cnt[23:16]     <= 'd0;
169         end
170         else if(w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h01) & w_ctrl_wr_mask[2])
171         begin
172             o_fre_cnt[23:16]     <= w_ctrl_wr_data[23:16];
173         end            
174     end
175     always @ (posedge i_s_axi_aclk)
176     begin
177         if(~i_s_axi_aresetn)
178         begin
179             o_fre_cnt[31:24]     <= 'd0;
180         end
181         else if(w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h01) & w_ctrl_wr_mask[3])
182         begin
183             o_fre_cnt[31:24]     <= w_ctrl_wr_data[31:24];
184         end            
185     end
186     
187     assign w_reg_01_rd = o_fre_cnt;
188     
189 /******************************************************************************\
190 Register 0x08~0x0b
191 \******************************************************************************/
192     assign w_fifo_rstn = i_s_axi_aresetn & o_mode_enable;
193 
194     assign w_tx_fifo_wr = (w_ctrl_wr_en & (w_ctrl_wr_addr[7:2] == 6'h02) & w_ctrl_wr_mask[0]);
195     assign o_tx_valid = ~w_tx_fifo_empty;
196     Async_FIFO
197     #(
198         .WIDTH             (30                      ),
199         .DEPTH             (log(FIFO_DEPTH    )     )
200     )u_tx_FIFO
201     (
202         .i_rstn            (w_fifo_rstn             ),
203         .i_wr_clk          (i_s_axi_aclk            ),
204         .i_wr_req          (w_tx_fifo_wr            ),
205         .i_wr_data         (w_ctrl_wr_data[29:0]    ),
206         .o_wr_full         (                        ),
207         .o_wr_cnt          (w_tx_wr_cnt             ),
208         .i_rd_clk          (i_s_axi_aclk            ),
209         .i_rd_req          (i_tx_req                ),
210         .o_rd_data         (o_tx_data               ),
211         .o_rd_empty        (w_tx_fifo_empty         ),
212         .o_rd_cnt          (                        )
213     );
214     
215 /******************************************************************************\
216 Register 0x0c~0x0f
217 \******************************************************************************/
218     assign w_rx_fifo_rd = i_s_axi_arvalid & o_s_axi_arready & (i_s_axi_araddr[11:0] == 12'h00c);
219     assign w_reg_03_rd = {16'd0,w_rx_fifo_dout};
220     Async_FIFO
221     #(
222         .WIDTH             (17                      ),
223         .DEPTH             (log(FIFO_DEPTH    )     )
224     )u_rx_FIFO
225     (
226         .i_rstn            (w_fifo_rstn             ),
227         .i_wr_clk          (i_s_axi_aclk            ),
228         .i_wr_req          (i_rx_valid              ),
229         .i_wr_data         (i_rx_data               ),
230         .o_wr_full         (                        ),
231         .o_wr_cnt          (                        ),
232         .i_rd_clk          (i_s_axi_aclk            ),
233         .i_rd_req          (w_rx_fifo_rd            ),
234         .o_rd_data         (w_rx_fifo_dout          ),
235         .o_rd_empty        (                        ),
236         .o_rd_cnt          (w_rx_rd_cnt             )
237     );
238 /******************************************************************************\
239 Register 0x10~0x13
240 \******************************************************************************/          
241     assign w_reg_04_rd = {w_rx_rd_cnt,w_tx_wr_cnt};      
242 /******************************************************************************\
243 Read Register
244 \******************************************************************************/
245     always @ (*)
246     begin
247         case(w_ctrl_rd_addr[7:2])
248             6'h00    :    w_ctrl_rd_data = w_reg_00_rd        ;   
249             6'h01    :    w_ctrl_rd_data = w_reg_01_rd        ;      
250             6'h03    :    w_ctrl_rd_data = w_reg_03_rd        ;      
251             6'h04    :    w_ctrl_rd_data = w_reg_04_rd        ;   
252             default    :    w_ctrl_rd_data = 32'h00000000;
253         endcase
254     end
255     
256 endmodule

Mdio_Axi4_lite_slave.v

FPGA以太网篇之MDIO协议
FPGA以太网篇之MDIO协议

  1 //**************************************************************************
  2 // *** file name   : Mdio_Axi4_lite_slave.v
  3 // *** version     : 1.0
  4 // *** Description : Mdio_Axi4_lite_slave slave interface
  5 // *** Blogs       : https://www.cnblogs.com/WenGalois123/
  6 // *** Author      : Galois_V
  7 // *** Date        : 2022.3.29
  8 // *** Changes     :
  9 //**************************************************************************
 10 `timescale 1ns/1ps
 11 module Mdio_Axi4_lite_slave
 12 (
 13     input        wire                 i_s_axi_aclk            ,
 14     input        wire                 i_s_axi_aresetn         ,
 15     input        wire    [31:0]       i_s_axi_awaddr          ,
 16     input        wire    [2:0]        i_s_axi_awprot          ,
 17     input        wire                 i_s_axi_awvalid         ,
 18     output       reg                  o_s_axi_awready         ,
 19     input        wire    [31:0]       i_s_axi_wdata           ,
 20     input        wire    [3:0]        i_s_axi_wstrb           ,
 21     input        wire                 i_s_axi_wvalid          ,
 22     output       reg                  o_s_axi_wready          ,
 23     output       wire    [1:0]        o_s_axi_bresp           ,
 24     output       reg                  o_s_axi_bvalid          ,
 25     input        wire                 i_s_axi_bready          ,
 26     input        wire    [31:0]       i_s_axi_araddr          ,
 27     input        wire    [2:0]        i_s_axi_arprot          ,
 28     input        wire                 i_s_axi_arvalid         ,
 29     output       reg                  o_s_axi_arready         ,
 30     output       reg     [31:0]       o_s_axi_rdata           ,
 31     output       wire    [1:0]        o_s_axi_rresp           ,
 32     output       reg                  o_s_axi_rvalid          ,
 33     input        wire                 i_s_axi_rready          ,
 34     output       reg     [31:0]       o_ctrl_wr_addr          ,
 35     output       wire                 o_ctrl_wr_en            ,
 36     output       wire    [31:0]       o_ctrl_wr_data          ,
 37     output       wire    [3:0]        o_ctrl_wr_mask          ,
 38     output       reg     [31:0]       o_ctrl_rd_addr          ,
 39     input        wire    [31:0]       i_ctrl_rd_data
 40 );
 41 
 42     reg                                r_wr_en;
 43     reg                                r_rd_en;
 44     wire                               w_raddr_en;
 45 /******************************************************************************\
 46 Write Address operation
 47 \******************************************************************************/
 48     always@(posedge i_s_axi_aclk)
 49     begin
 50         if(~i_s_axi_aresetn)
 51         begin
 52             r_wr_en <= 1'b1;
 53         end
 54         else if(o_ctrl_wr_en)
 55         begin
 56             r_wr_en <= 1'b0;
 57         end
 58         else if(o_s_axi_bvalid & i_s_axi_bready)
 59         begin
 60             r_wr_en <= 1'b1;
 61         end
 62     end
 63 
 64     always@(posedge i_s_axi_aclk)
 65     begin
 66         if(~i_s_axi_aresetn)
 67         begin
 68             o_s_axi_awready <= 'd0;
 69         end
 70         else if(~o_s_axi_awready & i_s_axi_wvalid & i_s_axi_awvalid & r_wr_en)
 71         begin
 72             o_s_axi_awready <= 1'b1;
 73         end
 74         else
 75         begin
 76             o_s_axi_awready <= 'd0;
 77         end
 78     end
 79 
 80     always@(posedge i_s_axi_aclk)
 81     begin
 82         if(~i_s_axi_aresetn)
 83         begin
 84             o_ctrl_wr_addr <= 'd0;
 85         end
 86         else if(~o_s_axi_awready & i_s_axi_awvalid & i_s_axi_wvalid)
 87         begin
 88             o_ctrl_wr_addr <= i_s_axi_awaddr;
 89         end
 90     end
 91 /******************************************************************************\
 92 Write data operation
 93 \******************************************************************************/
 94     always@(posedge i_s_axi_aclk)
 95     begin
 96         if(~i_s_axi_aresetn)
 97         begin
 98             o_s_axi_wready <= 'd0;
 99         end
100         else if(~o_s_axi_wready & i_s_axi_wvalid & i_s_axi_awvalid & r_wr_en)
101         begin
102             o_s_axi_wready <= 1'b1;
103         end
104         else
105         begin
106             o_s_axi_wready <= 'd0;
107         end
108     end
109 
110     assign o_ctrl_wr_data = i_s_axi_wdata;
111     assign o_ctrl_wr_mask = i_s_axi_wstrb;
112     assign o_ctrl_wr_en = o_s_axi_awready & i_s_axi_awvalid & i_s_axi_wvalid & o_s_axi_wready;
113 
114 /******************************************************************************\
115 write response and response
116 \******************************************************************************/
117     always@(posedge i_s_axi_aclk)
118     begin
119         if(~i_s_axi_aresetn)
120         begin
121             o_s_axi_bvalid <= 'd0;
122         end
123         else if(~o_s_axi_bvalid & o_ctrl_wr_en)
124         begin
125             o_s_axi_bvalid <= 1'b1;
126         end
127         else if(o_s_axi_bvalid & i_s_axi_bready)
128         begin
129             o_s_axi_bvalid <= 'd0;
130         end
131     end
132 
133 /******************************************************************************\
134 Read Address operation
135 \******************************************************************************/
136     always@(posedge i_s_axi_aclk)
137     begin
138         if(~i_s_axi_aresetn)
139         begin
140             r_rd_en <= 1'b1;
141         end
142         else if(w_raddr_en)
143         begin
144             r_rd_en <= 1'b0;
145         end
146         else if(o_s_axi_rvalid & i_s_axi_rready)
147         begin
148             r_rd_en <= 1'b1;
149         end
150     end
151 
152     always@(posedge i_s_axi_aclk)
153     begin
154         if(~i_s_axi_aresetn)
155         begin
156             o_s_axi_arready <= 'd0;
157         end
158         else if(~o_s_axi_arready & i_s_axi_arvalid & r_rd_en)
159         begin
160             o_s_axi_arready <= 1'b1;
161         end
162         else
163         begin
164             o_s_axi_arready <= 'd0;
165         end
166     end
167 
168     always@(posedge i_s_axi_aclk)
169     begin
170         if(~i_s_axi_aresetn)
171         begin
172             o_ctrl_rd_addr <= 'd0;
173         end
174         else if(~o_s_axi_arready & i_s_axi_arvalid)
175         begin
176             o_ctrl_rd_addr <= i_s_axi_araddr;
177         end
178     end
179 
180     assign w_raddr_en = o_s_axi_arready & i_s_axi_arvalid & (~o_s_axi_rvalid);
181 /******************************************************************************\
182 Read data operation
183 \******************************************************************************/
184     always@(posedge i_s_axi_aclk)
185     begin
186         if(~i_s_axi_aresetn)
187         begin
188             o_s_axi_rvalid <= 'd0;
189         end
190         else if(w_raddr_en)
191         begin
192             o_s_axi_rvalid <= 1'b1;
193         end
194         else if(o_s_axi_rvalid & i_s_axi_rready)
195         begin
196             o_s_axi_rvalid <= 'd0;
197         end
198     end
199 
200     always@(posedge i_s_axi_aclk)
201     begin
202         if(~i_s_axi_aresetn)
203         begin
204             o_s_axi_rdata <= 'd0;
205         end
206         else if(w_raddr_en)
207         begin
208             o_s_axi_rdata <= i_ctrl_rd_data;
209         end
210     end
211 
212 
213     assign o_s_axi_rresp = 2'b00;
214     assign o_s_axi_bresp = 2'b00;
215 
216 endmodule

View Code

Async_FIFO.v

FPGA以太网篇之MDIO协议
FPGA以太网篇之MDIO协议

  1 //**************************************************************************
  2 // *** file name      : Async_FIFO.v
  3 // *** version        : 1.0
  4 // *** Description    : Async_FIFO
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.4.14
  8 // *** Changes        : Initial
  9 //**************************************************************************
 10 `timescale 1ns/1ps
 11 module Async_FIFO
 12 #(
 13     parameter                WIDTH = 8,        //data width
 14     parameter                DEPTH = 3         //data depth,2**DEPTH
 15 )
 16 (
 17     input                          i_rstn,
 18     input                          i_wr_clk,
 19     input                          i_wr_req,
 20     input            [WIDTH-1:0]   i_wr_data,
 21     output    reg                  o_wr_full,
 22     output    reg    [DEPTH-1:0]   o_wr_cnt,
 23     input                          i_rd_clk,
 24     input                          i_rd_req,
 25     output           [WIDTH-1:0]   o_rd_data,
 26     output    reg                  o_rd_empty,
 27     output    reg    [DEPTH-1:0]   o_rd_cnt
 28 );
 29 
 30     wire    [DEPTH-1:0]      w_wr_addr;
 31     wire    [DEPTH-1:0]      w_rd_addr;
 32     wire    [DEPTH:0]        w_wr_binnext;
 33     wire    [DEPTH:0]        w_wr_graynext;
 34     wire    [DEPTH:0]        w_rd_binnext;
 35     wire    [DEPTH:0]        w_rd_graynext;
 36     wire                     w_wr_full;
 37     wire                     w_rd_empty;
 38     reg      [WIDTH-1:0]     map[0:(1<<DEPTH)-1];
 39     reg      [DEPTH:0]       r_wr_bin;
 40     reg      [DEPTH:0]       r_rd_bin;
 41     reg      [DEPTH:0]       r_wr_index;
 42     reg      [DEPTH:0]       r_rd_index;
 43     reg      [DEPTH:0]       r_wr_index1;
 44     reg      [DEPTH:0]       r_rd_index1;
 45     reg      [DEPTH:0]       r_wr_index2;
 46     reg      [DEPTH:0]       r_rd_index2;
 47     reg      [DEPTH:0]       r_addr_diff;
 48 /******************************************************************************\
 49 Dual port ram
 50 \******************************************************************************/
 51     assign o_rd_data = map[w_rd_addr];
 52 
 53     always@(posedge i_wr_clk)
 54     begin
 55         if(~o_wr_full&i_wr_req)
 56         begin
 57             map[w_wr_addr] <= i_wr_data;
 58         end
 59     end
 60 /******************************************************************************\
 61 Sync index
 62 \******************************************************************************/
 63     always@(posedge i_wr_clk or negedge i_rstn)
 64     begin
 65         if(~i_rstn)
 66         begin
 67             r_wr_index1 <= 'd0;
 68             r_wr_index2 <= 'd0;
 69         end
 70         else
 71         begin
 72             r_wr_index1 <= r_rd_index;
 73             r_wr_index2 <= r_wr_index1;
 74         end
 75     end
 76     always@(posedge i_rd_clk or negedge i_rstn)
 77     begin
 78         if(~i_rstn)
 79         begin
 80             r_rd_index1 <= 'd0;
 81             r_rd_index2 <= 'd0;
 82         end
 83         else
 84         begin
 85             r_rd_index1 <= r_wr_index;
 86             r_rd_index2 <= r_rd_index1;
 87         end
 88     end
 89 /******************************************************************************\
 90 Generate full signal
 91 \******************************************************************************/
 92     assign w_wr_addr     = r_wr_bin[DEPTH-1:0];
 93     assign w_wr_binnext  = r_wr_bin + (~o_wr_full & i_wr_req);
 94     assign w_wr_graynext = w_wr_binnext ^ (w_wr_binnext>>1);
 95     assign w_wr_full     = (w_wr_graynext == {~r_wr_index2[DEPTH:DEPTH-1], r_wr_index2[DEPTH-2:0]});
 96 
 97     always@(posedge i_wr_clk or negedge i_rstn)
 98     begin
 99         if(~i_rstn)
100         begin
101             r_wr_bin     <= 'd0;
102             r_wr_index     <= 'd0;
103         end
104         else
105         begin
106             r_wr_bin    <= w_wr_binnext;
107             r_wr_index    <= w_wr_graynext;
108         end
109     end
110     always@(posedge i_wr_clk or negedge i_rstn)
111     begin
112         if(~i_rstn)
113         begin
114             o_wr_full <= 'd0;
115         end
116         else
117         begin
118             o_wr_full <= w_wr_full;
119         end
120     end
121 /******************************************************************************\
122 Generate  empty signal
123 \******************************************************************************/
124     assign w_rd_addr     = r_rd_bin[DEPTH-1:0];
125     assign w_rd_binnext  = r_rd_bin + (~o_rd_empty & i_rd_req);
126     assign w_rd_graynext = w_rd_binnext ^ (w_rd_binnext>>1);
127     assign w_rd_empty      = (w_rd_graynext == r_rd_index2);
128 
129     always@(posedge i_rd_clk or negedge i_rstn)
130     begin
131         if(~i_rstn)
132         begin
133             r_rd_bin     <= 'd0;
134             r_rd_index     <= 'd0;
135         end
136         else
137         begin
138             r_rd_bin    <= w_rd_binnext;
139             r_rd_index    <= w_rd_graynext;
140         end
141     end
142     always@(posedge i_rd_clk or negedge i_rstn)
143     begin
144         if(~i_rstn)
145         begin
146             o_rd_empty <= 1'b1;
147         end
148         else
149         begin
150             o_rd_empty <= w_rd_empty;
151         end
152     end
153 
154 /******************************************************************************\
155 Write and read data cnt
156 \******************************************************************************/
157 
158     always @(*)
159     begin
160         if(~i_rstn)
161         begin
162             r_addr_diff = 'd0;
163         end
164         else if(w_wr_addr > w_rd_addr)
165         begin
166             r_addr_diff = w_wr_addr - w_rd_addr;
167         end
168         else
169         begin
170             r_addr_diff = {1'b0,{(DEPTH - 1){1'b0}}} - w_rd_addr + w_wr_addr;
171         end
172     end
173 
174     always@(posedge i_wr_clk or negedge i_rstn)
175     begin
176         if(~i_rstn)
177         begin
178             o_wr_cnt <= 'd0;
179         end
180         else
181         begin
182             o_wr_cnt <= r_addr_diff[DEPTH-1:0];
183         end
184     end
185 
186     always@(posedge i_rd_clk or negedge i_rstn)
187     begin
188         if(~i_rstn)
189         begin
190             o_rd_cnt <= 'd0;
191         end
192         else
193         begin
194             o_rd_cnt <= r_addr_diff[DEPTH-1:0];
195         end
196     end
197 endmodule

View Code

MDIO接口模块MDIO_if.v

  1 //**************************************************************************
  2 // *** file name   : MDIO_if.v
  3 // *** version     : 1.0
  4 // *** Description : MDIO interface
  5 // *** Blogs       : https://www.cnblogs.com/WenGalois123/
  6 // *** Author      : Galois_V
  7 // *** Date        : 2022.4.27
  8 // *** Changes     :
  9 //**************************************************************************
 10 `timescale  1ns/1ps 
 11 module MDIO_if
 12 #(
 13     parameter                    DELAY = 3        
 14 )
 15 (
 16     input                        i_sys_clk         ,
 17     input                        i_sys_rstn        ,
 18     input                        i_mdio_en         ,
 19     output    reg                o_tx_req          ,
 20     input        [29:0]          i_tx_data         ,
 21     input                        i_tx_valid        ,
 22     input        [31:0]          i_fre_cnt         ,
 23     output       [16:0]          o_rx_data         ,
 24     output                       o_rx_valid        ,
 25     output                       o_mdio_mdc        ,
 26     output                       o_mdio_o          ,
 27     output                       o_mdio_t          ,
 28     input                        i_mdio_i        
 29 );
 30     localparam                  MDIO_IDLE     = 5'b00001,
 31                                 MDIO_FRMOP    = 5'b00010,
 32                                 MDIO_WROP     = 5'b00100,
 33                                 MDIO_TXDATA   = 5'b01000,
 34                                 MDIO_RXDATA   = 5'b10000;
 35     
 36     reg            [31:0]            r_freq_sum;
 37     reg                              r_clk_gen;
 38     reg                              r_tx_en;
 39     reg                              r_rx_en;
 40     reg            [1:0]             r_mdio_op;
 41     reg            [4:0]             r_cur_state;
 42     reg            [4:0]             r_next_state;
 43     reg            [6:0]             r_tx_bit_cnt;
 44     reg            [4:0]             r_rx_bit_cnt;
 45     reg            [63:0]            r_tx_data;
 46     reg            [2:0]             r_mdio_i;
 47     reg            [DELAY-1:0]       r_mdio_mdc;
 48     reg            [17:0]            r_rx_data;
 49     
 50     wire                        w_mdc_neg;
 51     wire                        w_mdc_pos;
 52     wire                        w_clk_gen_neg;
 53     wire                        w_deal_en;
 54     wire                        w_tx_bit_end;
 55     wire                        w_mdc_dly_pos;
 56     wire                        w_rx_bit_end;
 57 /******************************************************************************\
 58 generate mdc
 59 \******************************************************************************/
 60     
 61     always@(posedge i_sys_clk)
 62     begin
 63         if((~i_sys_rstn) | (~i_mdio_en))
 64         begin
 65             r_freq_sum <= 'd0;
 66         end
 67         else
 68         begin
 69             r_freq_sum <= r_freq_sum + i_fre_cnt;
 70         end
 71     end
 72     
 73     always@(posedge i_sys_clk)
 74     begin
 75         if(~i_sys_rstn)
 76         begin
 77             r_clk_gen <= 'd0;
 78         end
 79         else
 80         begin
 81             r_clk_gen <= r_freq_sum[31];
 82         end
 83     end
 84     
 85     assign w_mdc_pos = ~r_clk_gen & r_freq_sum[31];
 86     assign w_clk_gen_neg = (~r_freq_sum[31] & r_clk_gen);
 87     assign w_mdc_neg = w_clk_gen_neg;
 88     
 89     always@(posedge i_sys_clk)
 90     begin
 91         if(~i_sys_rstn)
 92         begin
 93             r_mdio_op <= 'd0;
 94         end
 95         else if(w_deal_en)
 96         begin
 97             r_mdio_op <= i_tx_data[29:28];
 98         end
 99     end
100     
101     assign w_deal_en = i_tx_valid & o_tx_req;
102 /******************************************************************************\
103 State machine
104 \******************************************************************************/    
105     
106     always@(posedge i_sys_clk)
107     begin
108         if(~i_sys_rstn)
109         begin
110             r_cur_state <= MDIO_IDLE;
111         end
112         else
113         begin
114             r_cur_state <= r_next_state;
115         end
116     end
117     
118     always@(*)
119     begin
120         case(r_cur_state)
121             MDIO_IDLE:
122                 if(w_clk_gen_neg & i_tx_valid)
123                 begin
124                     r_next_state = MDIO_FRMOP;
125                 end
126                 else
127                 begin
128                     r_next_state = MDIO_IDLE;
129                 end
130             MDIO_FRMOP:
131                 if(r_tx_bit_cnt == 46)
132                 begin
133                     r_next_state = MDIO_WROP;
134                 end
135                 else
136                 begin
137                     r_next_state = MDIO_FRMOP;
138                 end
139             MDIO_WROP:
140                 if(r_mdio_op == 2'b01)
141                 begin
142                     r_next_state = MDIO_TXDATA;
143                 end
144                 else if((r_mdio_op==2'b10)&&(r_tx_bit_cnt == 47))
145                 begin
146                     r_next_state = MDIO_RXDATA;
147                 end
148             MDIO_TXDATA:
149                 if(r_tx_bit_cnt == 65)
150                 begin
151                     r_next_state = MDIO_IDLE;
152                 end
153                 else
154                 begin
155                     r_next_state = MDIO_TXDATA;
156                 end
157             MDIO_RXDATA:
158                 if(r_rx_bit_cnt == 18)
159                 begin
160                     r_next_state = MDIO_IDLE;
161                 end
162                 else 
163                 begin
164                     r_next_state = MDIO_RXDATA;
165                 end
166             default: r_next_state = MDIO_IDLE;
167         endcase
168     end
169 
170     always@(*)
171     begin
172         case(r_cur_state)
173             MDIO_FRMOP:
174                 begin 
175                     r_tx_en = 1'b1;
176                 end
177             MDIO_TXDATA:
178                 begin
179                     r_tx_en = 1'b1;
180                 end
181             MDIO_WROP:
182                 begin
183                     r_tx_en = 1'b1;
184                 end
185             default:
186                 begin
187                     r_tx_en = 1'b0;
188                 end
189         endcase
190     end
191     
192     always@(*)
193     begin
194         case(r_cur_state)
195             MDIO_RXDATA:
196                 begin
197                     r_rx_en = 1'b1;
198                 end
199             default:
200                 begin
201                     r_rx_en = 1'b0;
202                 end
203         endcase
204     end
205     
206     always@(*)
207     begin
208         case(r_cur_state)
209             MDIO_IDLE:
210                 if(w_clk_gen_neg & i_tx_valid)
211                 begin
212                     o_tx_req <= 1'b1;
213                 end
214                 else
215                 begin
216                     o_tx_req <= 1'b0;
217                 end
218             default:
219                 begin
220                     o_tx_req = 1'b0;
221                 end
222         endcase
223     end
224 /******************************************************************************\
225 TX 
226 \******************************************************************************/
227     always@(posedge i_sys_clk)
228     begin
229         if(~i_sys_rstn)
230         begin
231             r_tx_data <= 'd0;
232         end
233         else if(w_deal_en)
234         begin
235             r_tx_data <= {32'hffffffff,2'b01,i_tx_data};
236         end
237         else if(w_mdc_neg)
238         begin
239             r_tx_data <= {r_tx_data[62:0],1'b0};
240         end
241     end
242 
243     always@(posedge i_sys_clk)
244     begin
245         if(~i_sys_rstn | w_tx_bit_end | w_deal_en)
246         begin
247             r_tx_bit_cnt <= 'd1;
248         end
249         else if(w_mdc_neg)
250         begin
251             r_tx_bit_cnt <= r_tx_bit_cnt + 1'b1;
252         end
253     end
254     assign w_tx_bit_end = (r_tx_bit_cnt == 7'd65) ? 1'b1 : 1'b0;
255     
256 /******************************************************************************\
257 RX 
258 \******************************************************************************/    
259     always@(posedge i_sys_clk)
260     begin
261         if(~i_sys_rstn)
262         begin
263             r_mdio_i <= 'd0;
264         end
265         else
266         begin
267             r_mdio_i <= {r_mdio_i[1:0],i_mdio_i};
268         end
269     end
270     
271     always@(posedge i_sys_clk)
272     begin
273         if(~i_sys_rstn)
274         begin
275             r_mdio_mdc[DELAY-1:0] <= 'd0;
276         end
277         else
278         begin
279             r_mdio_mdc <= {r_mdio_mdc[DELAY-2:0],r_clk_gen};
280         end
281     end
282     assign w_mdc_dly_pos = r_rx_en ? (~r_mdio_mdc[DELAY-1] & r_mdio_mdc[DELAY-2]) : 1'b0;
283     
284     always@(posedge i_sys_clk)
285     begin
286         if(~i_sys_rstn | w_rx_bit_end | w_deal_en)
287         begin
288             r_rx_bit_cnt <= 'd1;
289         end
290         else if(w_mdc_dly_pos)
291         begin
292             r_rx_bit_cnt <= r_rx_bit_cnt + 1'b1;
293         end
294     end
295     assign w_rx_bit_end = (r_rx_bit_cnt == 5'd18) ? 1'b1 : 1'b0;
296     
297     always@(posedge i_sys_clk)
298     begin
299         if(~i_sys_rstn)
300         begin
301             r_rx_data <= 'd0;
302         end
303         else if(w_mdc_dly_pos)
304         begin
305             r_rx_data <= {r_rx_data[16:0],r_mdio_i[2]};
306         end
307     end
308     assign o_rx_valid = w_rx_bit_end;
309     assign o_rx_data = r_rx_data[16:0];
310 /******************************************************************************\
311 MDIO three states interface
312 \******************************************************************************/    
313     assign o_mdio_mdc      = r_clk_gen;
314     assign o_mdio_o        = r_tx_data[63];
315     assign o_mdio_t        = ~r_tx_en;
316     
317     
318 endmodule

最后是总的仿真文件MDIO_sim.v

  1 //**************************************************************************
  2 // *** file name      : MDIO_sim.sv
  3 // *** version        : 1.0
  4 // *** Description    : MDIO IP core testbech
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.4.27
  8 // *** Changes        :
  9 //**************************************************************************
 10 `timescale 1ns/1ps
 11 
 12 module MDIO_sim();
 13 
 14 /******************************************************************************\
 15 Define AXI4-lite interface port
 16 \******************************************************************************/
 17     wire                w_axi_aclk       ;
 18     wire                w_axi_aresetn    ;
 19 
 20     wire    [31:0]      w_axi_awaddr     ;
 21     wire                w_axi_awvalid    ;
 22     wire                w_axi_awready    ;
 23 
 24     wire    [31:0]      w_axi_wdata      ;
 25     wire    [3:0]       w_axi_wstrb      ;
 26     wire                w_axi_wvalid     ;
 27     wire                w_axi_wready     ;
 28 
 29     wire    [1:0]       w_axi_bresp      ;
 30     wire                w_axi_bvalid     ;
 31     wire                w_axi_bready     ;
 32 
 33     wire    [31:0]      w_axi_araddr     ;
 34     wire                w_axi_arvalid    ;
 35     wire                w_axi_arready    ;
 36 
 37     wire    [31:0]      w_axi_rdata      ;
 38     wire    [1:0]       w_axi_rresp      ;
 39     wire                w_axi_rvalid     ;
 40     wire                w_axi_rready     ;
 41 
 42 /******************************************************************************\
 43 Instantiate AXI4-lite master module
 44 \******************************************************************************/
 45     m_axi4_lite_if u_m_axi4_lite_if
 46     (
 47         .o_sys_clk                 (w_axi_aclk              ),
 48         .o_sys_rstn                (w_axi_aresetn           ),
 49         .o_m_axi_awaddr            (w_axi_awaddr            ),
 50         .o_m_axi_awvalid           (w_axi_awvalid           ),
 51         .i_m_axi_awready           (w_axi_awready           ),
 52         .o_m_axi_wdata             (w_axi_wdata             ),
 53         .o_m_axi_wstrb             (w_axi_wstrb             ),
 54         .o_m_axi_wvalid            (w_axi_wvalid            ),
 55         .i_m_axi_wready            (w_axi_wready            ),
 56         .i_m_axi_bresp             (w_axi_bresp             ),
 57         .i_m_axi_bvalid            (w_axi_bvalid            ),
 58         .o_m_axi_bready            (w_axi_bready            ),
 59         .o_m_axi_araddr            (w_axi_araddr            ),
 60         .o_m_axi_arvalid           (w_axi_arvalid           ),
 61         .i_m_axi_arready           (w_axi_arready           ),
 62         .i_m_axi_rdata             (w_axi_rdata             ),
 63         .i_m_axi_rresp             (w_axi_rresp             ),
 64         .i_m_axi_rvalid            (w_axi_rvalid            ),
 65         .o_m_axi_rready            (w_axi_rready            )
 66     );
 67 
 68 /******************************************************************************\
 69 Instantiate AXI4-lite slave IP core
 70 \******************************************************************************/
 71     wire                        w_mdio_mdc;
 72     wire                        w_mdio_if_o;
 73     wire                        w_mdio_if_t;
 74     wire                        w_mdio_if_i;
 75     AXI4_MDIO u_AXI4_MDIO
 76     (
 77         .i_s_axi_aclk            (w_axi_aclk               ),
 78         .i_s_axi_aresetn         (w_axi_aresetn            ),
 79         .i_s_axi_awaddr          (w_axi_awaddr             ),
 80         .i_s_axi_awprot          ('d0                      ),
 81         .i_s_axi_awvalid         (w_axi_awvalid            ),
 82         .o_s_axi_awready         (w_axi_awready            ),
 83         .i_s_axi_wdata           (w_axi_wdata              ),
 84         .i_s_axi_wstrb           (w_axi_wstrb              ),
 85         .i_s_axi_wvalid          (w_axi_wvalid             ),
 86         .o_s_axi_wready          (w_axi_wready             ),
 87         .o_s_axi_bresp           (w_axi_bresp              ),
 88         .o_s_axi_bvalid          (w_axi_bvalid             ),
 89         .i_s_axi_bready          (w_axi_bready             ),
 90         .i_s_axi_araddr          (w_axi_araddr             ),
 91         .i_s_axi_arprot          ('d0                      ),
 92         .i_s_axi_arvalid         (w_axi_arvalid            ),
 93         .o_s_axi_arready         (w_axi_arready            ),
 94         .o_s_axi_rdata           (w_axi_rdata              ),
 95         .o_s_axi_rresp           (w_axi_rresp              ),
 96         .o_s_axi_rvalid          (w_axi_rvalid             ),
 97         .i_s_axi_rready          (w_axi_rready             ),
 98         .o_mdio_mdc              (w_mdio_mdc               ),
 99         .o_mdio_if_o             (w_mdio_if_o              ),
100         .o_mdio_if_t             (w_mdio_if_t              ),
101         .i_mdio_if_i             (w_mdio_if_i              )
102     );
103     reg        [16:0]        r_tx_data = 17'h080a0;
104 
105     always@(negedge w_mdio_mdc)
106     begin
107         if(u_AXI4_MDIO.u_MDIO_if.r_rx_en)
108         begin
109             r_tx_data <= r_tx_data << 1;
110         end
111     end
112     assign w_mdio_if_i = r_tx_data[16];
113 
114 /******************************************************************************\
115 Perform the steps of IP core in sequence
116 \******************************************************************************/
117     reg  [31:0] r_cpu_rd_data;
118     initial r_cpu_rd_data = 0;
119 
120 
121     initial
122     begin
123         $display("start");
124         #2000;
125         u_m_axi4_lite_if.arm_write_data(32'h00000000,32'h00000001,4'h1);//enable the IP module
126         #200;
127         u_m_axi4_lite_if.arm_write_data(32'h00000004,32'd42949673,4'hf);//set the MDIO clk as 1MHz
128         #200;
129         u_m_axi4_lite_if.arm_write_data(32'h00000000,32'h00000101,4'h3);//enable MDIO bus
130         #200;
131         u_m_axi4_lite_if.arm_write_data(32'h00000008,{2'd0,2'b01,5'h01,5'h05,2'b10,16'h5a5a},4'hf);//write operation,phy chip addr:5'h01 reg addr:5'h05
132         #200;
133         u_m_axi4_lite_if.arm_write_data(32'h00000008,{2'd0,2'b01,5'h01,5'h15,2'b10,16'h80a0},4'hf);//write operation,phy chip addr:5'h01 reg addr:5'h15
134         #200;
135         u_m_axi4_lite_if.arm_write_data(32'h00000008,{2'd0,2'b10,5'h01,5'h15,2'b00,16'h80a0},4'hf);//read operation,phy chip addr:5'h01 reg addr:5'h15
136         #200000;
137         u_m_axi4_lite_if.arm_read_data(32'h0000000c,r_cpu_rd_data);
138 
139         $display("sim complete");
140     end
141 
142 
143 endmodule

m_axi4_lite_if.sv:

FPGA以太网篇之MDIO协议
FPGA以太网篇之MDIO协议

  1 //**************************************************************************
  2 // *** file name      : m_axi4_lite_if.sv
  3 // *** version        : 1.0
  4 // *** Description    : axi4_lite_if master
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.4.7
  8 // *** Changes        :
  9 //**************************************************************************
 10 `timescale 1ns/1ps
 11 
 12 module m_axi4_lite_if
 13 (
 14     output    reg                    o_sys_clk,
 15     output    reg                    o_sys_rstn,
 16 
 17     output    reg    [31:0]          o_m_axi_awaddr,
 18     output    reg                    o_m_axi_awvalid,
 19     input                            i_m_axi_awready,
 20 
 21     output    reg    [31:0]          o_m_axi_wdata,
 22     output    reg    [3:0]           o_m_axi_wstrb,
 23     output    reg                    o_m_axi_wvalid,
 24     input                            i_m_axi_wready,
 25 
 26     input        [1:0]               i_m_axi_bresp,
 27     input                            i_m_axi_bvalid,
 28     output    reg                    o_m_axi_bready,
 29 
 30     output    reg    [31:0]          o_m_axi_araddr,
 31     output    reg                    o_m_axi_arvalid,
 32     input                            i_m_axi_arready,
 33 
 34     input        [31:0]              i_m_axi_rdata,
 35     input        [1:0]               i_m_axi_rresp,
 36     input                            i_m_axi_rvalid,
 37     output    reg                    o_m_axi_rready
 38 );
 39 
 40     parameter               SYS_CLK = 100_000_000  ,
 41                             TIME_1S = 1000_000_000 ;
 42 
 43 
 44     real clk_cnt = TIME_1S/SYS_CLK;
 45 /******************************************************************************\
 46 产生仿真环境需要的时钟与复位信号,这里的时钟信号为100MHz
 47 \******************************************************************************/
 48     initial//所有的initial模块都是并行的,initial模块的语句是按顺序执行的。
 49     begin
 50         o_sys_clk = 0;
 51         o_sys_rstn = 0;
 52         #1000;
 53         o_sys_rstn = 1;
 54     end
 55 
 56     always #(clk_cnt/2) o_sys_clk = ~o_sys_clk;
 57 
 58 /******************************************************************************\
 59 先初始化axi4-lite的输出量信号
 60 \******************************************************************************/
 61     initial
 62     begin
 63         o_m_axi_awaddr         = 'd0;
 64         o_m_axi_awvalid        = 'd0;
 65         o_m_axi_wdata          = 'd0;
 66         o_m_axi_wstrb          = 'd0;
 67         o_m_axi_wvalid         = 'd0;
 68         o_m_axi_bready         = 'd0;
 69         o_m_axi_araddr         = 'd0;
 70         o_m_axi_arvalid        = 'd0;
 71         o_m_axi_rready         = 'd0;
 72     end
 73 /******************************************************************************\
 74 通过axi4-lite总线写数据,写task
 75 \******************************************************************************/
 76     task arm_write_data
 77     (
 78         input    [31:0]    i_addr ,
 79         input    [31:0]    i_data ,
 80         input    [3:0]     i_byte_en
 81     );
 82     begin
 83         @(posedge o_sys_clk)
 84         begin
 85             o_m_axi_awaddr  = i_addr;
 86             o_m_axi_awvalid = 1'b1;
 87             o_m_axi_wdata   = i_data;
 88             o_m_axi_wstrb   = i_byte_en;
 89             o_m_axi_wvalid  = 1'b1;
 90             o_m_axi_bready  = 1'b1;
 91         end
 92         @(posedge o_sys_clk);
 93         begin
 94             while(~(i_m_axi_awready & i_m_axi_wready))    //
 95             begin
 96                 @(posedge o_sys_clk)
 97                 begin
 98                     o_m_axi_awvalid = 1'b0;
 99                     o_m_axi_wvalid = 1'b0;
100                 end
101             end
102         end
103 
104         @(posedge o_sys_clk)
105         begin
106             while(~i_m_axi_bvalid)
107             begin
108                 @(posedge o_sys_clk)
109                 begin
110                     if(i_m_axi_bresp != 2'b00)
111                     begin
112                         $display("write fail");
113                     end
114                 end
115             end
116         end
117 
118         o_m_axi_bready = 1'b0;
119     end
120     endtask
121 
122 
123 /******************************************************************************\
124 通过axi4-lite总线读数据,读task
125 \******************************************************************************/
126     task arm_read_data
127     (
128         input    [31:0]    i_addr,
129         output    [31:0]    o_rdata
130     );
131     begin
132         @(posedge o_sys_clk)
133         begin
134             o_m_axi_araddr = i_addr;
135             o_m_axi_arvalid = 1'b1;
136             o_m_axi_rready = 1'b1;
137         end
138 
139         @(posedge o_sys_clk)
140         begin
141             while(~i_m_axi_arready)
142             begin
143                 @(posedge o_sys_clk)
144                 begin
145                     o_m_axi_arvalid = 1'b0;
146                 end
147             end
148         end
149         @(posedge o_sys_clk)
150         begin
151             o_rdata = i_m_axi_rdata;
152             while(~i_m_axi_rvalid)
153             begin
154                 if(i_m_axi_rresp!=2'b00)
155                 $display("read fail");
156             end
157         end
158 
159         o_m_axi_rready = 1'b0;
160     end
161     endtask
162 
163 endmodule

View Code

sim.do

 1 #删除work工作目录
 2 file delete -force work
 3     
 4 #设置uvm环境变量,指定uvm的dpi位置
 5 set UVM_DPI_HOME D:/modeltech64_10.5/uvm-1.1d/win64
 6 
 7 #创建work工作目录
 8 vlib work
 9 
10 #vlog表示编译 *.sv表示do文件同级路径下所有.sv文件 -L表示添加库文件
11 vlog -L mtiAvm -L mtiOvm -L mtiUvm -L mtiUPF *.sv
12 
13 #编译源文件,包含覆盖率测试
14 vlog -cover sbctf -coveropt 3 ../rtl/*.v
15 
16 #执行仿真,打开覆盖率窗口,不使能优化,调用uvm库uvm_dpi,利用UVM_TEST_NAME从命令行中寻找测试用例的名字,创建它的实例并运行
17 vsim -coverage -novopt -c -sv_lib $UVM_DPI_HOME/uvm_dpi work.MDIO_sim +UVM_TESTNAME=case0
18 
19 #观察DUT的信号波形
20 add wave -position insertpoint sim:/MDIO_sim/u_AXI4_MDIO/*
21 view -new wave
22 add wave -position insertpoint sim:/MDIO_sim/u_AXI4_MDIO/u_MDIO_if/*
23 
24 run 10ms

仿真的信号如下:

MDIO_if模块

FPGA以太网篇之MDIO协议

IP核封装后:

FPGA以太网篇之MDIO协议

MDIO配置phy芯片IP核就此完成。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30408.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信