OpenCores
URL https://opencores.org/ocsvn/1000base-x/1000base-x/trunk

Subversion Repositories 1000base-x

[/] [1000base-x/] [trunk/] [rtl/] [verilog/] [ge_1000baseX_mdio.v] - Rev 3

Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  File name "ge_1000baseX_mdio.v"                             ////
////                                                              ////
////  This file is part of the :                                  ////
////                                                              ////
//// "1000BASE-X IEEE 802.3-2008 Clause 36 - PCS project"         ////
////                                                              ////
////  http://opencores.org/project,1000base-x                     ////
////                                                              ////
////  Author(s):                                                  ////
////      - D.W.Pegler Cambridge Broadband Networks Ltd           ////
////                                                              ////
////      { peglerd@gmail.com, dwp@cambridgebroadand.com }        ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2009 AUTHORS. All rights reserved.             ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// This module is based on the coding method described in       ////
//// IEEE Std 802.3-2008 Clause 22 "Reconcilliation Sublayer (RS) ////
//// Media Independent Interface (MII)"; see                      ////
////                                                              ////
//// http://standards.ieee.org/about/get/802/802.3.html           ////
//// and                                                          ////
//// doc/802.3-2008_section2.pdf, Clause/Section 36.              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
 
`include "ge_1000baseX_constants.v"
 
`include "timescale.v"
 
module ge_1000baseX_mdio #(
  parameter PHY_ADDR = 5'b00000		   
) (
 
   //  reset 
   input              reset, 
   //  clock 
   input              mdc,
 
   input              mdio,
   output             mdio_out,
   output             mdio_oe,
 
   output     [4:0]   data_addr,    
   input     [15:0]   data_rd,
   output    [15:0]   data_wr,
   output reg         strobe_wr
   );
 
 
`ifdef MODEL_TECH
  enum logic [3:0] {
`else
  localparam
`endif
		    S_PREAMBLE  = 0,
		    S_ST        = 1,
		    S_OP_CODE   = 2,
		    S_PHY_ADDR  = 3,
		    S_REG_ADDR  = 4,
		    S_TA        = 5,
		    S_WR_DATA   = 6,
		    S_RD_DATA   = 7,
		    S_WR_COMMIT = 8
`ifdef MODEL_TECH
  } present, next;
`else
  ; reg [3:0] present, next;
`endif
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////   
 
   reg [5:0] preamble_cnt;
 
   assign preamble_match = (preamble_cnt == 31);
 
   always @(posedge mdc or posedge reset)
     if (reset)
       preamble_cnt = 0;
     else
       preamble_cnt <= (mdio & ~preamble_match) ? preamble_cnt + 1 : 
		       (mdio & preamble_match)  ? preamble_cnt : 0;
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////
 
   reg pos_cnt_inc; reg [4:0] pos_cnt;
 
   always @(posedge mdc or posedge reset)
     if (reset)
       pos_cnt <= 0;
     else 
	pos_cnt <= (pos_cnt_inc) ? pos_cnt + 1 : 0;
 
   assign op_code_done   = (pos_cnt == 1);
   assign phy_addr_done  = (pos_cnt == 6);
   assign reg_addr_done  = (pos_cnt == 11);
   assign ta0_done       = (pos_cnt == 12);
   assign ta1_done       = (pos_cnt == 13);
   assign data_done      = (pos_cnt == 29);
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////
 
   reg st; reg st_latch;
 
   always @(posedge mdc or posedge reset)
     if (reset)
       st <= 0;
     else
       if (st_latch) st <= mdio;
 
   assign st_match = ~st & mdio;
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////  
 
   reg [1:0] op_code; reg op_code_shift;
 
   always @(posedge mdc or posedge reset)
     if (reset)
       op_code <= 0;
     else
       if (op_code_shift) op_code <= { op_code[0], mdio};
 
   assign op_is_rd = (op_code == 2'b10); assign op_is_wr = (op_code == 2'b01);
 
   assign op_is_invalid = ~op_is_rd & ~op_is_wr;
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////  
 
   reg [4:0] phy_addr; reg phy_addr_shift;
 
   always @(posedge mdc or posedge reset)
     if (reset)
       phy_addr <= 0;
     else
       if (phy_addr_shift) phy_addr <= { phy_addr[3:0], mdio};
 
   assign phy_addr_match = (phy_addr == PHY_ADDR);
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////  
 
   reg [4:0] reg_addr; reg reg_addr_shift;
 
   always @(posedge mdc or posedge reset)
     if (reset)
       reg_addr <= 0;
     else
       if (reg_addr_shift) reg_addr <= { reg_addr[3:0], mdio};
 
   assign data_addr = reg_addr;
 
   //////////////////////////////////////////////////////////////////////////////
   //
   ////////////////////////////////////////////////////////////////////////////// 
 
   reg [15:0] data_in; reg data_in_shift;
 
   always @(posedge mdc or posedge reset)
     if (reset) 
       data_in <= 0;
     else
       if (data_in_shift) data_in <= { data_in[14:0], mdio};
 
   assign data_wr = data_in;
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////
 
   reg [15:0] data_out; reg data_out_load, data_out_shift;
 
   always @(posedge mdc or posedge reset)
     if (reset)
       data_out <= 0;
     else
       if      (data_out_load)  data_out <= data_rd;
       else if (data_out_shift) data_out <= { data_out[14:0], 1'b0 };
 
   //////////////////////////////////////////////////////////////////////////////
   //
   //////////////////////////////////////////////////////////////////////////////
 
   assign mdio_oe = (ta1_done & op_is_rd) | data_out_shift;
 
   assign mdio_out = (ta1_done & op_is_rd) ? 1'b1 : data_out[15];
 
   //////////////////////////////////////////////////////////////////////////////
   // mdio/mdc state machine registered part.
   //////////////////////////////////////////////////////////////////////////////
 
   always @(posedge mdc or posedge reset)
 
     present <= (reset) ? S_PREAMBLE : next;
 
   //////////////////////////////////////////////////////////////////////////////
   // IEEE Std 802.3-2008 Clause 22 "Reconcilliation Sublayer (RS) and
   // Media Independent Interface (MII)IEEE 802.3-2005 Clause 22 
   //////////////////////////////////////////////////////////////////////////////
 
   always @*
     begin	
	next = present;
 
	pos_cnt_inc = 0;  st_latch = 0; 
 
	op_code_shift = 0; phy_addr_shift = 0; reg_addr_shift = 0; 
 
	data_in_shift = 0; data_out_load = 0; data_out_shift = 0;
 
	strobe_wr = 0;
 
	case (present)
 
	  S_PREAMBLE:
	    begin
	       next = (preamble_match & ~mdio) ? S_ST : S_PREAMBLE;
	    end
 
	  S_ST:
	    begin
	       next = (mdio) ? S_OP_CODE: S_PREAMBLE;
	    end
 
	  S_OP_CODE:
	    begin
	       pos_cnt_inc = 1; op_code_shift = 1;
 
	       next = (op_code_done) ? S_PHY_ADDR : S_OP_CODE;
	    end
 
	  S_PHY_ADDR:
	    begin
	       pos_cnt_inc = 1; phy_addr_shift = 1;
 
	       next = (phy_addr_done) ? S_REG_ADDR : S_PHY_ADDR;
	    end
 
	  S_REG_ADDR:
	    begin
	       if (phy_addr_match) begin
 
		  pos_cnt_inc = 1; reg_addr_shift = 1;
 
		  next = (reg_addr_done) ? S_TA : S_REG_ADDR;
	       end
	       else  
		 next = S_PREAMBLE;  
	    end
 
	  S_TA:
	    begin
	       pos_cnt_inc = 1;
 
	       if (ta1_done) begin
 
		  data_out_load = op_is_rd;
 
		  next = (op_is_rd) ? S_RD_DATA : 
			 (op_is_wr) ? S_WR_DATA : S_PREAMBLE;
	       end
	    end
 
	  S_WR_DATA:
	    begin 
	       pos_cnt_inc = 1; data_in_shift = 1;
 
	       next = (data_done) ? S_WR_COMMIT : S_WR_DATA;
	    end
 
	  S_RD_DATA:
	    begin
	       pos_cnt_inc = 1; data_out_shift = 1;
 
	       next = (data_done) ? S_PREAMBLE : S_RD_DATA;
	    end
 
 
	  S_WR_COMMIT:
	    begin
	       strobe_wr = 1; next = S_PREAMBLE;
	    end
	endcase 	
     end
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.