RGMII接口(KSZ9031)

概述:

RGMII的时序是时钟双沿采样,在默认的RGMII时序中,时钟(RXC/TXC)边沿与数据边沿(TXD/RXD/TX_CTL/RX_CTL)的对齐,因此,FPGA想要正确收发数据,需要对TXC或RXC进行适当的延迟。由于最高时钟为125MHz,最佳延迟为2ns。

RGMII接口(KSZ9031)_第1张图片 RGMII接口时序
 

延迟设计:

在三速网络应用中,通常的方案需要125MHz,25MHz和2.5MHz的时钟和相移90°的时钟信号。同时锁相环可能无法产生2.5MHz时钟,该方案时钟数量多达6个,需要2级选择器,不适合时序约束。另一种方案是,将输入时钟进行一定的延迟,然后用延迟后的时钟信号进行内部数据处理,最后将延迟后的时钟信号在通过一定的延迟输出,这样即可保证三速网络的应用,同时时钟数量少,适合时序分析和约束。

在如Xilinx的7z020、7z030等系列中,有IDELAY2和ODELAY2对时钟和数据进行精确延迟,可以实现三速率应用。使用IDELAY2和ODELAY2还需要一个200MHz的参考时钟和IDELAYCTRL,并将其约束成一个group。其使用方法如下:

// IDELAYCTRL is needed for calibration
(* IODELAY_GROUP = "rgmii_interface" *)
IDELAYCTRL          idelayctrl_inst 
                    (
                    .RDY                (                   ),
                    .REFCLK             (ref_clock_bufg     ),
                    .RST                (idelay_reset       )
                    );

//delay the output clock
defparam            odelay2_inst.CINVCTRL_SEL            = "FALSE"   ;
defparam            odelay2_inst.DELAY_SRC               = "CLKIN"   ;
defparam            odelay2_inst.HIGH_PERFORMANCE_MODE   = "FALSE"   ;
defparam            odelay2_inst.ODELAY_TYPE             = "FIXED"   ;
defparam            odelay2_inst.ODELAY_VALUE            = 25        ;
defparam            odelay2_inst.PIPE_SEL                = "FALSE"   ;
defparam            odelay2_inst.REFCLK_FREQUENCY        = 200.0     ;
defparam            odelay2_inst.SIGNAL_PATTERN          = "CLOCK"   ;
(* IODELAY_GROUP = "rgmii_interface" *)                  
ODELAYE2            odelay2_inst 
                    (
                    .DATAOUT            (clk_out_delay      ),
                    .C                  (1'b0               ),
                    .CE                 (1'b0               ),
                    .INC                (1'b0               ),
                    .ODATAIN            (1'b0               ), 
                    .LD                 (idelay_reset       ),
                    .LDPIPEEN           (1'b0               ),
                    .REGRST             (1'b0               ),
                    .CLKIN              (rgmii_clk          ),                    
                    .CNTVALUEIN         (5'b00000           ), 
                    .CNTVALUEOUT        (                   ),
                    .CINVCTRL           (1'b0               )                      
                    );

// delay the input clock
defparam            idelay2_inst.CINVCTRL_SEL           = "FALSE"     ;
defparam            idelay2_inst.DELAY_SRC              = "IDATAIN"   ;
defparam            idelay2_inst.HIGH_PERFORMANCE_MODE  = "FALSE"     ;
defparam            idelay2_inst.IDELAY_TYPE            = "FIXED"     ;
defparam            idelay2_inst.IDELAY_VALUE           = 25          ;
defparam            idelay2_inst.REFCLK_FREQUENCY       = 200.0       ;
defparam            idelay2_inst.PIPE_SEL               = "FALSE"     ;
defparam            idelay2_inst.SIGNAL_PATTERN         = "CLOCK"     ;
(* IODELAY_GROUP = "rgmii_interface" *)
IDELAYE2            idelay2_inst
                    (
                    .DATAOUT            (clk_in_delay       ),  // Delayed clock
                    .DATAIN             (1'b0               ),  // Data from FPGA logic
                    .C                  (1'b0               ),
                    .CE                 (1'b0               ),
                    .INC                (1'b0               ),
                    .IDATAIN            (clk_in             ),
                    .LD                 (idelay_reset       ),
                    .LDPIPEEN           (1'b0               ),
                    .REGRST             (1'b0               ),
                    .CNTVALUEIN         (5'b00000           ),
                    .CNTVALUEOUT        (                   ),
                    .CINVCTRL           (1'b0               )
                    );

在Altera的Cyclone系列中,可以通过IOE delay实现。在Assignment Editor中通过Decrease Input Delay 或则 Increase Delay to Output Pin.或其他Delay。

由于部分FPGA并不完全具备延迟调节的功能,因此,可以通过SMI接口调节PHY的内部延迟达到预计效果。其中,数据的延迟范围是-0.42~0.48ns,时钟的延迟范围是-0.9~0.96ns。

KSZ9031的SMI接口程序:

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2016.4
// Copyright (C) 1986-2016 Xilinx, Inc. All Rights Reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

module smi          (
                    reset                   ,
                    sysclk                  ,
                    start                   ,//start
                    ack                     ,//ack
                    op_mode                 ,//1-read,0-write
                    phy_addr                ,
                    reg_addr                ,
                    write_data              ,
                    read_data               ,
                    read_data_val           ,
                    done                    ,
                    mdc                     ,
                    mdi                     ,
                    mdo                     ,
                    mdoe                    
                    );
parameter           N = 50_000_000          ;//分频因子,MDC时钟频率=时钟/N;
localparam          Nmax = N-1              ;
localparam          wd = Nmax>0 ? clogb2(Nmax) : 1;

input               reset               ;
input               sysclk              ;
input               start               ;
output              ack                 ;    
input               op_mode             ;
input   [2:0]       phy_addr            ;
input   [4:0]       reg_addr            ;
input   [15:0]      write_data          ;
output  [15:0]      read_data           ;
output              read_data_val       ;
output              done                ;
output              mdc                 ;
input               mdi                 ;
output              mdo                 ;
output              mdoe                ;

reg     [15:0]      read_data           ;
reg                 mdoe = 1'b0         ;
reg                 mdo                 ;
reg                 done                ;
reg                 read_data_val       ;
reg                 mdc                 ;
reg                 ack='b0             ;

wire                mdi                 ;
reg [wd-1:0]        sys_cnt ={wd{1'b0}} ;
reg                 clk_en              ;
reg [31:0]          data_reg            ;
reg                 read_flag           ;
reg [ 7:0]          clk_cnt=8'd0        ;

//---0-----1-----2-----
//-start---x-----------
//--------ack----x-----

//clk_cnt[7]:1-work,0-idle
//clk_cnt[0]:mdc

//------------------------SMI timing-------------------------------
// preamble | sof  |  op  | phy |  reg | TA | data | IDLE
//   32x1     01      10   00aaa  rrrrr  z0   16*x    z     (read)
//   32x1     01      01   00aaa  rrrrr  10   16*x    z     (write)
//-----------------------------------------------------------------

//preamble: 128<=clk_cnt<192,
//sof     : 192<=clk_cnt<196,
//op_code : 196<=clk_cnt<200,
//phy addr: 200<=clk_cnt<210,
//reg addr: 210<=clk_cnt<220,
//TA      : 220<=clk_cnt<224,
//data    : 224<=clk_cnt<256,
//IDLE    : 0  <=clk_cnt<127,

//分频产生目标MDC时钟频率
always @ ( posedge sysclk )
    if(sys_cnt == Nmax)
        sys_cnt <= {wd{1'b0}};
    else
        sys_cnt <= sys_cnt + 1;
    
always @ ( posedge sysclk )
    clk_en <= sys_cnt == Nmax;

//握手信号,开始和应答
always @ ( posedge sysclk )
    if(clk_en)
        begin
            if(clk_cnt==0)
                begin
                    if(start)
                        clk_cnt <= 7'd1;
                end
            else
                clk_cnt <= clk_cnt + 7'd1;
        end

always @ ( posedge sysclk )
    ack <= clk_en & (clk_cnt == 0) & start;

//MDC时钟信号
always @ ( posedge sysclk )
    mdc <= clk_cnt[0] & clk_cnt[7];

//MDIO输出
always @ ( posedge sysclk )
    if(clk_cnt[7]&&clk_cnt<=8'd191)
        mdo <= 1'b1;
    else
        mdo <= data_reg[31];

//MDIO输出使能
always @ ( posedge sysclk )
    if(read_flag)
        mdoe <= (clk_cnt[7] && clk_cnt<=8'd219); 
    else
        mdoe <= clk_cnt[7];

//MDIO输入
always @ ( posedge sysclk )
    if(!mdoe & clk_cnt[0] & clk_en)
        read_data <= {read_data,mdi};

//MDIO输入数据完成      
always @ ( posedge sysclk )
    read_data_val <= (clk_en&read_flag)&(clk_cnt==8'd254);

//传输完成  
always @ ( posedge sysclk )
    done <= clk_en & (clk_cnt==8'd255);

//输出移位寄存器        
always @ ( posedge sysclk )
    if(clk_en)
        begin
            if(clk_cnt==0)
                begin
                    if(start)
                        begin
                            data_reg <= {2'b01,op_mode,!op_mode,
                                        2'b00,phy_addr,reg_addr,
                                        2'b10,write_data};
                            read_flag <= op_mode;
                        end
                end
            else if((clk_cnt[7:6]==2'b11)&clk_cnt[0])
                data_reg <= {data_reg,1'b0};
        end
        
//求log2(xin)
function integer clogb2;
    input integer depth;
        for (clogb2=0; depth>0; clogb2=clogb2+1)
            depth = depth >> 1;
endfunction

endmodule //smi

 

你可能感兴趣的:(常用芯片及协议)