在局域网中目前物理层(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 时钟频率检测程序
`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
`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的正确选择。