千兆以太网(二)——MDIO接口协议

 

千兆以太网(二)——MDIO接口协议

 

`timescale 1ns / 1ps

module mdio_dri(
    input    wire             clk         ,
    input    wire             rst_n         ,
    input    wire            op_exec     ,     //触发开始信号
    input    wire             op_rh_wl    ,    //低电平写,高电平读
    input    wire     [4:0]     op_phy_addr ,     //芯片地址
    input    wire     [4:0]     op_reg_addr ,     //寄存器地址
    input     wire     [15:0]     op_wr_data     ,     //写数据
    output    reg              op_done     ,     //操作完成
    output    reg     [15:0]     op_rd_data     ,    //读出的数据
    output     reg              op_rd_ack     ,     //读应答

    output    reg               eth_mdc     ,
    inout     wire              eth_mdio     
);



localparam         SYS_CLK         =     'd50_000_000                     ;
localparam         DRI_CLK         =     'd12_500_000                      ;
localparam         DIV_CNT_MAX     =    (SYS_CLK/DRI_CLK  >> 1)  -  1     ;

localparam         IDLE             =     6'b000_001;     //初始状态
localparam         PRE             =     6'b000_010;     //前导码  32位1
localparam         START             =     6'b000_100;     //发送帧开始加操作码
localparam         ADDR             =     6'b001_000;     //发送PHY地址加寄存器地址
localparam         WR                 =     6'b010_000;     //发送TA加写入数据
localparam         RD                 =     6'b100_000;     //发送TA加接收数据

localparam        Pre             =     32'b1111_1111_1111_1111 ;    //前导码
localparam        ST                 =     2'b01                     ;    //帧开始

wire             mdio_in      ;     //mdio数据输入
reg             st_done      ;     //操作完成

reg     [5:0]     state          ;     //状态机
reg             op_rh_wl_r      ;
reg     [5:0]    op_phy_addr_r;
reg     [5:0]    op_reg_addr_r;
reg     [15:0]    op_wr_data_r ;
reg             mdio_out      ;     //mdio数据输出
reg     [9:0]     clk_cnt      ;     //时钟计数器
reg             mdio_dir      ;     //mdio数据方向指示  0输入 1输出
reg     [1:0]     op_code      ;

/********************ila模块*****************************/
wire     [255:0]     probe0;
assign probe0 = {    eth_mdc,
                    mdio_out,
                    mdio_in,
                    mdio_dir,
                    state,
                    clk_cnt,
                    op_code,
                    op_rd_data,
                    op_rh_wl,
                    op_phy_addr,
                    op_wr_data,
                    st_done,
                    op_reg_addr,
                    op_rd_ack
                };
ila_0 ila_0_inst (
    .clk(clk), // input wire clk
    .probe0(probe0) // input wire [255:0] probe0
);
/********************************************************/
//双向IO
assign eth_mdio = mdio_dir ? mdio_out : 1'bz;
assign mdio_in  = eth_mdio;


//eth_mdc     12.5MHZ    1   3时钟变化
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        eth_mdc     <=      'd1;
    end
    else if (state != IDLE && clk_cnt[0] == 1'b0) begin
        eth_mdc     <=     ~eth_mdc;
    end
end

//寄存器  当传输开始时将数据锁存起来
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        op_code         <= 'd0;
        op_phy_addr_r     <= 'd0;
        op_reg_addr_r     <= 'd0;
        op_wr_data_r    <= 'd0;
    end
    else if (op_exec == 1'b1) begin
        op_code         <= {op_rh_wl,~op_rh_wl};//OP_CODE: 2'b01(写)  2'b10(读) 
        op_phy_addr_r     <= op_phy_addr     ;
        op_reg_addr_r     <= op_reg_addr;
        op_wr_data_r    <= op_wr_data ;
    end
end

//状态转移
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        state <= IDLE ;
    end
    else  begin
        case(state)
            IDLE     :     begin
                if (op_exec == 1'b1) begin
                    state <= PRE ;
                end
            end
            PRE     :     begin
                if (st_done == 1'b1) begin
                    state <= START ;
                end
            end
            START     :     begin
                if (st_done == 1'b1) begin
                    state <= ADDR ;
                end
            end
            ADDR     :     begin
                if (st_done == 1'b1 && op_code[1] == 1'b0) begin
                    state <= WR ;
                end
                else if (st_done == 1'b1 && op_code[1] == 1'b1) begin
                    state <= RD ;
                end
            end
            WR         :     begin
                if (st_done == 1'b1) begin
                    state <= IDLE ;
                end
            end
            RD         :     begin
                if (st_done == 1'b1) begin
                    state <= IDLE ;
                end
            end
        endcase
    end
end


//状态输出
always @(posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        clk_cnt     <= 'd0;
        mdio_out     <= 1'b0;
        mdio_dir     <= 1'b0;
        op_done     <= 1'b0;
        st_done     <= 1'b0;
        op_rd_data     <= 16'b0;
    end
    else  begin
    clk_cnt  <= clk_cnt + 1'b1;
    op_done  <= 1'b0;
        case(state)
            IDLE     :     begin
                clk_cnt     <= 'd0;
                mdio_dir     <= 'd0;
                mdio_out     <= 'd1;
                op_rd_ack     <= 1'b1;
                op_done     <= 1'b0;
            end
            PRE     :     begin     //前导码  发送32位1
                mdio_dir <= 1'b1;
                mdio_out <= 1'b1;
                if (clk_cnt == 4 * 32 - 2) begin
                    st_done <= 1'b1;
                end
                else if (clk_cnt == 4 * 32 - 1) begin
                    st_done <= 1'b0;
                    clk_cnt <= 'd0;
                end
            end
            START     :     begin     //帧开始加操作码
                mdio_dir <= 1'b1;
                case(clk_cnt)
                    0     :     mdio_out     <=     1'b0         ;
                    4     :     mdio_out     <=  1'b1         ;     //两位帧开始
                    8     :     mdio_out     <=     op_code[1]     ;
                    12     :     mdio_out     <=     op_code[0]     ;
                    14  :     st_done     <=     1'b1         ;
                    15     :     begin
                        st_done     <=     1'b0     ;
                        clk_cnt     <=     'd0     ;
                    end
                endcase
            end
            ADDR     :     begin
                mdio_dir <= 1'b1;
                case(clk_cnt)
                    0     :     mdio_out     <=     op_phy_addr_r[4]     ;
                    4     :     mdio_out     <=     op_phy_addr_r[3]     ;
                    8     :     mdio_out     <=     op_phy_addr_r[2]     ;
                    12     :     mdio_out     <=     op_phy_addr_r[1]     ;
                    16     :     mdio_out     <=     op_phy_addr_r[0]     ;     //PHY地址
                    20     :     mdio_out     <=     op_reg_addr_r[4]     ;
                    24     :     mdio_out     <=     op_reg_addr_r[3]     ;
                    28     :     mdio_out     <=     op_reg_addr_r[2]     ;
                    32     :     mdio_out     <=     op_reg_addr_r[1]     ;
                    36     :     mdio_out     <=     op_reg_addr_r[0]     ;     //寄存器地址
                    38     :     st_done     <=     1'b1                 ;
                    39  :     begin
                        st_done     <=     1'b0;
                        clk_cnt     <=      'b0;
                    end
                endcase
            end
            WR         :     begin
                mdio_dir <= 1'b1;
                case(clk_cnt)
                     0     :     mdio_out     <=     1'b1              ;
                     4     :     mdio_out     <=     1'b0              ;     //写操作 不转向 10
                     8     :     mdio_out     <=     op_wr_data_r[15] ;
                     12     :     mdio_out     <=     op_wr_data_r[14] ;
                     16     :     mdio_out     <=     op_wr_data_r[13] ;
                     20     :     mdio_out     <=     op_wr_data_r[12] ;
                     24     :     mdio_out     <=     op_wr_data_r[11] ;
                     28     :     mdio_out     <=     op_wr_data_r[10] ;
                     32     :     mdio_out     <=     op_wr_data_r[9]  ;
                     36     :     mdio_out     <=     op_wr_data_r[8]  ;
                     40     :     mdio_out     <=     op_wr_data_r[7]  ;
                     44     :     mdio_out     <=     op_wr_data_r[6]  ;
                     48     :     mdio_out     <=     op_wr_data_r[5]  ;
                     52     :     mdio_out     <=     op_wr_data_r[4]  ;
                     56     :     mdio_out     <=     op_wr_data_r[3]  ;
                     60     :     mdio_out     <=     op_wr_data_r[2]  ;
                     64     :     mdio_out     <=     op_wr_data_r[1]  ;
                     68     :     mdio_out     <=     op_wr_data_r[0]  ;
                     70     :     st_done     <=     1'b1             ;
                     71     :     begin
                         st_done     <= 1'b0 ;
                         clk_cnt     <= 'd0  ;
                         mdio_dir     <= 1'b0 ;
                         op_done     <= 1'b1 ;
                         mdio_out     <= 1'b1 ;
                     end
                 endcase
            end
            RD         :     begin
                mdio_dir <= 1'b0;
                case(clk_cnt)
                    2     :                                      ;     //等待转向
                    6     :     op_rd_ack         <=     mdio_in      ;     //转向完成  应答信号拉低代表应答成功  
                    10     :     op_rd_data[15]     <=     mdio_in     ;     
                    14     :     op_rd_data[14]     <=     mdio_in     ;
                    18     :     op_rd_data[13]     <=     mdio_in     ;
                    22     :     op_rd_data[12]     <=     mdio_in     ;
                    26     :     op_rd_data[11]     <=     mdio_in     ;
                    30     :     op_rd_data[10]     <=     mdio_in     ;
                    34     :     op_rd_data[9]     <=     mdio_in     ;
                    38     :     op_rd_data[8]     <=     mdio_in     ;
                    42     :     op_rd_data[7]     <=     mdio_in     ;
                    46     :     op_rd_data[6]     <=     mdio_in     ;
                    50     :     op_rd_data[5]     <=     mdio_in     ;
                    54     :     op_rd_data[4]     <=     mdio_in     ;
                    58     :     op_rd_data[3]     <=     mdio_in     ;
                    62     :     op_rd_data[2]     <=     mdio_in     ;
                    66     :     op_rd_data[1]     <=     mdio_in     ;
                    70     :     op_rd_data[0]     <=     mdio_in     ;
                    72     :     st_done         <=     1'b1         ;
                    73     :     begin
                        st_done     <=     1'b0                 ;
                        clk_cnt     <=     'd0                   ;
                        mdio_dir     <=     'd0                 ;     //高阻
                        mdio_out     <=  'd1                 ;
                        op_done     <=     1'b1                 ;
                    end
                endcase 
            end
        endcase
    end
end
endmodule
mdio_dri

 

https://blog.csdn.net/q1594/article/details/126584892

posted on 2025-08-21 16:19  taylorrrrrrrrrr  阅读(38)  评论(0)    收藏  举报