【以太网通信】MDIO 管理接口及控制器设计

news2024/12/29 14:40:03

MDIO 管理接口是以太网 MAC 和 PHY 之间的接口,用于管理/配置以太网 PHY 芯片。本文主要介绍 MDIO 管理接口定义,以及 MDIO 控制器设计。

目录

1 MDIO 管理接口

2 MDIO 控制器设计


1 MDIO 管理接口

        MDIO 管理接口是以太网 MAC 和 PHY 之间的接口,用于管理/配置以太网 PHY 芯片。MDIO 接口通过 MDC 和 MDIO 两根引脚访问 PHY 芯片的内部寄存器,详细可参考 IEEE 802.3u secton 22 中的定义。

序号名称方向功能说明
1MDC单向,MAC -> PHYMDIO 参考时钟
2MDIO双向,MAC <-> PHYMDIO 数据

        MDC 信号是由以太网 MAC 提供的参考时钟,MDIO 是数据输入/输出,与 MDC 信号同步运行的双向信号。在硬件设计上,MDIO 引脚需要一个 1.5k 欧姆的上拉电阻,以在空闲和周转期间保持 MDIO 高电平。

        多个 PHY 芯片可以共享同一个 MDIO 接口。在交换机或路由器应用中,每个 PHY 芯片会分配一个唯一的地址,并且只能通过该唯一的 PHY 地址对其进行寻址。有关管理寄存器的详细信息,请参阅 PHY 对应芯片手册。

2 MDIO 控制器设计

        MDIO 管理接口分读和写两种操作方式,读/写帧格式见下表。

        MDIO 读/写时序按照先后顺序分别为:32 位前导码、帧头、操作符、PHY 地址、寄存器地址、TA 标志,最后是 16 位数据。

可以使用有限状态机设计 MDIO 控制器,设计代码如下:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity mdio_core is
   port(
      -- System level
      sys_rst               : in std_logic;
      sys_clk               : in std_logic;

      -- MDIO control/data ports
      mdio_req              : in  std_logic;
      mdio_ack              : out std_logic;
      mdio_done             : out std_logic;
      phy_addr              : in  std_logic_vector(7 downto 0);
      reg_addr              : in  std_logic_vector(7 downto 0);
      reg_wdata             : in  std_logic_vector(15 downto 0);
      reg_rdata             : out std_logic_vector(15 downto 0);
      reg_rw                : in  std_logic;

      -- MDIO Interface
      phy_mdc               : out std_logic;
      phy_mdio_id           : in  std_logic;
      phy_mdio_od           : out std_logic;
      phy_mdio_oe           : out std_logic
   );
end entity;
architecture behav of mdio_core is
-- internal signal declarations
type state is(
   idle,
   preamble,
   start,
   op_read,
   op_write,
   write_addr,
   turn_around,
   read_data,
   write_data
);
signal pstate           : state := idle;
signal phy_mdio_id_r1   : std_logic;
signal phy_mdio_id_r2   : std_logic;
signal reg_rdwr_r       : std_logic;
signal mdc_buf          : std_logic_vector(7 downto 0);
signal buf_mdio_ack     : std_logic;
signal pulse_cnt        : std_logic_vector(5 downto 0);
signal step_cnt         : std_logic_vector(6 downto 0);
signal addr_buf         : std_logic_vector(9 downto 0);
signal reg_wdata_buf    : std_logic_vector(15 downto 0);
signal reg_rdata_buf    : std_logic_vector(15 downto 0);
---------------------------------------------------------
begin
---------------------------------------------------------
phy_mdc <= mdc_buf(mdc_buf'high);

process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      pulse_cnt <= (0 => '1', others => '0');
   elsif rising_edge(sys_clk) then
      if pstate /= idle then
         if pulse_cnt(5) = '1' then
            pulse_cnt <= (0 => '1', others => '0');
         else
            pulse_cnt <= pulse_cnt + 1;
         end if;
      else
         pulse_cnt <= (others => '0');
      end if;
   end if;
end process;

process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      mdc_buf <= (others => '1');
   elsif rising_edge(sys_clk) then
      mdc_buf <= mdc_buf(mdc_buf'high-1 downto 0) & pulse_cnt(4);
   end if;
end process;

process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      phy_mdio_id_r1 <= '1';
      phy_mdio_id_r2 <= '1';
   elsif rising_edge(sys_clk) then
      phy_mdio_id_r1 <= phy_mdio_id;
      phy_mdio_id_r2 <= phy_mdio_id_r1;
   end if;
end process;

--================================================================
mdio_ack <= buf_mdio_ack;
reg_rdata <= reg_rdata_buf;

process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      step_cnt <= (0 => '1', others => '0');
   elsif rising_edge(sys_clk) then
      case(pstate) is
         when idle => 
            step_cnt <= (0 => '1', others => '0');

         when preamble => 
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(5) = '1' then
                  step_cnt <= (0 => '1', others => '0');
               else
                  step_cnt <= step_cnt + 1;
               end if;
            end if;

         when start | op_read | op_write | turn_around => 
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(1) = '1' then
                  step_cnt <= (0 => '1', others => '0');
               else
                  step_cnt <= step_cnt + 1;
               end if;
            end if;

         when write_addr => 
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(3) = '1' and step_cnt(1) = '1' then
                  step_cnt <= (0 => '1', others => '0');
               else
                  step_cnt <= step_cnt + 1;
               end if;
            end if;

         when write_data | read_data => 
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(4) = '1' then
                  step_cnt <= (0 => '1', others => '0');
               else
                  step_cnt <= step_cnt + 1;
               end if;
            end if;

         when others => NULL;

      end case;
   end if;
end process;

process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      pstate <= idle;
      reg_rdwr_r <= '0';
      buf_mdio_ack <= '0';
      mdio_done <= '0';
   elsif rising_edge(sys_clk) then
      case(pstate) is
         when idle =>
            mdio_done <= '0';

            if mdio_req = '1' and buf_mdio_ack = '1' then
               buf_mdio_ack <= '0';
               reg_rdwr_r <= reg_rw;
               pstate <= preamble;
            elsif mdio_req = '1' and buf_mdio_ack = '0' then
               buf_mdio_ack <= '1';
               pstate <= idle;
            end if;

         when preamble =>
            if mdc_buf(1 downto 0) = "10" and step_cnt(5) = '1' then
               pstate <= start;
            else
               pstate <= preamble;
            end if;

         when start =>
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(1) = '1' and reg_rdwr_r = '1' then
                  pstate <= op_write;
               elsif step_cnt(1) = '1' and reg_rdwr_r = '0' then
                  pstate <= op_read;
               end if;
            end if;

         when op_read | op_write =>
            -- Send Read or Write OP Code
            if mdc_buf(1 downto 0) = "10" and step_cnt(1) = '1' then
               pstate <= write_addr;
            end if;

         when write_addr =>
            -- Send PHY Address and REG Address
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(3) = '1' and step_cnt(1) = '1' then
                  pstate <= turn_around;
               end if;
            else
               pstate <= write_addr;
            end if;

         when turn_around =>
            if mdc_buf(1 downto 0) = "10" then
               if step_cnt(1) = '1' and reg_rdwr_r = '1' then
                  pstate <= write_data;
               elsif step_cnt(1) = '1' and reg_rdwr_r = '0' then
                  pstate <= read_data;
               end if;
            else
               pstate <= turn_around;
            end if;

         when write_data | read_data =>
            if mdc_buf(1 downto 0) = "10" and step_cnt(4) = '1' then
               pstate <= idle;
               mdio_done <= '1';
            end if;
         
         when others => NULL;
             
      end case;
   end if;
end process;

process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      addr_buf <= (others => '0');
      reg_wdata_buf <= (others => '0');
      reg_rdata_buf <= (others => '0');
   elsif rising_edge(sys_clk) then
      case(pstate) is
         when idle => 
            if mdio_req = '1' and buf_mdio_ack = '1' then
               reg_wdata_buf <= reg_wdata;
               addr_buf <= phy_addr(4 downto 0) & reg_addr(4 downto 0);
            end if;

         when preamble => 
            reg_rdata_buf <= (others => '1');

         when write_addr => 
            if mdc_buf(1 downto 0) = "10" then
               addr_buf <= addr_buf(8 downto 0) & '0';
            end if;

         when write_data => 
            if mdc_buf(1 downto 0) = "10" then
               reg_wdata_buf <= reg_wdata_buf(14 downto 0) & '0';
            end if;

         when read_data => 
            if mdc_buf(1 downto 0)= "01" then
               reg_rdata_buf <= reg_rdata_buf(14 downto 0) & phy_mdio_id_r2;
            end if;

         when others => NULL;

      end case;
   end if;
end process;

mdio_od_pro: process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      phy_mdio_od <= '1';
   elsif rising_edge(sys_clk) then
      case(pstate) is
         when idle | read_data | preamble => 
            phy_mdio_od <= '1';

         when start | op_write =>
            case(step_cnt(1 downto 0)) is
               when "01" => phy_mdio_od <= '0';
               when "10" => phy_mdio_od <= '1';
               when others => phy_mdio_od <= '1';
            end case;

         when op_read => 
            case(step_cnt(1 downto 0)) is
               when "01" => phy_mdio_od <= '1';
               when "10" => phy_mdio_od <= '0';
               when others => phy_mdio_od <= '1';
            end case;

         when write_addr => 
            phy_mdio_od <= addr_buf(9);

         when turn_around => 
            if reg_rdwr_r = '1' then
               -- Turn around for write
               case(step_cnt(1 downto 0)) is
                  when "01" => phy_mdio_od <= '1';
                  when "10" => phy_mdio_od <= '0';
                  when others => phy_mdio_od <= '1';
               end case;
            else
               -- Turn around for read
               phy_mdio_od <= '1';
            end if;

         when write_data => 
            phy_mdio_od <= reg_wdata_buf(15);

         when others => 
            phy_mdio_od <= '1';

      end case;
   end if;
end process;

mdio_oe_pro: process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      phy_mdio_oe <= '0';
   elsif rising_edge(sys_clk) then
      case(pstate) is
         when idle | read_data =>
            phy_mdio_oe <= '0';

         when preamble | start | op_write | op_read | write_addr | write_data => 
            phy_mdio_oe <= '1';

         when turn_around =>
            if reg_rdwr_r = '1' then
                phy_mdio_oe <= '1';
            else
                phy_mdio_oe <= '0';
            end if;

         when others => 
            phy_mdio_oe <= '0';

      end case;
   end if;
end process;
end architecture;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/994012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS2010 Windows API 串口编程 (二)

目录 一串口通信基础 1.1串口通信原理与特点 1.2串口通信的传输方式 1.3串口通信的同步技术 1.4串行接口标准 二 API函数实现串口通信 2.1打开串口 2.1.1串口是否有驱动 2.1.2连接串口 2.1.3串口逻辑端口号大于10无法打开问题…

TCP原理(全网最详细)

一、确认应答&#xff08;可靠性机制&#xff09; TCP诞生的初衷就是可靠传输 可靠传输是TCP最核心的部分&#xff0c;TCP内部很多机制都是在保证可靠传输&#xff08;可以理解为发一条消息&#xff0c;上面显示已读未读&#xff0c;可靠传输就是发一条消息我知道对方是否收到…

【wordPress】WordPress删除index.php后缀【亲测有效】(手把手教学)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

BUUCTF test_your_nc

这是一题pwn入门题 使用linux中的file命令查看文件类型 file test64-bit告诉我们是64位程序 IDA64进行反编译 可以看到main函数中直接执行/bin/sh了 使用nc直接连接上面的地址 nc node4.buuoj.cn 28561然后就可以直接执行shell命令了 cat /flag

【Redis】深入探索 Redis 的数据类型 —— 哈希表 hash

文章目录 前言一、hash 类型相关命令1.1 HSET 和 HSETNX1.2 HGET 和 HMGET1.3 HKEYS、HVALS 和 HGETALL1.4 HEXISTS 和 HDEL1.5 HLEN1.6 HINCRBY 和 HINCRBYFLOAT1.7 哈希相关命令总结 二、hash 类型内部编码三、hash 类型的应用场景四、原生&#xff0c;序列化&#xff0c;哈希…

怎样去掉win11快捷方式的小箭头

前有创造注册表新值的方法,现在有了注册表加文件的方法 开始 先下载这个文件,里面有要用到的信息 下载 保存文件到电脑,并解压 有两个文件, 一个是 Remove_shortcut_arrow_icon.reg 一个是blank.ico 把第二个文件移动到 C:\Windows 文件夹, 然后点击打开文件, 如果提示是…

Windows11下Python安装GTK4

在Python下使用GTK无法直接使用pip安装PyGObject库 打卡MSYS终端&#xff0c;依次执行&#xff1a; pacman -Suy pacman -S mingw-w64-x86_64-gtk4 mingw-w64-x86_64-python3 mingw-w64-x86_64-python3-pip mingw-w64-x86_64-python3-gobject mingw-w64-x86_64-libadwaita min…

Kotlin File writeText appendText appendBytes readBytes readText

Kotlin File writeText appendText appendBytes readBytes readText import java.io.Filefun main(args: Array<String>) {val filePath "./myfile.txt"val file File(filePath)file.writeText("hello,") //如果原有文件有内容&#xff0c;将完全覆…

八大排序——快速排序

Hello&#xff0c;大家好&#xff0c;今天分享的八大排序里的快速排序&#xff0c;所谓快速排序是一个叫霍尔的人发明&#xff0c;有很多人可能会觉得为什么不叫霍尔排序&#xff0c;其中原因就是因为它快&#xff0c;快速则体现了它的特点&#xff0c;今天我们就来讲一下快速排…

李宏毅-hw5-translation-有关transformer、seq2seq的探索

一、ppt研读&#xff1a; 1.关于这个 input Embedding 的内容: 2.关于Positional Encoding&#xff1a; 二、慢慢积累&#xff0c;一点点阅读代码&#xff1a; 虽然这次的模块挺多的&#xff0c;但是&#xff0c;这样也就意味着&#xff0c;把这个内化为自己的&#xff0c;就…

【面试经典150 | 数组】合并两个有序数组

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;合并排序方法二&#xff1a;双指针方法三&#xff1a;原地操作-从前往后方法四&#xff1a;原地操作-从后往前 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章…

Axure RP 9 for Mac/Windows图文安装教程

Axure RP 9是一款一款专业级快速产品原型设计工具&#xff0c;使用它可以让用户快速、高效创建应用软件或Web网站的线框图、流程图、原型和规格说明文档。 Axure RP 9 for Mac采用了极简主义的设计&#xff0c;界面布局更加清爽简洁&#xff0c;操作也非常简单&#xff0c;并且…

系统架构设计专业技能 ·操作系统

现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reality. 点击进入系列文章目录 系统架构设计高级技能 操作系统 一、操作系统概述二、进程管理2.1 进程概念2.2 进…

VSCode中配置命令行参数

VSCode中配置命令行参数 在跑程序调试的时候&#xff0c;可以直接使用脚本运行程序&#xff0c;这个时候调试代码只能用pdb ,我觉得不太习惯&#xff0c;而且感觉不是很好&#xff0c;所以想这能不能将运行程序的脚本中的命令直接配置到vscode上&#xff0c;就有了这篇记录。 …

oCPC实践录 | oCPC转化的设计、选择、归因与成本设置(2)

在oCPC实践录 | oCPC转化的设计、选择、归因与成本设置&#xff08;1&#xff09;中初步介绍了平台侧和广告主侧的转化设计&#xff0c;这篇文章介绍平台侧和广告主怎么选择转化目标&#xff0c;归因与成本控制。 一 上周受公司增长部门的同事邀请做了一场分享和交流&#xf…

Cesium 制作风流场,制作风场可视化

需求 Cesium 制作风场 预览 分析 以下是开发中参考的几个博主的案例 博客一&#xff1a;风场热力图博客二博客三 风场数据准备&#xff0c;data.json 由于数据量过大&#xff0c;我这边只做格式展示&#xff0c;想要完整 json 文件&#xff0c;可以在我的资源里获取 […

A Yet Another Remainder The 2022 ICPC Asia Regionals Online Contest (II)

PTA | 程序设计类实验辅助教学平台 题目大意&#xff1a;有一个n位长的隐藏数x&#xff0c;从高位到低位依次标号为1到n&#xff0c;sum[i][j]表示从第i为开始每j位上的数的和&#xff0c;有q次询问&#xff0c;每次给出一个100以内除了5以外的质数p&#xff0c;问这个数%p等于…

免费版Photoshop2024智能人像磨皮插件

Portraiture是一款智能磨皮插件&#xff0c;为Photoshop和Lightroom添加一键磨皮美化功能&#xff0c;快速对照片中皮肤、头发、眉毛等部位进行美化&#xff0c;无需手动调整&#xff0c;大大提高P图效率。全新4版本&#xff0c;升级AI算法&#xff0c;并独家支持多人及全身模式…

企业架构LNMP学习笔记32

企业架构LB-服务器的负载均衡之LVS实现&#xff1a; 学习目标和内容 1&#xff09;能够了解LVS的工作方式&#xff1b; 2&#xff09;能够安装和配置LVS负载均衡&#xff1b; 3&#xff09;能够了解LVS-NAT的配置方式&#xff1b; 4&#xff09;能够了解LVS-DR的配置方式&…

基于SSM的生鲜电商系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…