eth_mdio.sv (3421B)
1 // Copyright 2014 Brian Swetland <swetland@frotz.net> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 `timescale 1ns / 1ps 16 17 module eth_mdio( 18 input clk, 19 20 input do_read, 21 input do_write, 22 input [31:0]txdata, 23 output [15:0]rxdata, 24 output reg busy = 0, 25 26 input i_mdio, 27 output o_mdio, 28 output t_mdio, 29 output reg mdc = 0 30 ); 31 32 parameter CLKDIV = 16; 33 34 // ST OP PHYAD REGAD TA DATA IDLE 35 // PRE 11 11 11111 11111 11 1111111111111111 Z 36 // READ 01 10 AAAAA RRRRR Z0 DDDDDDDDDDDDDDDD Z // 6 37 // WRITE 01 01 AAAAA RRRRR 10 DDDDDDDDDDDDDDDD Z // 5 38 39 // on phase entry: 40 // ------------------------- 41 // .-----. A mdc=0 shift (new data on o_mdio) 42 // | | B mdc=1 capture=i_mdio 43 // --' '-- C mdc=1 44 // A B C D D mdc=0 45 // 46 // always: o_mdio=shift[31] 47 48 typedef enum { IDLE, PHA, PHB, PHC, PHD } state_t; 49 state_t state = IDLE; 50 state_t next_state; 51 52 reg next_busy; 53 reg next_mdc; 54 55 reg [31:0]shift = 0; 56 reg [31:0]next_shift; 57 reg [4:0]count = 0; 58 reg [4:0]next_count; 59 reg [7:0]clkcnt = 0; 60 reg [7:0]next_clkcnt; 61 reg capture0 = 0; 62 reg next_capture0; 63 reg capture1 = 0; 64 reg next_capture1; 65 reg tristate = 1; 66 reg next_tristate; 67 reg op_read = 0; 68 reg next_op_read; 69 70 reg step; 71 72 assign o_mdio = shift[31]; 73 assign t_mdio = tristate; 74 assign rxdata = shift[15:0]; 75 76 always_comb begin 77 next_tristate = tristate; 78 next_capture0 = capture0; 79 next_capture1 = capture1; 80 next_clkcnt = clkcnt; 81 next_count = count; 82 next_op_read = op_read; 83 next_state = state; 84 next_shift = shift; 85 next_busy = busy; 86 next_mdc = mdc; 87 step = 0; 88 89 // while txn active, count clocks and advance 90 // phases every CLKDIV clocks 91 if (busy) begin 92 if (clkcnt == CLKDIV) begin 93 next_clkcnt = 0; 94 step = 1; 95 end else begin 96 next_clkcnt = clkcnt + 1; 97 step = 0; 98 end 99 // debounce input 100 next_capture0 = i_mdio; 101 end 102 103 case (state) 104 IDLE: if (do_read | do_write) begin 105 next_state = PHA; 106 next_mdc = 0; 107 next_busy = 1; 108 next_tristate = 0; 109 next_count = 31; 110 next_shift = txdata; 111 next_op_read = do_read; 112 end 113 PHA: if (step) begin 114 next_state = PHB; 115 next_mdc = 1; 116 // acquire debounced input 117 next_capture1 = capture0; 118 end 119 PHB: if (step) begin 120 next_state = PHC; 121 next_mdc = 1; 122 end 123 PHC: if (step) begin 124 next_state = PHD; 125 next_mdc = 0; 126 end 127 PHD: if (step) begin 128 next_shift = { shift[30:0], capture1 }; 129 if (op_read & (count == 18)) begin 130 next_tristate = 1; 131 end 132 if (count == 0) begin 133 next_state = IDLE; 134 next_tristate = 1; 135 next_busy = 0; 136 end else begin 137 next_state = PHA; 138 next_count = count - 1; 139 end 140 end 141 default: next_state = IDLE; 142 endcase 143 end 144 145 always_ff @(posedge clk) begin 146 tristate <= next_tristate; 147 capture0 <= next_capture0; 148 capture1 <= next_capture1; 149 op_read <= next_op_read; 150 clkcnt <= next_clkcnt; 151 state <= next_state; 152 shift <= next_shift; 153 count <= next_count; 154 busy <= next_busy; 155 mdc <= next_mdc; 156 end 157 158 endmodule 159