Menu Close

网速检测及Verilog实现技巧

在局域网中目前物理层(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 )

%title插图%num

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等,如果用户采用不同于上面所列的频率,可以根据如下计算进行修改。

%title插图%num

 

    • 用系统时钟生成周期为2mS的方波,高电平1mS,低电平1mS

    • 在高电平1mS 期间用RXC作为时钟进行计数。

    • 根据计数值判断RXC应该是表2中对应的哪种频率并编码

    • 输出编码值为MAC接口的其它程序服务

    • 封装接口

4. RXC 时钟频率检测程序

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Fraser Innovation Inc.
// Engineer: William Gou
// 
// Create Date: 09/22/2021 03:23:15 PM
// Design Name: 
// Module Name: phy_mode_detect
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


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 250ms 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) test_line <= 1; // 1MS
    
    if(cnt == DELAY_2MS) 
    begin
        cnt <= 0;
        test_line <= 0;
    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

5. 测试程序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所示,

%title插图%num

图1 Phy speed 检测仿真波形

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

 

Posted in FPGA, FPGA, IP开发, Vivado, 教材与教案, 文章, 资料区

发表评论

相关链接