以太网——MDIO(SMI)接口的FPGA实现

news2024/11/23 0:53:08

  在 MAC 与 PHY 之间,有一个配置接口,即 MDIO(也称 SMI,Serial Management Interface),可以配置 PHY 的工作模式、获取 PHY 芯片的工作状态等。本文以 PHY 芯片 B50610 为例,实现 MDIO 接口,以实现对传输速度、接口类型的自协商。

  MDIO 包含 2 根信号线:

  • MDC,由 MAC 侧提供给 PHY 的时钟信号,最大 12.5MHz;
  • MDIO,inout,数据线

  MDIO 的通信协议如下

在这里插入图片描述

MDIO 的帧构成如下:

  • Preamble,32 位前导码,MAC 端发送 32 位逻辑 1,以同步 PHY 芯片
  • Start of Frame,帧开始信号,2’b01
  • Operation Code,操作码,2‘b01 表示进行写操作,2’b10 表示读操作
  • PHY Address,5 位 PHY 地址,用于决定和哪个 PHY 芯片通信
  • Register Address,5 位寄存器地址,最大可表示 32 个寄存器
  • Turn Around,2 位转向,在读操作中,MDIO 在此时由 MAC 驱动改为 PHY 驱动,在第一个 TA 位,MDIO 引脚为高阻状态,第二个 TA 位,PHY 将 MDIO 引脚拉低,准备发送数据,MAC 端此两位设为高阻,若 MAC 检测到第二位非低电平,表明对方无应答,可通过这个判断是否读取失败;在写操作中,不需要 MDIO 方向发生变化,MAC 固定输出 2’b10
  • Data,16bit 数据
  • IDLE,空闲状态下,一般将 MDIO 上拉

  MDIO 的时序如下

在这里插入图片描述

可以看到,PHY 芯片在 MDC 上升沿读取数据,并在上升沿给出数据。因此 MAC 端须在 MDC 下降沿给出数据,而读取数据在上升沿、下降沿均可(不过需要注意,由于 MDIO_DELAY 最大可达 50ns,若使用高于 10M 的 MDC 频率,则下降沿读取可能出现问题,因此推荐 MAC 侧在 MDC 上升沿读取数据)。

  由于一次 MDIO 读写,均由 32bit 前导码,以及 32bit 读写比特流组成,因此可以方便地使用一个 5bit 计数器进行计数,然后根据当前的计数值操作 MDIO。Verilog 代码如下

/* 
 * file			: smi_top.v
 * author		: 今朝无言
 * date			: 2023-05-31
 * version		: v2.0
 * description	: SMI(MDIO)Read/Write
 */
module smi_top(
input				clk,
input				rst_n,

output				mdc,
inout				mdio,

input		[4:0]	phy_addr,
input		[4:0]	reg_addr,

input		[15:0]	wrdata,
input				write_req,
//req 信号上升沿有效,应维持至少一个 mdc 周期,可在检测到 busy 后再置低,下同

output	reg	[15:0]	rddata,
input				read_req,

output	reg			busy,
output	reg			rd_failed	//对方无应答
);

parameter	CLK_FREQ	= 100_000_000;
parameter	MDC_FREQ	= 100_000;

clkdiv #(.N(CLK_FREQ/MDC_FREQ))
clkdiv_inst(
	.clk_in		(clk),
	.clk_out	(mdc)
);

reg				mdio_buf;
reg				link;			//MAC是否占有MDIO控制权

assign	mdio	= link? mdio_buf : 1'bz;

//-----------------edge detect---------------------------
wire	write_req_pe;
reg		write_req_d0;
reg		write_req_d1;

wire	read_req_pe;
reg		read_req_d0;
reg		read_req_d1;

always @(posedge mdc) begin
	write_req_d0	<= write_req;
	write_req_d1	<= write_req_d0;

	read_req_d0		<= read_req;
	read_req_d1		<= read_req_d0;
end

assign	write_req_pe	= write_req_d0 & (~write_req_d1);
assign	read_req_pe		= read_req_d0 & (~read_req_d1);

//---------------------FSM-------------------------------
localparam	S_IDLE	= 8'h01;
localparam	S_ARB	= 8'h02;
localparam	S_PRE_R	= 8'h04;
localparam	S_RD	= 8'h08;
localparam	S_PRE_W	= 8'h10;
localparam	S_WR	= 8'h20;
localparam	S_STOP	= 8'h40;

localparam	ST		= 2'b01;
localparam	R_OP	= 2'b10;
localparam	W_OP	= 2'b01;
localparam	W_TA	= 2'b10;

reg		[4:0]	cnt;	//一次读写正好 32bit Pre + 32bit WR/RD

reg		[7:0]	state		= S_IDLE;
reg		[7:0]	next_state;

always @(posedge mdc or negedge rst_n) begin
	if(~rst_n) begin
		state	<= S_IDLE;
	end
	else begin
		state	<= next_state;
	end
end

always @(*) begin
	case(state)
	S_IDLE: begin
		next_state	<= S_ARB;
	end
	S_ARB: begin
		if(write_req_pe) begin		//写优先
			next_state	<= S_PRE_W;
		end
		else if(read_req_pe) begin
			next_state	<= S_PRE_R;
		end
		else begin
			next_state	<= S_ARB;
		end
	end
	S_PRE_R: begin
		if(cnt==5'd31) begin
			next_state	<= S_RD;
		end
		else begin
			next_state	<= S_PRE_R;
		end
	end
	S_RD: begin
		if(cnt==5'd31) begin
			next_state	<= S_STOP;
		end
		else begin
			next_state	<= S_RD;
		end
	end
	S_PRE_W: begin
		if(cnt==5'd31) begin
			next_state	<= S_WR;
		end
		else begin
			next_state	<= S_PRE_W;
		end
	end
	S_WR: begin
		if(cnt==5'd31) begin
			next_state	<= S_STOP;
		end
		else begin
			next_state	<= S_WR;
		end
	end
	S_STOP: begin
		next_state	<= S_IDLE;
	end
	default: begin
		next_state	<= S_IDLE;
	end
	endcase
end

//cnt
always @(posedge mdc) begin
	case(state)
	S_IDLE: begin
		cnt		<= 5'd0;
	end
	S_PRE_R, S_RD, S_PRE_W, S_WR: begin
		cnt		<= cnt + 1'b1;
	end
	default: begin
		cnt		<= 5'd0;
	end
	endcase
end

//mdio_buf
always @(negedge mdc) begin		//必须下降沿发送数据
	case(state)
	S_IDLE: begin
		mdio_buf	<= 1'b1;
	end
	S_PRE_R, S_PRE_W: begin
		mdio_buf	<= 1'b1;
	end
	S_WR: begin
		case(cnt)
		5'd0: mdio_buf	<= ST[1];
		5'd1: mdio_buf	<= ST[0];

		5'd2: mdio_buf	<= W_OP[1];
		5'd3: mdio_buf	<= W_OP[0];

		5'd4: mdio_buf	<= phy_addr[4];
		5'd5: mdio_buf	<= phy_addr[3];
		5'd6: mdio_buf	<= phy_addr[2];
		5'd7: mdio_buf	<= phy_addr[1];
		5'd8: mdio_buf	<= phy_addr[0];

		5'd9: mdio_buf	<= reg_addr[4];
		5'd10: mdio_buf	<= reg_addr[3];
		5'd11: mdio_buf	<= reg_addr[2];
		5'd12: mdio_buf	<= reg_addr[1];
		5'd13: mdio_buf	<= reg_addr[0];

		5'd14: mdio_buf	<= W_TA[1];
		5'd15: mdio_buf	<= W_TA[0];

		5'd16: mdio_buf	<= wrdata[15];
		5'd17: mdio_buf	<= wrdata[14];
		5'd18: mdio_buf	<= wrdata[13];
		5'd19: mdio_buf	<= wrdata[12];
		5'd20: mdio_buf	<= wrdata[11];
		5'd21: mdio_buf	<= wrdata[10];
		5'd22: mdio_buf	<= wrdata[9];
		5'd23: mdio_buf	<= wrdata[8];
		5'd24: mdio_buf	<= wrdata[7];
		5'd25: mdio_buf	<= wrdata[6];
		5'd26: mdio_buf	<= wrdata[5];
		5'd27: mdio_buf	<= wrdata[4];
		5'd28: mdio_buf	<= wrdata[3];
		5'd29: mdio_buf	<= wrdata[2];
		5'd30: mdio_buf	<= wrdata[1];
		5'd31: mdio_buf	<= wrdata[0];

		default: begin
			mdio_buf	<= 1'b1;
		end
		endcase
	end
	S_RD: begin
		case(cnt)
		5'd0: mdio_buf	<= ST[1];
		5'd1: mdio_buf	<= ST[0];

		5'd2: mdio_buf	<= R_OP[1];
		5'd3: mdio_buf	<= R_OP[0];

		5'd4: mdio_buf	<= phy_addr[4];
		5'd5: mdio_buf	<= phy_addr[3];
		5'd6: mdio_buf	<= phy_addr[2];
		5'd7: mdio_buf	<= phy_addr[1];
		5'd8: mdio_buf	<= phy_addr[0];

		5'd9: mdio_buf	<= reg_addr[4];
		5'd10: mdio_buf	<= reg_addr[3];
		5'd11: mdio_buf	<= reg_addr[2];
		5'd12: mdio_buf	<= reg_addr[1];
		5'd13: mdio_buf	<= reg_addr[0];

		default: begin
			mdio_buf	<= 1'b1;
		end
		endcase
	end
	default: begin
		mdio_buf	<= 1'b1;
	end
	endcase
end

//data_tmp
reg		[15:0]	data_tmp;

always @(posedge mdc) begin	//在上升沿读数据
	case(state)
	S_RD: begin
		case(cnt)
		5'd15: rd_failed	<= mdio;	//若对方应答,此处会被拉低,否则失败
		5'd16: data_tmp[15]	<= mdio;
		5'd17: data_tmp[14]	<= mdio;
		5'd18: data_tmp[13]	<= mdio;
		5'd19: data_tmp[12]	<= mdio;
		5'd20: data_tmp[11]	<= mdio;
		5'd21: data_tmp[10]	<= mdio;
		5'd22: data_tmp[9]	<= mdio;
		5'd23: data_tmp[8]	<= mdio;
		5'd24: data_tmp[7]	<= mdio;
		5'd25: data_tmp[6]	<= mdio;
		5'd26: data_tmp[5]	<= mdio;
		5'd27: data_tmp[4]	<= mdio;
		5'd28: data_tmp[3]	<= mdio;
		5'd29: data_tmp[2]	<= mdio;
		5'd30: data_tmp[1]	<= mdio;
		5'd31: data_tmp[0]	<= mdio;
		default: begin
			data_tmp	<= data_tmp;
		end
		endcase
	end
	default: begin
		data_tmp	<= data_tmp;
	end
	endcase
end

//rddata
always @(posedge mdc) begin
	case(state)
	S_STOP: begin
		rddata	<= data_tmp;
	end
	default: begin
		rddata	<= rddata;
	end
	endcase
end

//link
always @(posedge mdc) begin
	case(state)
	S_PRE_W, S_PRE_R, S_WR: begin
		link	<= 1'b1;
	end
	S_RD: begin
		if(cnt<=13) begin
			link	<= 1'b1;
		end
		else begin
			link	<= 1'b0;
		end
	end
	default: begin
		link	<= 1'b0;
	end
	endcase
end

//busy
always @(posedge mdc) begin
	case(state)
	S_IDLE, S_ARB: begin
		busy	<= 1'b0;
	end
	S_PRE_R, S_RD, S_PRE_W, S_WR, S_STOP: begin
		busy	<= 1'b1;
	end
	default: begin
		busy	<= busy;
	end
	endcase
end

endmodule

测试

  B50610 的 PHY 地址通过 PHYA0、TEST3、TEST2 三个引脚进行配置

在这里插入图片描述

比如我们想查看下网络是否连接、当前操作速度等信息,可以查看 Auxiliary Status Summary Register 寄存器,地址 0x19。各比特含义如下

在这里插入图片描述

  测试代码略.

  连接路由器(100BASE)后:

在这里插入图片描述

可以看到网络已连接(bit2=1),自协商已完成(bit15=1),当前网速 100M 全双工(bit10:8=0b101)。

拔掉网线:

在这里插入图片描述

可以检测到网络断开(bit2=0),正在自协商过程中(bit15=0)。

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

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

相关文章

NUC972 Linux学习 NAND FLASH 制作系统

设备&#xff1a;NUC972DF61YC 使用的虚拟机环境&#xff1a;官方提供的NUC972DF61YC - Nuvoton 板载NAND FLASH&#xff0c;前期主要学习怎么uboot、ubootspl、uimage、env烧录。官方配置没有使用rootfs在flash中&#xff0c;所以数据会掉电丢失。即文件系统在RAM中。 这里仅…

基于Jackson实现API接口数据脱敏

一、背景 用户的一些敏感数据&#xff0c;例如手机号、邮箱、身份证等信息&#xff0c;在数据库以明文存储&#xff08;加密存储见《基于Mybatis-Plus拦截器实现MySQL数据加解密》&#xff09;&#xff0c; 但在接口返回数据给浏览器&#xff08;或三方客户端&#xff09;时&a…

设计一个支持并发的前端接口缓存

目录​​​​​​​ 缓存池 并发缓存 问题 思考 优化&#x1f914; 总结 最后 缓存池 缓存池不过就是一个map&#xff0c;存储接口数据的地方&#xff0c;将接口的路径和参数拼到一块作为key&#xff0c;数据作为value存起来罢了&#xff0c;这个咱谁都会。 const cach…

DTU和MQTT网关优缺点

目前市面上有两种设备实现Modbus转MQTT网关。网关式、DTU式。 钡铼技术网关内部进行转换 网关式 优点&#xff1a; 1、通讯模块和MCU分开&#xff0c;通讯模块只做通讯功能&#xff0c;协议转换有单独主控MCU&#xff0c;“硬转换”&#xff1b; 2、数据点是通过映射到主控…

【严重】GitLab 存在代码执行漏洞

漏洞描述 GitLab 是一款基于Git的代码托管、版本控制、协作开发平台。 GitLab CE/EE 15.4 至 15.9.6 版本&#xff0c;15.10 至 15.10.5 版本和 15.11 至 15.11.1 版本存在代码执行漏洞。在某些条件下&#xff0c;实例上的任何GitLab用户都可以使用GraphQL端点将恶意运行程序…

HTML框架-----标签(下)

目录 前言&#xff1a; 5.容器标签 效果&#xff1a;​编辑 6.列表标签 (1)无序 &#xff08;2&#xff09;有序 7.图片标签 8.超链接标签 &#xff08;1&#xff09;链接资源 &#xff08;2&#xff09;超链接锚点 前言&#xff1a; 今天我们接着来继续学习html的标签&am…

五重要性能测试指标揭秘!并发数、TPS、QPS、响应时间和资源利用率,了解性能瓶颈,优化系统高负载下的处理能力

目录 前言&#xff1a; 1. 并发数 2. TPS 3. QPS 4. 响应时间 5. 资源利用率 总结 前言&#xff1a; 在高并发的场景下&#xff0c;我们需要考虑如何优化我们的应用程序&#xff0c;以确保它可以承受大量的请求并且在给定时间内响应。对于这个问题&#xff0c;性能测试就…

字节码文件结构

目录 1、概述 2、JVM的两个无关性 3、Class字节码文件的结构 1、基本存储单位 2、字节码文件数据结构 3、Class文件格式 4、魔数与Class文件的版本 5、常量池 6、访问标志 7、类索引、父类索引与接口索引集合 8、字段表集合 9、方法表集合 10、属性表集合 11、总…

centos7.9升级rockylinux8.8

前言 查看centos的版本 &#xff0c;我这台服务器是虚拟机,下面都是模拟实验 升级前一定要把服务器上配置文件&#xff0c;数据等进行备份 [rootlocalhost ~]#cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]#uname -a Linux jenkins_ser…

Ubuntu常见基本问题

系列文章目录 文章目录 系列文章目录一、复制粘贴问题二、无法全屏问题三、设置为中文四、时间同步问题1、选择时区2、同步网络时间 一、复制粘贴问题 开启终端&#xff1a;ctrlaltt卸载已有工具 sudo apt-get autoremove open-vm-tools安装工具open-vm-tools sudo apt-get …

echarts的y轴数据显示过长占不下,内容截取,鼠标hover上去显示全部

初始效果&#xff1a; 优化后的效果&#xff1a; 优化点&#xff1a;控制了y轴显示字数&#xff0c;鼠标hover上去显示全部 主要实现思路参考了这位同学的文章&#xff1a;https://www.cnblogs.com/liuboren/p/9040622.html 我是用vue实现的&#xff0c;因为我需要一个页面中…

各算法/协议知识理论笔记(fpga)

一、利用fifo对3行数据求和 需要2个fifo保存第0行和第1行的数据&#xff0c;如下图 比如有20行数据&#xff0c;则将一行一行的输给fifo2, fifo2出来的数据再给fifo1.当fifo和fifo1有数据时&#xff0c;在准备给 fifo2输入新的一行数据时&#xff0c;同时读出fifo2&#xff0c;…

Linux进程间通信(信号)

信号发送 信号是 Linux 系统响应某些条件而产生的一个事件&#xff0c;接收到该信号的进程会执行相应的操作。 信号的产生有三种方式&#xff1a; &#xff08;1)由硬件产生&#xff0c;如从键盘输入 CtrlC 可以终止当前进程 &#xff08;2)由其他进程发送&#xff0c;如可在 …

PostgreSQL修炼之道之高可用性方案设计(十七)

目录 20 高可用性方案设计&#xff08;二&#xff09; 20.2 基于共享存储的高可用方案 20.2.1 SAN存储的方案 20.2.2 DRBD的方案 20.3 WAL日志同步或流复制同步的方案 20.3.1 持续复制归档的standby的方法 20.3.2 异步流复制的方案 20.3.3 基于同步流复制方案 20.4 基于…

国内外低代码开发平台发展情况如何?

国内外低代码开发平台发展情况如何&#xff1f;之前有些过很多关于低代码的内容&#xff0c;这篇就来详细梳理下国内外低代码开发平台发展现状。 关于低代码解读看这篇>>什么是低代码&#xff08;Low-Code&#xff09;&#xff1f;关于低代码平台看这篇>>主流的开…

业务高速增长,如祺出行如何用腾讯云消息队列 RocketMQ 应对挑战

导语 作为广汽集团旗下的智慧出行平台&#xff0c;如祺出行上线四年时间&#xff0c;用户规模和订单量保持高速增长。在过去的2022年&#xff0c;如祺出行平台累计注册用户突破1800万&#xff0c;同比增长64%&#xff0c;年度订单总量超7000万&#xff0c;同比增长52%。 高速…

【MCS-51】串行I/O接口及其通信

我们知道MCS-51中有很多的引脚&#xff0c;这些引脚很多一般都是用作输入或者输出口&#xff0c;其中有两个引脚P3.0和P3.1比较特殊&#xff0c;我们常将其用作串行通信的数据发送和接收端TXD、RXD。 目录 &#x1f431;通信方式 &#x1f431;串行通信的传输方式和数据通信…

python笔记17_实例演练_二手车折旧分析p2

…… 书接上文 4.车辆等级维度 探查车龄为5年的车辆&#xff0c;折旧价值与车辆等级的关系。 # 筛选出车龄为5的数据创建新表 data_age5 data[data[age] 5] data_age5 # 分组聚合计算均值 data_car_level data_age5.groupby(car_level_name)[lowest_price].mean().reset…

16.2:岛屿数量问题

文章目录 岛屿数量问题方法一&#xff1a;采用递归的方法方法二&#xff1a;使用并查集的方法&#xff08;map&#xff09;方法三&#xff1a;使用并查集的方法&#xff08;数组&#xff09; 岛屿数量问题 测试链接&#xff1a;https://leetcode.com/problems/number-of-islan…

大数据:分布式计算,MapReduce,hadoop的计算组件,hive是sql分布式计算框架,底层就是基于MapReduce的

大数据&#xff1a;分布式计算&#xff0c;MapReduce&#xff0c;hadoop的计算组件&#xff0c;hive是sql分布式计算框架&#xff0c;底层就是基于MapReduce的 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学…