diff options
Diffstat (limited to 'netfpga10g/hdl/mdio.vhd')
-rw-r--r-- | netfpga10g/hdl/mdio.vhd | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/netfpga10g/hdl/mdio.vhd b/netfpga10g/hdl/mdio.vhd new file mode 100644 index 0000000..1cb34fa --- /dev/null +++ b/netfpga10g/hdl/mdio.vhd @@ -0,0 +1,223 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity mdio is port ( + clk125 : in std_logic; + reset125 : in std_logic; + + command : in std_logic_vector(0 to 27); -- operation(2) & phyaddr(5) & devaddr(5) & data_in(16) + data_out : out std_logic_vector(0 to 15); + enable : in std_logic; + done : out std_logic; + + mdio_in : in std_logic; + mdio_out : out std_logic; + mdio_Z : out std_logic; + mdc : out std_logic; + phy_reset_n : out std_logic; + + total_count : out std_logic_vector(31 downto 0); + address_count : out std_logic_vector(31 downto 0); + write_count : out std_logic_vector(31 downto 0); + read_count : out std_logic_vector(31 downto 0); + read_incr_count : out std_logic_vector(31 downto 0) +); +end mdio; + +architecture arch of mdio is + type state_t is (state_idle, state_preamble, state_start, state_operation, + state_phyaddr, state_devaddr, state_turnaround, state_data); + + signal state : state_t; + signal state_count : natural range 0 to 32; + + signal operation : std_logic_vector(0 to 1); + signal phyaddr : std_logic_vector(0 to 4); + signal devaddr : std_logic_vector(0 to 4); + signal data_in : std_logic_vector(0 to 15); + + signal mdc_count : natural range 0 to 25; + signal mdc_i : std_logic; + + signal total_count_i : unsigned(31 downto 0); + signal address_count_i : unsigned(31 downto 0); + signal write_count_i : unsigned(31 downto 0); + signal read_count_i : unsigned(31 downto 0); + signal read_incr_count_i : unsigned(31 downto 0); + + signal done_i : std_logic; +begin + phy_reset_n <= not reset125; + mdc <= mdc_i; + + operation <= command(0 to 1); + phyaddr <= command(2 to 6); + devaddr <= command(7 to 11); + data_in <= command(12 to 27); + + done <= done_i; + + process (clk125, reset125) begin + if reset125 = '1' then + mdc_i <= '0'; + mdc_count <= 0; + done_i <= '0'; + + elsif rising_edge(clk125) then + done_i <= '0'; + + if mdc_count = 25 - 1 then + mdc_count <= 0; + mdc_i <= not mdc_i; -- 2.5 MHz + + if mdc_i = '0' then -- rising edge + if state = state_data and state_count = 15 then + done_i <= '1'; + end if; + end if; + else + mdc_count <= mdc_count + 1; + end if; + end if; + end process; + + process (mdc_i, reset125) begin + if reset125 = '1' then + state <= state_idle; + state_count <= 0; + data_out <= (others => '0'); + + elsif rising_edge(mdc_i) then + state_count <= state_count + 1; + + if state = state_preamble then + if state_count = 31 then + state <= state_start; + state_count <= 0; + end if; + elsif state = state_start then + if state_count = 1 then + state <= state_operation; + state_count <= 0; + end if; + elsif state = state_operation then + if state_count = 1 then + state <= state_phyaddr; + state_count <= 0; + end if; + elsif state = state_phyaddr then + if state_count = 4 then + state <= state_devaddr; + state_count <= 0; + end if; + elsif state = state_devaddr then + if state_count = 4 then + state <= state_turnaround; + state_count <= 0; + end if; + elsif state = state_turnaround then + if state_count = 1 then + state <= state_data; + state_count <= 0; + end if; + elsif state = state_data then + data_out(state_count) <= mdio_in; + + if state_count = 15 then + state <= state_idle; + state_count <= 0; + end if; + else -- state = state_idle + if enable = '1' then + state <= state_preamble; + state_count <= 0; + end if; + end if; + end if; + end process; + + process (mdc_i, reset125) begin + if reset125 = '1' then + mdio_out <= '0'; + mdio_Z <= '1'; + + elsif falling_edge(mdc_i) then + mdio_out <= '0'; + mdio_Z <= '1'; + + if state = state_preamble then + mdio_out <= '1'; + mdio_Z <= '0'; + + elsif state = state_start then + mdio_out <= '0'; + mdio_Z <= '0'; + + elsif state = state_operation then + mdio_out <= operation(state_count); + mdio_Z <= '0'; + + elsif state = state_phyaddr then + mdio_out <= phyaddr(state_count); + mdio_Z <= '0'; + + elsif state = state_devaddr then + mdio_out <= devaddr(state_count); + mdio_Z <= '0'; + + elsif state = state_turnaround then + if operation(0) = '0' then -- write or address + mdio_Z <= '0'; + + if state_count = 0 then + mdio_out <= '1'; + else + mdio_out <= '0'; + end if; + end if; + + elsif state = state_data then + if operation(0) = '0' then -- write or address + mdio_Z <= '0'; + mdio_out <= data_in(state_count); + end if; + end if; + end if; + end process; + + total_count <= std_logic_vector(total_count_i); + address_count <= std_logic_vector(address_count_i); + write_count <= std_logic_vector(write_count_i); + read_count <= std_logic_vector(read_count_i); + read_incr_count <= std_logic_vector(read_incr_count_i); + + process (clk125, reset125) begin + if reset125 = '1' then + total_count_i <= (others => '0'); + address_count_i <= (others => '0'); + write_count_i <= (others => '0'); + read_count_i <= (others => '0'); + read_incr_count_i <= (others => '0'); + + elsif rising_edge(clk125) then + if done_i = '1' then + total_count_i <= total_count_i + 1; + + if operation = "00" then + address_count_i <= address_count_i + 1; + end if; + if operation = "01" then + write_count_i <= write_count_i + 1; + end if; + if operation = "11" then + read_count_i <= read_count_i + 1; + end if; + if operation = "10" then + read_incr_count_i <= read_incr_count_i + 1; + end if; + end if; + end if; + end process; +end arch; |