-
Notifications
You must be signed in to change notification settings - Fork 0
/
fft_controller.vhd
316 lines (278 loc) · 11.7 KB
/
fft_controller.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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fft_controller is
port (clk : in std_logic;
start : in std_logic;
done : out std_logic;
tdom_data_in : in signed(15 downto 0);
tdom_addr_in : in unsigned(7 downto 0);
tdom_write : in std_logic;
fdom_data_out : out signed(31 downto 0);
fdom_addr_out : in unsigned(7 downto 0));
end fft_controller;
architecture rtl of fft_controller is
type control_state_type is (idle, dftsetup, dftcomp,
recomb_setup, recomb_comp);
signal tdom_addr_even : unsigned(3 downto 0);
signal tdom_data_even : signed(15 downto 0);
signal tdom_addr_odd : unsigned(3 downto 0);
signal tdom_data_odd : signed(15 downto 0);
signal tdom_sel : unsigned(2 downto 0);
signal control_state : control_state_type;
signal last_state : control_state_type;
signal fdom_writedata_low : signed(31 downto 0);
signal fdom_readdata_low : signed(31 downto 0);
signal fdom_readaddr_low : unsigned(3 downto 0);
signal fdom_writeaddr_low : unsigned(3 downto 0);
signal fdom_write_en_low : std_logic;
signal fdom_writedata_high : signed(31 downto 0);
signal fdom_readdata_high : signed(31 downto 0);
signal fdom_readaddr_high : unsigned(3 downto 0);
signal fdom_writeaddr_high : unsigned(3 downto 0);
signal fdom_write_en_high : std_logic;
signal recomb_stage : unsigned(1 downto 0);
signal comp_step : unsigned(2 downto 0);
signal fdom_step : unsigned(2 downto 0);
signal dft_rom_data_low : signed(31 downto 0);
signal dft_rom_addr_low : unsigned(7 downto 0);
signal dft_out_data_low : signed(31 downto 0);
signal dft_out_addr_low : unsigned(3 downto 0);
signal dft_out_write_low : std_logic;
signal dft_rom_data_high : signed(31 downto 0);
signal dft_rom_addr_high : unsigned(7 downto 0);
signal dft_out_data_high : signed(31 downto 0);
signal dft_out_addr_high : unsigned(3 downto 0);
signal dft_out_write_high : std_logic;
signal dft_done : std_logic_vector(1 downto 0);
signal dft_reset : std_logic;
signal recomb_reset : std_logic;
-- This helps us map the DFT inputs to the DFT outputs
-- The mappings are (0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15)
-- We do the even and odd mappings simultaneously
-- Thus, mapping(i) = 2 * fft_reorder(i) for even
-- and mapping(i) = 2 * fft_reorder(i) + 1 for odd
type fft_reorder_type is array(0 to 7) of unsigned(2 downto 0);
constant fft_reorder : fft_reorder_type := ("000", "100", "010", "110",
"001", "101", "011", "111");
signal rcrom16_data : signed(31 downto 0);
signal rcrom32_data : signed(31 downto 0);
signal rcrom64_data : signed(31 downto 0);
signal rcrom128_data : signed(31 downto 0);
signal rcromcur_addr : unsigned(3 downto 0);
signal rcromcur_data : signed(31 downto 0);
signal rcrom32_addr : unsigned(4 downto 0);
signal rcrom64_addr : unsigned(5 downto 0);
signal rcrom128_addr : unsigned(6 downto 0);
signal recomb_writeaddr_low : unsigned(3 downto 0);
signal recomb_writedata_low : signed(31 downto 0);
signal recomb_readaddr_low : unsigned(3 downto 0);
signal recomb_readdata_low : signed(31 downto 0);
signal recomb_write_low : std_logic;
signal recomb_writeaddr_high : unsigned(3 downto 0);
signal recomb_writedata_high : signed(31 downto 0);
signal recomb_readaddr_high : unsigned(3 downto 0);
signal recomb_readdata_high : signed(31 downto 0);
signal recomb_write_high : std_logic;
signal recomb_done : std_logic;
begin
TDOM_RAM : entity work.fft_tdom_ram port map (
clk => clk,
readaddr_even => tdom_addr_even,
readdata_even => tdom_data_even,
readaddr_odd => tdom_addr_odd,
readdata_odd => tdom_data_odd,
readsel => tdom_sel,
writeaddr => tdom_addr_in,
writedata => tdom_data_in,
write_en => tdom_write
);
FDOM_RAM : entity work.fft_fdom_ram port map (
readdata_low => fdom_readdata_low,
readaddr_low => fdom_readaddr_low,
writedata_low => fdom_writedata_low,
writeaddr_low => fdom_writeaddr_low,
write_en_low => fdom_write_en_low,
readdata_high => fdom_readdata_high,
readaddr_high => fdom_readaddr_high,
writedata_high => fdom_writedata_high,
writeaddr_high => fdom_writeaddr_high,
write_en_high => fdom_write_en_high,
stage => recomb_stage,
step => fdom_step,
clk => clk
);
COEFF_ROM : entity work.dft_lut port map (
clock => clk,
address_a => std_logic_vector(dft_rom_addr_low),
address_b => std_logic_vector(dft_rom_addr_high),
signed(q_a) => dft_rom_data_low,
signed(q_b) => dft_rom_data_high
);
tdom_sel <= fft_reorder(to_integer(comp_step));
DFT_EVEN : entity work.dft_top port map (
tdom_data => tdom_data_even,
tdom_addr => tdom_addr_even,
clk => clk,
reset => dft_reset,
rom_data => dft_rom_data_low,
rom_addr => dft_rom_addr_low,
fdom_data => dft_out_data_low,
fdom_addr => dft_out_addr_low,
fdom_write => dft_out_write_low,
done => dft_done(0)
);
DFT_ODD : entity work.dft_top port map (
tdom_data => tdom_data_odd,
tdom_addr => tdom_addr_odd,
clk => clk,
reset => dft_reset,
rom_data => dft_rom_data_high,
rom_addr => dft_rom_addr_high,
fdom_data => dft_out_data_high,
fdom_addr => dft_out_addr_high,
fdom_write => dft_out_write_high,
done => dft_done(1)
);
-- Multiplex between dft and recomb units for the fdom ram
with control_state select fdom_writedata_low <=
dft_out_data_low when dftsetup | dftcomp,
recomb_writedata_low when recomb_setup | recomb_comp,
(others => '0') when others;
with control_state select fdom_writeaddr_low <=
dft_out_addr_low when dftsetup | dftcomp,
recomb_writeaddr_low when recomb_setup | recomb_comp,
(others => '0') when others;
with control_state select fdom_write_en_low <=
dft_out_write_low when dftsetup | dftcomp,
recomb_write_low when recomb_setup | recomb_comp,
'0' when others;
with control_state select fdom_readaddr_low <=
recomb_readaddr_low when recomb_setup | recomb_comp,
fdom_addr_out(3 downto 0) when idle,
(others => '0') when others;
recomb_readdata_low <= fdom_readdata_low;
with control_state select fdom_writedata_high <=
dft_out_data_high when dftsetup | dftcomp,
recomb_writedata_high when recomb_setup | recomb_comp,
(others => '0') when others;
with control_state select fdom_writeaddr_high <=
dft_out_addr_high when dftsetup | dftcomp,
recomb_writeaddr_high when recomb_setup | recomb_comp,
(others => '0') when others;
with control_state select fdom_write_en_high <=
dft_out_write_high when dftsetup | dftcomp,
recomb_write_high when recomb_setup | recomb_comp,
'0' when others;
with control_state select fdom_readaddr_high <=
recomb_readaddr_high when recomb_setup | recomb_comp,
fdom_addr_out(3 downto 0) when idle,
(others => '0') when others;
recomb_readdata_high <= fdom_readdata_high;
-- highest bit of fdom address determines which half of the RAM
-- the data is pulled out of
fdom_data_out <= fdom_readdata_high when fdom_addr_out(7) = '1' else
fdom_readdata_low;
-- when idle, allow the fdom read address to select the step
-- when computing, let comp_step determine it
fdom_step <= fdom_addr_out(6 downto 4) when
control_state = idle else comp_step;
RECOMB : entity work.fft_recomb port map (
clk => clk,
reset => recomb_reset,
rom_addr => rcromcur_addr,
rom_data => rcromcur_data,
low_readaddr => recomb_readaddr_low,
low_writeaddr => recomb_writeaddr_low,
low_readdata => recomb_readdata_low,
low_writedata => recomb_writedata_low,
low_write_en => recomb_write_low,
high_readaddr => recomb_readaddr_high,
high_writeaddr => recomb_writeaddr_high,
high_readdata => recomb_readdata_high,
high_writedata => recomb_writedata_high,
high_write_en => recomb_write_high,
done => recomb_done
);
-- select which recomb rom to use based on recomb_stage
with recomb_stage select rcromcur_data <=
rcrom16_data when "00",
rcrom32_data when "01",
rcrom64_data when "10",
rcrom128_data when others;
RCR16 : entity work.rcrom16 port map (
address => std_logic_vector(rcromcur_addr),
signed(q) => rcrom16_data,
clock => clk
);
rcrom32_addr <= comp_step(0) & rcromcur_addr;
RCR32 : entity work.rcrom32 port map (
address => std_logic_vector(rcrom32_addr),
signed(q) => rcrom32_data,
clock => clk
);
rcrom64_addr <= comp_step(1 downto 0) & rcromcur_addr;
RCR64 : entity work.rcrom64 port map (
address => std_logic_vector(rcrom64_addr),
signed(q) => rcrom64_data,
clock => clk
);
rcrom128_addr <= comp_step & rcromcur_addr;
RCR128 : entity work.rcrom128 port map (
address => std_logic_vector(rcrom128_addr),
signed(q) => rcrom128_data,
clock => clk
);
done <= '1' when control_state = idle else '0';
dft_reset <= '1' when control_state = dftsetup else '0';
recomb_reset <= '1' when control_state = recomb_setup else '0';
process (clk)
begin
if rising_edge(clk) then
last_state <= control_state;
case control_state is
when idle =>
-- reads in the idle state must be done with
-- recomb_stage at "11" so that low and high
-- split the ram into two contiguous chunks
recomb_stage <= "11";
comp_step <= "111";
if start = '1' then
control_state <= dftsetup;
end if;
when dftsetup =>
-- same thing goes for dft
-- recomb_stage set to "11"
recomb_stage <= "11";
-- first time in dftcomp will see comp_step = 0
comp_step <= comp_step + 1;
control_state <= dftcomp;
when dftcomp =>
if dft_done = "11" then
if comp_step = "111" then
control_state <= recomb_setup;
else
control_state <= dftsetup;
end if;
end if;
when recomb_setup =>
-- go through steps and then through stages
if comp_step = "111" then
recomb_stage <= recomb_stage + 1;
comp_step <= "000";
else
comp_step <= comp_step + 1;
end if;
control_state <= recomb_comp;
when recomb_comp =>
if recomb_done = '1' then
if comp_step = "111" and recomb_stage = "11" then
control_state <= idle;
else
control_state <= recomb_setup;
end if;
end if;
end case;
end if;
end process;
end rtl;