commit 336e64a11c05c140869de796d479a5dfe7036c10
parent 527a60a15a47846538e2f0532a1941877c9c2ab0
Author: Brian Swetland <swetland@frotz.net>
Date: Tue, 22 Jul 2014 07:39:01 -0700
ethernet mdio master
Diffstat:
2 files changed, 219 insertions(+), 0 deletions(-)
diff --git a/hdl/eth_mdio.sv b/hdl/eth_mdio.sv
@@ -0,0 +1,159 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns / 1ps
+
+module eth_mdio(
+ input clk,
+
+ input do_read,
+ input do_write,
+ input [31:0]txdata,
+ output [15:0]rxdata,
+ output reg busy = 0,
+
+ input i_mdio,
+ output o_mdio,
+ output t_mdio,
+ output reg mdc = 0
+ );
+
+parameter CLKDIV = 16;
+
+// ST OP PHYAD REGAD TA DATA IDLE
+// PRE 11 11 11111 11111 11 1111111111111111 Z
+// READ 01 10 AAAAA RRRRR Z0 DDDDDDDDDDDDDDDD Z // 6
+// WRITE 01 01 AAAAA RRRRR 10 DDDDDDDDDDDDDDDD Z // 5
+
+// on phase entry:
+// -------------------------
+// .-----. A mdc=0 shift
+// | | B mdc=1
+// --' '-- C mdc=1 capture=i_mdio
+// A B C D D mdc=0
+//
+// always: o_mdio=shift[31]
+
+typedef enum { IDLE, PHA, PHB, PHC, PHD } state_t;
+state_t state = IDLE;
+state_t next_state;
+
+reg next_busy;
+reg next_mdc;
+
+reg [31:0]shift = 0;
+reg [31:0]next_shift;
+reg [4:0]count = 0;
+reg [4:0]next_count;
+reg [7:0]clkcnt = 0;
+reg [7:0]next_clkcnt;
+reg capture0 = 0;
+reg next_capture0;
+reg capture1 = 0;
+reg next_capture1;
+reg tristate = 1;
+reg next_tristate;
+reg op_read = 0;
+reg next_op_read;
+
+reg step;
+
+assign o_mdio = shift[31];
+assign t_mdio = tristate;
+assign rxdata = shift[16:1];
+
+always_comb begin
+ next_tristate = tristate;
+ next_capture0 = capture0;
+ next_capture1 = capture1;
+ next_clkcnt = clkcnt;
+ next_count = count;
+ next_op_read = op_read;
+ next_state = state;
+ next_shift = shift;
+ next_busy = busy;
+ next_mdc = mdc;
+ step = 0;
+
+ // while txn active, count clocks and advance
+ // phases every CLKDIV clocks
+ if (busy) begin
+ if (clkcnt == CLKDIV) begin
+ next_clkcnt = 0;
+ step = 1;
+ end else begin
+ next_clkcnt = clkcnt + 1;
+ step = 0;
+ end
+ // debounce input
+ next_capture0 = i_mdio;
+ end
+
+ case (state)
+ IDLE: if (do_read | do_write) begin
+ next_state = PHA;
+ next_mdc = 0;
+ next_busy = 1;
+ next_tristate = 0;
+ next_count = 31;
+ next_shift = txdata;
+ next_op_read = do_read;
+ end
+ PHA: if (step) begin
+ next_state = PHB;
+ next_mdc = 1;
+ end
+ PHB: if (step) begin
+ next_state = PHC;
+ next_mdc = 1;
+ // acquire debounced input
+ next_capture1 = capture0;
+ end
+ PHC: if (step) begin
+ next_state = PHD;
+ next_mdc = 0;
+ end
+ PHD: if (step) begin
+ next_shift = { shift[30:0], capture1 };
+ if (op_read & (count == 18)) begin
+ next_tristate = 1;
+ end
+ if (count == 0) begin
+ next_state = IDLE;
+ next_tristate = 1;
+ next_busy = 0;
+ end else begin
+ next_state = PHA;
+ next_count = count - 1;
+ end
+ end
+ default: next_state = IDLE;
+ endcase
+end
+
+always_ff @(posedge clk) begin
+ tristate <= next_tristate;
+ capture0 <= next_capture0;
+ capture1 <= next_capture1;
+ op_read <= next_op_read;
+ clkcnt <= next_clkcnt;
+ state <= next_state;
+ shift <= next_shift;
+ count <= next_count;
+ busy <= next_busy;
+ mdc <= next_mdc;
+end
+
+endmodule
+
diff --git a/hdl/test/eth_mdio_test.sv b/hdl/test/eth_mdio_test.sv
@@ -0,0 +1,60 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns / 1ps
+
+module testbench(input clk);
+
+reg do_read = 0;
+reg do_write = 0;
+reg [31:0]txdata = 32'h80AA0123;
+wire [15:0]rxdata;
+wire busy;
+wire o_dat;
+wire t_dat;
+wire o_clk;
+reg i_raw = 0;
+wire i_dat = t_dat ? i_raw : o_dat;
+
+eth_mdio mdio0(
+ .clk(clk),
+ .do_read(do_read),
+ .do_write(do_write),
+ .txdata(txdata),
+ .rxdata(rxdata),
+ .busy(busy),
+ .i_mdio(i_dat),
+ .o_mdio(o_dat),
+ .t_mdio(t_dat),
+ .mdc(o_clk)
+ );
+
+integer count = 0;
+reg next_rd;
+reg next_wr;
+
+always_comb begin
+ next_rd = 0;
+ next_wr = 0;
+ if (count == 32768) $finish;
+ if (count == 32) next_rd = 1;
+end
+
+always @(posedge clk) begin
+ count <= count + 1;
+ do_read <= next_rd;
+ do_write <= next_wr;
+end
+
+endmodule