-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfft_wrapper.sv
190 lines (181 loc) · 4.73 KB
/
fft_wrapper.sv
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
/* FFT Wrapper for One Channel
* Author: Sound Localizer Team
* Includes:
* 1. FFT ip core, RAM ip core
* 2. FFT control logic
* FFT Mode: Variable Streaming
* Version Notes:
* I made the variable names consistent with fft_block's for clarity.
*/
module fft_wrapper(
input logic clk,
input logic rst_n, // Active low
input logic go, // Reset FSM
input logic ready, // Raw data RAMs ready to be read
input logic [13:0]data_in, // Raw data input
input logic [9:0]rd_addr_fft, // Read address of fft RAMs
output logic fftdone, // fft wrapper output ready
output logic rdreq, // Read request
output logic [27:0]ram_q // fft results from fft RAM
);
logic [9:0]count; // 1024 counter
logic sor; // start of read (raw data)
// fft ip singals
logic sink_valid, sink_ready, source_valid;
logic sink_sop, sink_eop, source_sop, source_eop;
logic [13:0] source_real, source_imag;
// RAM signals
logic [9:0] wr_addr;
logic wren;
logic [10:0] addr_raw;
logic flag; // Toggle to differ control wren
enum {IDLE, READ, WRITE, READY} state;
enum {VACANT, START} state_wr_addr;
parameter FFT_PTS = 11'd1024;
/* Generate sink_eop & sink_sop stream signals for fft_block
* sor (start of raw) ensures addr_raw to output correctly,
* which can align with the sink_sop & sink_eop stream
*/
always @(posedge clk) begin
if (~rst_n) begin
count = 10'd1;
sink_valid <= 1'd0;
sink_eop <= 1'd0;
sink_sop <= 1'd0;
sor <= 1'd0;
end else begin
count <= count + 1'b1;
if (count == 10'd0) begin
sink_eop <= 0;
sink_sop <= 1;
sink_valid <= 1;
end else if(count == 10'd1) begin
sink_sop <= 0;
end else if (count == 10'd1021) begin
sor <= 1;
end else if (count == 10'd1022) begin
sor <= 0;
end else if (count == 10'd1023) begin
sink_eop <= 1;
end
end
end
/* Control Calculation
* FSM
* IDLE: Wait for the ready signals from raw data RAM and FFT engine
* READ: Read the raw data out of the RAM
* WRITE: Write the fft results to RAM when source_eop
* (I intentionally used eop instead of sop since eop is one cycle earlier than sop)
* (So that it won't miss the first output in terms of wren)
* READY: fft RAM is ready to be read to the next stage
*/
always_ff @(posedge clk) begin
if (~rst_n) begin
state <= IDLE;
addr_raw <= 11'd2047;
wren <= 1'd0;
fftdone <= 1'd0;
rdreq <= 1'd0;
flag <= 1'd0;
end else begin
case (state)
IDLE: begin
fftdone <= 1'd0;
if (ready && sink_ready && sor)
state <= READ;
else
state <= IDLE;
end
READ: begin
addr_raw <= addr_raw + 11'd1;
if (addr_raw == 11'd1023) begin
rdreq <= 1'd0;
end else if (addr_raw == 11'd2046) begin // because the calculation delay of fft is about 1024
state <= WRITE;
end else if (addr_raw == 11'd2047) begin
rdreq <= 1'd1;
end else begin
state <= READ;
end
end
WRITE: begin
if (source_eop) begin
wren <= 1'd1;
flag <= 1'd1;
end
if (flag && wr_addr == 10'd1022) begin
state <= READY;
end else begin
state <= WRITE;
end
end
READY: begin
flag <= 1'd0;
wren <= 1'd0;
fftdone <= 1'd1;
if (go)
state <= IDLE;
else
state <= READY;
end
default: begin
state <= IDLE;
end
endcase
end
end
/* Generate Control Singals for fft RAM
* FSM
* VACANT: wait until source_eop to start wr_addr streaming
* START: generate wr_addr singal stream for FFT RAM
*/
always @(posedge clk) begin
if (~rst_n) begin
wr_addr <= 10'd0;
state_wr_addr <= VACANT;
end else begin
case (state_wr_addr)
VACANT: begin
wr_addr <= 10'd0;
if (source_eop)
state_wr_addr <= START;
else
state_wr_addr <= VACANT;
end
START: begin
wr_addr <= wr_addr + 10'd1;
end
default: state_wr_addr <= VACANT;
endcase
end
end
fft_block fft_inst(
.clk(clk),
.reset_n(rst_n),
.sink_valid(sink_valid), // Asserted when data is valid
.sink_ready(sink_ready), // Output. Asserted when fft engine can accept data.
.sink_error(2'b00), // Error
.sink_sop(sink_sop), // Start of input
.sink_eop(sink_eop), // End of input
.sink_real(data_in),// Real input data (signed)
.sink_imag(14'd0),
.fftpts_in(FFT_PTS), // The number of points
.inverse(1'b0),
.source_valid(source_valid), // Output valid
.source_ready(1'b1),// Asserted when downstream module is able to accept data
.source_error(), // Output error
.source_sop(source_sop), // Start of output. Only valid when source valid
.source_eop(source_eop),
.source_real(source_real),
.source_imag(source_imag),
.fftpts_out()
);
ram_fft_output fft_ram1(
.clock (clk),
.data ({source_real, source_imag}), // 28 bits width
.rdaddress (rd_addr_fft), // 10 bits width address
.wraddress (wr_addr),
.wren (wren),
.q (ram_q)
);
endmodule