zynq-sandbox

old FPGA projects for ZYNQ
git clone http://frotz.net/git/zynq-sandbox.git
Log | Files | Refs | README

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