-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphy_ctrl.vhd
155 lines (148 loc) · 5.16 KB
/
phy_ctrl.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
-----------------------------------------------------------------------------
-- Module for configuring the phy to 100Mbit full-duplex through the
-- MDC-interface (connect to the miim-module)
--
-- Authors:
-- -- Kristoffer E. Koch
-----------------------------------------------------------------------------
-- Copyright 2008 Authors
--
-- This file is part of hwpulse.
--
-- hwpulse is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- hwpulse 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 General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with hwpulse. If not, see <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
entity phy_ctrl is
Port (
sysclk : in std_logic;
reset : in std_logic;
data_i : in std_logic_vector(7 downto 0);
data_i_v : in std_logic;
miim_addr : out std_logic_vector(4 downto 0);
miim_data_i : out std_logic_vector(15 downto 0);
miim_data_i_e : out std_logic;
miim_data_o : in std_logic_vector(15 downto 0);
miim_data_o_e : out std_logic;
miim_busy : in std_logic
);
end phy_ctrl;
architecture RTL of phy_ctrl is
type miim_state_t is (set_reg0, set_reg4,
wait_miim, wait_miim1,
vfy_reg0, vfy_reg0_1, vfy_reg4, vfy_reg4_1,
poll_link, poll_link_1, miim_reset_st);
signal miim_state, miim_after_wait:miim_state_t;
constant PHY_SET_REG0 :std_logic_vector(15 downto 0):="0011000100000000";
constant PHY_SET_REG0_MSK:std_logic_vector(15 downto 0):="1101111010000000";
constant PHY_SET_REG4 :std_logic_vector(15 downto 0):="0000000100000001";
constant PHY_SET_REG4_MSK:std_logic_vector(15 downto 0):="0000000100000000";
signal miim_reset:std_logic:='0';
signal miim_rdy:std_logic;
begin
-- This state-machine configures and verifies
-- the PHY to auto-negotiate 100Base-TX Full-duplex
-- Sets miim_rdy when link is up. When miim_reset is
-- asserted, a soft reset is done
miim_ctrl_fsm:process(sysclk, reset) is
begin
if rising_edge(sysclk) then
if reset = '1' then
miim_state <= wait_miim1;
miim_after_wait <= set_reg0;
miim_addr <= (OTHERS => '0');
miim_data_i <= (OTHERS => '0');
miim_data_i_e <= '0';
miim_data_o_e <= '0';
--debug <= (OTHERS => '1');
miim_rdy <= '0';
else
if miim_reset = '1' then
miim_after_wait <= miim_reset_st;
miim_rdy <= '0';
else
case miim_state is
when miim_reset_st =>
miim_addr <= std_logic_vector(to_unsigned(0, 5));
miim_data_i <= "1000000000000000";
miim_data_i_e <= '1';
miim_state <= wait_miim;
miim_after_wait <= set_reg0;
when set_reg0 =>
miim_addr <= std_logic_vector(to_unsigned(0, 5));
miim_data_i <= PHY_SET_REG0;
miim_data_i_e <= '1';
miim_state <= wait_miim;
miim_after_wait <= set_reg4;
when set_reg4 =>
miim_addr <= std_logic_vector(to_unsigned(4, 5));
miim_data_i <= PHY_SET_REG4;
miim_data_i_e <= '1';
miim_state <= wait_miim;
miim_after_wait <= vfy_reg0;
when vfy_reg0 =>
miim_addr <= std_logic_vector(to_unsigned(0, 5));
miim_data_o_e <= '1';
miim_state <= wait_miim;
miim_after_wait <= vfy_reg0_1;
when vfy_reg0_1 =>
if (miim_data_o and PHY_SET_REG0_MSK) = (PHY_SET_REG0 and PHY_SET_REG0_MSK) then
miim_state <= vfy_reg4;
else
miim_state <= set_reg0; --reset
end if;
when vfy_reg4 =>
miim_addr <= std_logic_vector(to_unsigned(4, 5));
miim_data_o_e <= '1';
miim_state <= wait_miim;
miim_after_wait <= vfy_reg4_1;
when vfy_reg4_1 =>
if (miim_data_o and PHY_SET_REG4_MSK) = (PHY_SET_REG4 and PHY_SET_REG4_MSK) then
miim_state <= poll_link;
else
miim_state <= set_reg0; --reset
end if;
when poll_link =>
miim_addr <= std_logic_vector(to_unsigned(1, 5));
miim_data_o_e <= '1';
miim_state <= wait_miim;
miim_after_wait <= poll_link_1;
when poll_link_1 =>
-- debug(0) <= miim_data_o(14); -- 100Base-TX FD (1)
-- debug(1) <= miim_data_o(5); -- Auto-neg comp (1)
-- debug(2) <= miim_data_o(4); -- remote fault (0)
-- debug(3) <= miim_data_o(3); -- able to autoneg (1)
-- debug(4) <= miim_data_o(2); -- link status (1)
-- debug(5) <= miim_data_o(1); -- jabber detect (0)
-- debug(6) <= miim_data_o(0); -- extended cap (1)
-- debug(7) <= '0';
miim_rdy <= miim_data_o(14) and miim_data_o(2);
miim_state <= poll_link;
when wait_miim =>
if miim_busy = '1' then
miim_state <= wait_miim1;
end if;
when wait_miim1 =>
miim_data_i_e <= '0';
miim_data_o_e <= '0';
if miim_busy = '0' then
miim_state <= miim_after_wait;
end if;
end case;
end if;
end if;
end if;
end process;
end RTL;