千兆以太网(二)——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
https://blog.csdn.net/q1594/article/details/126584892
posted on 2025-08-21 16:19 taylorrrrrrrrrr 阅读(38) 评论(0) 收藏 举报
浙公网安备 33010602011771号