在局域网中目前物理层(Phy)芯片基本都支持10M、100M、1000M自适应系统,而且MII的版本众多,如GMII,RGMII,MII,RMII等接口。由物理层之间支持自动协商功能,MII接口也是自动适配的,MAC层如果及时掌握这些信息,对于MAC与Phy层的交互采用什么样的速度,用哪种接口,为MAC层能够自适应控制时钟和不同接口提供有力保证。
1. 网络速度识别
有两种办法可以识别网速,一种是读取Phy芯片的寄存器识别网速。经过Auto-Negotiation之后网络物理层芯片的速度已经确定,可通过读取Phy寄存器REG17,对应的地址为0x11, 如表1所示,虽然表1使用RTL8211eVB为例进行介绍,但在IEEE802.3中这个寄存器的内容是一致的。
表1 RTL8211eVB( REG 17 )PHYSR(Phy Specific Status Register )

2. RXC时钟频率检测目的
虽然读取Phy寄存器可以得到Phy层的通信速率,但具体到底使用哪一种MII接口,不同的芯片使用的接口也有所不同,因此配合RXC时钟检测得到不同的MII的RXC的时钟频率范围基本可以确定Phy应该使用哪种接口,最终配合Phy的MODE管脚可以最终设定MII的接口。如确定RXC的频率如表2,
表2 RXC时钟频率与MII接口对应关系
| RXC 时钟频率(Hz) | MII具体接口 | Mode(Pin on RTL8211eVB) |
| 125M | RGMII , GMII 1000Base-T | 0: GMII/MII
1: RGMII |
| 50M | RMII 100Base-TX | |
| 25M | MII 100Base-TX | |
| 12.5M | MII (MII dual edge)100Base-T | |
| 2.5M | MII 10Base-T | |
| 1.25M | MII (MII with dual edge) 10Base-T |
3. RXC时钟频率检测方法
由于RXC的时钟频率为检测对象,因此需要引入另外一个确定的时钟进行检测,一般采用系统时钟进行处理。本设计中系统时钟可能有如下几种情况250Mhz,200Mhz, 125Mhz, 100Mhz,50Mhz等,如果用户采用不同于上面所列的频率,可以根据如下计算进行修改。

-
-
用系统时钟生成周期为2mS的方波,高电平1mS,低电平1mS
-
在高电平1mS 期间用RXC作为时钟进行计数。
-
根据计数值判断RXC应该是表2中对应的哪种频率并编码
-
输出编码值为MAC接口的其它程序服务
-
封装接口
-
4. RXC 时钟频率检测程序
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
`timescale 1ns / 1ps module phy_detect # ( parameter MAIN_CLK = 50 ) ( input sys_clk, input rx_clk, output reg [2:0] eth_speed = 0, input sys_rst ); localparam DELAY_2MS = (MAIN_CLK == 250) ? 500_000 : // 2000_000 ns / 4ns (MAIN_CLK == 200) ? 400_000 : // 2000_000 ns / 5ns (MAIN_CLK == 125) ? 250_000 : // 2000_000 ns / 8ns (MAIN_CLK == 100) ? 200_000 : // 2000_000 ns / 10ns (MAIN_CLK == 50) ? 100_000 : 100_000; // 2000_000 ns / 20ns //================================================================== // generate 2ms wave reg [31:0] cnt = 0; reg test_line = 0; always @ (posedge sys_clk ) if(sys_rst) begin cnt <= 0; test_line <= 0; end else begin if(cnt == DELAY_2MS/2 - 1) begin cnt <= 0; test_line <= ~test_line; // 1MS end else cnt <= cnt + 1; end //================================================================== reg [2:0] rx_test_line = 0; always @ (posedge rx_clk) rx_test_line <= {rx_test_line[1:0], test_line}; reg rx_rst = 0; always @ (posedge rx_clk) rx_rst <= sys_rst; reg [31:0] rx_cnt = 0; reg [1:0] rx_st = 0; reg [2:0] eth_spd = 0; reg [2:0] temp_spd = 7; always @ (posedge rx_clk ) if(rx_rst) begin temp_spd <= 7; eth_spd <= 0; rx_cnt <= 0; rx_st <= 0; end else case (rx_st) 0: begin rx_cnt <= 0; if(rx_test_line[2:1] == 2'b01) rx_st <= 1; end 1: begin if(~&rx_cnt) rx_cnt <= rx_cnt + 1; case (rx_cnt) 124_000: eth_spd <= 4; // 125m rgmii 48_000: eth_spd <= 5; // 50m rmii 24_000: eth_spd <= 3; // 25m mii 12_000: eth_spd <= 2; // 12.5m 4800: eth_spd <= 6; // 5m rmii 2400: eth_spd <= 1; // 2.5m mii 1200: eth_spd <= 0; // 1.25m endcase if(rx_test_line[2:1] == 2'b10) rx_st <= 2; end 2: begin temp_spd <= eth_spd; if(temp_spd == eth_spd) eth_speed <= eth_spd; rx_st <= 3; end 3: begin rx_st <= 0; end endcase endmodule |
测试程序testbench.v
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
`timescale 1ns / 1ps module sim_phy_detect_inst( ); parameter MAIN_CLK = 125; wire [2:0] eth_speed; reg sys_clk = 0; reg rx_clk125 = 0; reg rx_clk50 = 0; reg rx_clk25 = 0; reg rx_clk12_5 = 0; reg rx_clk5 = 0; reg rx_clk2_5 = 0; reg rx_clk1_25 = 0; wire rx_clk; reg sys_rst = 1; reg [2:0] clk_sel = 0; always #4 sys_clk = ~sys_clk; always #4 rx_clk125 = ~rx_clk125; always #10 rx_clk50 = ~rx_clk50; always #20 rx_clk25 = ~rx_clk25; always #40 rx_clk12_5 = ~rx_clk12_5; always #100 rx_clk5 = ~rx_clk5; always #200 rx_clk2_5 = ~rx_clk2_5; always #400 rx_clk1_25 = ~rx_clk1_25; assign rx_clk = (clk_sel==1) ? rx_clk1_25 : (clk_sel==2) ? rx_clk2_5 : (clk_sel==3) ? rx_clk5 : (clk_sel==4) ? rx_clk12_5 : (clk_sel==5) ? rx_clk25 : (clk_sel==6) ? rx_clk50 : (clk_sel==7) ? rx_clk125 : 0; initial begin sys_rst = 1; clk_sel = 0; #30 sys_rst = 0; clk_sel = 1; #800_0000 clk_sel = 2; #800_0000 clk_sel = 3; #800_0000 clk_sel = 4; #800_0000 clk_sel = 5; #800_0000 clk_sel = 6; #800_0000 clk_sel = 7; #800_0000 $stop; end phy_detect # ( .MAIN_CLK (MAIN_CLK) ) phy_detect_inst ( .sys_clk (sys_clk), .rx_clk (rx_clk), .eth_speed (eth_speed), .sys_rst (sys_rst) ); endmodule |
仿真波形如图1所示,

图1 Phy speed 检测仿真波形
从图1仿真结果可以看出,能正确检测出rx_clk 频率,并能编码成不同类型。如何使用可以参照MAC IP 中发送和接收中对MII,RGMII的正确选择。