-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmiim.vhd
203 lines (194 loc) · 5.01 KB
/
miim.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
-----------------------------------------------------------------------------
-- Module for interfacing the PHY MDC for the mdc
--
-- 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;
entity miim is
generic (
DIVISOR : integer := 30;
PHYADDR : std_logic_vector(4 downto 0) := "00000"
);
port (
sysclk : in std_logic;
reset : in std_logic;
addr : in std_logic_vector(4 downto 0);
data_i : in std_logic_vector(15 downto 0);
data_i_e : in std_logic;
data_o : out std_logic_vector(15 downto 0);
data_o_e : in std_logic;
busy : out std_logic;
miim_clk : out std_logic;
miim_d : inout std_logic
);
end miim;
architecture RTL of miim is
signal clkcount:integer range 0 to DIVISOR/2-1;
signal miim_clk_s, negedge:std_logic;
type state_t is (PRE, ST, OP, PHYAD, REGAD, TA, DATA, IDLE);
signal state:state_t;
signal op_read:std_logic;
signal dreg:std_logic_vector(15 downto 0);
signal areg:std_logic_vector(4 downto 0);
signal cnt:integer range 0 to 31;
begin
miim_clk <= miim_clk_s;
negedge <= '1' when clkcount=0 and miim_clk_s = '1' else '0';
--posedge <= '1' when clkcount=0 and miim_clk_s = '0' else '0';
busy <= '1' when state /= IDLE else '0';
clockgen: process(sysclk, reset) is
begin
if reset = '1' then
miim_clk_s <= '0';
clkcount <= 0;
elsif rising_edge(sysclk) then
if clkcount = 0 then
clkcount <= DIVISOR/2 - 1;
miim_clk_s <= not miim_clk_s;
else
clkcount <= clkcount - 1;
end if;
end if;
end process clockgen;
data_o <= dreg;
fsm:process(sysclk, reset) is
begin
if rising_edge(sysclk) then
if reset = '1' then
state <= IDLE;
miim_d <= 'Z';
dreg <= (OTHERS => '0');
op_read <= '0';
areg <= (OTHERS => '0');
else
case state is
when IDLE =>
if negedge = '1' then
miim_d <= 'Z';
end if;
if data_i_e = '1' or data_o_e = '1' then
if data_i_e = '1' then
dreg <= data_i;
op_read <= '0';
else
--dreg <= (OTHERS => 'U'); -- debugging
op_read <= '1';
end if;
areg <= addr;
cnt <= 31;
state <= PRE;
end if;
when PRE =>
if negedge = '1' then
miim_d <= 'Z'; --gets pulled up to '1'
if cnt = 0 then
state <= ST;
cnt <= 1;
else
cnt <= cnt - 1;
end if;
end if;
when ST =>
if negedge = '1' then
if cnt = 1 then -- first
miim_d <= '0';
cnt <= cnt - 1;
else -- second
miim_d <= '1';
state <= OP;
cnt <= 1;
end if;
end if;
when OP =>
if negedge = '1' then
if cnt = 1 then
miim_d <= op_read;
cnt <= cnt - 1;
else
miim_d <= not op_read;
state <= PHYAD;
cnt <= 4;
end if;
end if;
when PHYAD =>
if negedge = '1' then
miim_d <= PHYADDR(cnt);
if cnt = 0 then
state <= REGAD;
cnt <= 4;
else
cnt <= cnt - 1;
end if;
end if;
when REGAD =>
if negedge = '1' then
miim_d <= areg(cnt);
if cnt = 0 then
state <= TA;
cnt <= 1;
else
cnt <= cnt - 1;
end if;
end if;
when TA =>
if negedge = '1' then
if op_read = '1' then
if cnt = 0 then
assert miim_d = '0' report "MIIM: PHY did not pull down second TA-bit";
state <= DATA;
cnt <= 15;
else --first
miim_d <= 'Z';
cnt <= cnt - 1;
end if;
else
if cnt = 0 then
miim_d <= '0';
state <= DATA;
cnt <= 15;
else --first
miim_d <= '1';
cnt <= cnt - 1;
end if;
end if;
end if;
when DATA =>
if negedge = '1' then
if op_read = '1' then
assert miim_d = '1' or miim_d = '0' --tautology for implementation, but makes sense in simulation
report "MIIM: PHY did not give good data bit " & integer'image(cnt);
dreg(cnt) <= miim_d;
else
miim_d <= dreg(cnt);
end if;
if cnt = 0 then
state <= IDLE;
cnt <= 31;
else
cnt <= cnt - 1;
end if;
end if;
end case;
end if;
end if;
end process fsm;
end RTL;