summaryrefslogtreecommitdiffhomepage
path: root/source/mdio.v
diff options
context:
space:
mode:
Diffstat (limited to 'source/mdio.v')
-rw-r--r--source/mdio.v146
1 files changed, 146 insertions, 0 deletions
diff --git a/source/mdio.v b/source/mdio.v
new file mode 100644
index 0000000..3339dcc
--- /dev/null
+++ b/source/mdio.v
@@ -0,0 +1,146 @@
+/*
+ * mdio.v
+ *
+ * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ *
+ * 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.
+ *
+ * function: MDIO HW driver / bit banger
+ *
+ */
+
+
+`timescale 1ns /10ps
+
+module mdio(
+ input rstn,
+ input mdc, // clock
+
+ // mdio
+ input mdi,
+ output reg mdo,
+ output reg mdo_oe,
+
+ // mdio_controller interface
+ input rwn, // read / write not
+ input [4:0] phy_addr,
+ input [4:0] reg_addr,
+ input [15:0] di,
+ input ld, // load, start
+ output reg run,
+ output done, // mdio xfer is done
+
+ // output port to converter
+ output reg [15:0] dout,
+ output we
+);
+
+ reg [5:0] state;
+ reg [15:0] d;
+
+ // run state machine
+ // run starts when ld is asserted and finishes when done is asserted
+ always @(negedge mdc or negedge rstn)
+ begin
+ if ( !rstn)
+ run <= 1'b0;
+ else if ( ld )
+ run <= 1'b1;
+ else if ( done )
+ run <= 1'b0;
+ end
+
+
+ // increment state during run
+ always @(negedge mdc or negedge rstn)
+ begin
+ if ( !rstn )
+ state <= 0;
+ else if ( ld )
+ state <= 0;
+ else if ( run )
+ state <= state + 1;
+ end
+
+ // register data for MDIO TX
+ always @(negedge mdc or negedge rstn)
+ begin
+ if ( !rstn )
+ d <= 0;
+ else if ( ld )
+ d <= di;
+ end
+
+ // done combo logic
+ assign done = ( state == 6'd36 ) ? 1'b1 : 1'b0;
+
+ // only assert we on mdio reads
+ assign we = done && rwn;
+
+ // mdo_oe logic
+ always @(*)
+ begin
+ mdo_oe = 1'b0;
+ if ( run && !rwn && state < 6'd36 )
+ mdo_oe = 1'b1;
+ else if ( run && rwn && state < 6'd14 )
+ mdo_oe = 1'b1;
+ end
+
+ // mdo mux
+ always @(*)
+ begin
+ mdo = 1'b0;
+ casez(state)
+ 6'h0: mdo = 1'b0;
+ 6'h1: mdo = 1'b1;
+ 6'h2: if (rwn)
+ mdo = 1'b1;
+ else
+ mdo = 1'b0;
+ 6'h3: if (rwn)
+ mdo = 1'b0;
+ else
+ mdo = 1'b1;
+ 6'h4: mdo = phy_addr[4];
+ 6'h5: mdo = phy_addr[3];
+ 6'h6: mdo = phy_addr[2];
+ 6'h7: mdo = phy_addr[1];
+ 6'h8: mdo = phy_addr[0];
+ 6'h9: mdo = reg_addr[4];
+ 6'ha: mdo = reg_addr[3];
+ 6'hb: mdo = reg_addr[2];
+ 6'hc: mdo = reg_addr[1];
+ 6'hd: mdo = reg_addr[0];
+ 6'he: mdo = 1'b1; // it's a don't care if we're doing a read
+ 6'hf: mdo = 1'b0;
+ 6'h1?: mdo = rwn ? 1'b1 : d[31-state]; // msbit
+ default: mdo = 1'b1;
+ endcase
+ end
+
+
+ /*
+ * capture mdi on rising edge
+ * data out shift register
+ * ( shift into it from mdio to parallel reg )
+ */
+ always @(posedge mdc or negedge rstn)
+ begin
+ if ( !rstn )
+ dout <= 16'h0;
+ else if ( rwn && run && ( state >= 16 && state <= 31 ))
+ dout <= { dout[14:0], mdi };
+ end
+
+endmodule