大家好,欢迎来到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完整的通信协议如下:
Preamble: 32 位前导码,由 MAC 端发送 32 位逻辑“1”,用于同步 PHY 芯片。
ST(Start of Frame): 2 位帧开始信号,用 01 表示。
OP(Operation Code): 2 位操作码,读: 10 写: 01。
PHYAD(PHY Address): 5 位 PHY 地址,用于表示与哪个 PHY 芯片通信,因此一个 MAC 上可以连接多个 PHY 芯片。
REGAD(Register Address): 5 位寄存器地址,可以表示共 32 位寄存器。
TA(Turnaround): 2 位转向,在读命令中, MDIO 在此时由 MAC 驱动改为 PHY 驱动,在第一个 TA位, MDIO 引脚为高阻状态,第二个 TA 位, PHY 将 MDIO 引脚拉低,准备发送数据;在写命令中,不需要 MDIO 方向发生变化, MAC 固定输出 2’b10,随后开始写入数据。
DATA: 16 位数据,在读命令中, PHY 芯片将读到的对应 PHYAD 的 REGAD 寄存器的数据写到DATA 中;在写命令中, PHY 芯片将接收到的 DATA 写入 REGAD 寄存器中。需要注意的是,在 DATA 传输的过程中,高位在前,低位在后。
IDLE:空闲状态,此时 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
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
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:
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模块
IP核封装后:
MDIO配置phy芯片IP核就此完成。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30408.html