Project

General

Profile

Download (13.2 KB) Statistics
| Branch: | Tag: | Revision:
1
---------------------------------------------------------------------------------------------------
2
-- Filename    : usbrx_halfband.vhd
3
-- Project     : OsmoSDR FPGA Firmware
4
-- Purpose     : Multichannel Halfband Decimation Filter
5
---------------------------------------------------------------------------------------------------
6

    
7
-----------------------------------------------------------------------------------
8
-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
9
-- written by Matthias Kleffel                                                   --
10
--                                                                               --
11
-- This program is free software; you can redistribute it and/or modify          --
12
-- it under the terms of the GNU General Public License as published by          --
13
-- the Free Software Foundation as version 3 of the License, or                  --
14
--                                                                               --
15
-- This program is distributed in the hope that it will be useful,               --
16
-- but WITHOUT ANY WARRANTY; without even the implied warranty of                --
17
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  --
18
-- GNU General Public License V3 for more details.                               --
19
--                                                                               --
20
-- You should have received a copy of the GNU General Public License             --
21
-- along with this program. If not, see <http://www.gnu.org/licenses/>.          --
22
-----------------------------------------------------------------------------------
23

    
24
-------------------------------------------------------------------------------
25
-- halfband decimation filter - input cache/control ---------------------------
26
-------------------------------------------------------------------------------
27

    
28
library ieee;
29
	use ieee.std_logic_1164.all;
30
	use ieee.numeric_std.all;
31
library work;
32
	use work.all;
33
	use work.mt_toolbox.all;
34
	use work.mt_filter.all;
35

    
36
entity usbrx_halfband_ictrl is
37
	generic (
38
		N        : natural := 3
39
	);
40
	port (
41
		-- common
42
		clk      : in  std_logic;
43
		reset    : in  std_logic;
44
		
45
		-- input
46
		in_clk   : in  std_logic_vector(N-1 downto 0);
47
		in_i     : in  fir_databus18(N-1 downto 0);
48
		in_q     : in  fir_databus18(N-1 downto 0);
49
		
50
		-- output
51
		out_ready : in  std_logic;
52
		out_clk   : out std_logic;
53
		out_chan  : out unsigned(log2(N)-1 downto 0);
54
		out_i0    : out fir_dataword18;
55
		out_i1    : out fir_dataword18;
56
		out_q0    : out fir_dataword18;
57
		out_q1    : out fir_dataword18
58
	);
59
end usbrx_halfband_ictrl;
60

    
61
architecture rtl of usbrx_halfband_ictrl is	
62

    
63
	-- control
64
	signal phase : std_logic_vector(N-1 downto 0);
65
	signal tmp_i : fir_databus18(N-1 downto 0);
66
	signal tmp_q : fir_databus18(N-1 downto 0);
67
	signal oclk  : std_logic;
68
	
69
	-- output
70
	signal pending  : std_logic_vector(N-1 downto 0);
71
	signal cache_i0 : fir_databus18(N-1 downto 0);
72
	signal cache_i1 : fir_databus18(N-1 downto 0);
73
	signal cache_q0 : fir_databus18(N-1 downto 0);
74
	signal cache_q1 : fir_databus18(N-1 downto 0);
75
	
76
begin
77
	
78
	-- control logic
79
	process(clk)
80
		variable found : std_logic;
81
	begin
82
		if rising_edge(clk) then
83
			-- set default values
84
			oclk <= '0';
85
			
86
			-- check if we are allowed to output the next entry
87
			if out_ready='1' and oclk='0' then
88
				-- search for pending cache-entry
89
				found := '0';
90
				for i in 0 to N-1 loop
91
					if found='0' and pending(i)='1' then
92
						--> output entry
93
						oclk <= '1';
94
						out_chan <= to_unsigned(i,out_chan'length);
95
						out_i0 <= cache_i0(i);
96
						out_i1 <= cache_i1(i);
97
						out_q0 <= cache_q0(i);
98
						out_q1 <= cache_q1(i);
99
						
100
						-- update status
101
						pending(i) <= '0';
102
						found := '1';
103
					end if;
104
				end loop;
105
			end if;
106
			
107
			-- handle incoming samples
108
			for i in in_clk'range loop
109
				if in_clk(i)='1' then
110
					-- write sample into cache
111
					if phase(i)='0' then 
112
						tmp_i(i) <= in_i(i);
113
						tmp_q(i) <= in_q(i);
114
					else 
115
						pending(i)  <= '1';
116
						cache_i0(i) <= tmp_i(i);
117
						cache_q0(i) <= tmp_q(i);
118
						cache_i1(i) <= in_i(i);
119
						cache_q1(i) <= in_q(i);	
120
					end if;
121
					phase(i) <= not phase(i);
122
				
123
					-- debug check
124
					assert phase(i)='0' or pending(i)='0'
125
						report "usbrx_halfband_ictrl: input too fast" 
126
						severity error;
127
				end if;
128
			end loop;
129
			
130
			-- handle reset
131
			if reset='1' then
132
				phase    <= (others=>'0');
133
				tmp_i    <= (others=>(others=>'0'));
134
				tmp_q    <= (others=>(others=>'0'));
135
				pending  <= (others=>'0');
136
				cache_i0 <= (others=>(others=>'0'));
137
				cache_i1 <= (others=>(others=>'0'));
138
				cache_q0 <= (others=>(others=>'0'));
139
				cache_q1 <= (others=>(others=>'0'));
140
				oclk     <= '0';
141
				out_chan <= (others=>'0');
142
				out_i0   <= (others=>'0');
143
				out_i1   <= (others=>'0');
144
				out_q0   <= (others=>'0');
145
				out_q1   <= (others=>'0');
146
			end if;
147
		end if;
148
	end process;
149
	
150
	-- connect output-clock
151
	out_clk <= oclk;
152
	
153
end rtl;
154

    
155

    
156
-------------------------------------------------------------------------------
157
-- halfband decimation filter - output control --------------------------------
158
-------------------------------------------------------------------------------
159

    
160
library ieee;
161
	use ieee.std_logic_1164.all;
162
	use ieee.numeric_std.all;
163
library work;
164
	use work.all;
165
	use work.mt_toolbox.all;
166
	use work.mt_filter.all;
167

    
168
entity usbrx_halfband_octrl is
169
	generic (
170
		N        : natural := 3
171
	);
172
	port (
173
		-- common
174
		clk      : in  std_logic;
175
		reset    : in  std_logic;
176
		
177
		-- input
178
		in_clk   : in  std_logic;
179
		in_chan  : in  unsigned(log2(2*N)-1 downto 0);
180
		in_data  : in  fir_dataword18;
181
		
182
		-- output
183
		out_clk  : out std_logic_vector(N-1 downto 0);
184
		out_i    : out fir_databus18(N-1 downto 0);
185
		out_q    : out fir_databus18(N-1 downto 0)
186
	);
187
end usbrx_halfband_octrl;
188

    
189
architecture rtl of usbrx_halfband_octrl is	
190

    
191
	-- cache
192
	signal tmp_i : fir_databus18(N-1 downto 0);
193

    
194
begin
195
	
196
	-- control logic
197
	process(clk)
198
		variable sel : natural range 0 to N-1;
199
	begin
200
		if rising_edge(clk) then
201
			-- set default values
202
			out_clk <= (others=>'0');
203
			
204
			-- handle input
205
			if in_clk='1' then
206
				sel := to_integer(in_chan)/2;
207
				for i in out_clk'range loop
208
					if sel=i then
209
						if in_chan(0)='0' then
210
							-- cache result
211
							tmp_i(i) <= in_data;
212
						else
213
							-- output result 
214
							out_clk(i) <= '1';
215
							out_i(i) <= tmp_i(i);
216
							out_q(i) <= in_data;
217
						end if;
218
					end if;
219
				end loop;
220
			end if;
221
			
222
			-- handle reset
223
			if reset='1' then
224
				tmp_i   <= (others=>(others=>'0'));
225
				out_clk <= (others=>'0');
226
				out_i   <= (others=>(others=>'0'));
227
				out_q   <= (others=>(others=>'0'));
228
			end if;
229
		end if;
230
	end process;
231
end rtl;
232

    
233

    
234
-------------------------------------------------------------------------------
235
-- halfband decimation filter -------------------------------------------------
236
-------------------------------------------------------------------------------
237

    
238
library ieee;
239
	use ieee.std_logic_1164.all;
240
	use ieee.numeric_std.all;
241
library work;
242
	use work.all;
243
	use work.mt_toolbox.all;
244
	use work.mt_filter.all;
245

    
246
entity usbrx_halfband is
247
	generic (
248
		N        : natural := 3
249
	);
250
	port (
251
		-- common
252
		clk      : in  std_logic;
253
		reset    : in  std_logic;
254
		
255
		-- input
256
		in_clk   : in  std_logic_vector(N-1 downto 0);
257
		in_i     : in  fir_databus18(N-1 downto 0);
258
		in_q     : in  fir_databus18(N-1 downto 0);
259
		
260
		-- output
261
		out_clk  : out std_logic_vector(N-1 downto 0);
262
		out_i    : out fir_databus18(N-1 downto 0);
263
		out_q    : out fir_databus18(N-1 downto 0)
264
	);
265
end usbrx_halfband;
266

    
267
architecture rtl of usbrx_halfband is	
268

    
269
	-- internal types
270
	type state_t is (S_IDLE, S_FILTER_I, S_FILTER_Q, S_COOLDOWN);
271
	
272
	-- status
273
	signal state : state_t;
274
	
275
	-- input control
276
	signal ic_ready : std_logic;
277
	signal ic_clk   : std_logic;
278
	signal ic_chan  : unsigned(log2(N)-1 downto 0);
279
	signal ic_i0    : fir_dataword18;
280
	signal ic_i1    : fir_dataword18;
281
	signal ic_q0    : fir_dataword18;
282
	signal ic_q1    : fir_dataword18;
283

    
284
	-- next output
285
	signal on_clk : std_logic;
286
	signal on_chan : unsigned(log2(2*N)-1 downto 0);
287
	signal on_dat1 : fir_dataword18;
288
	signal on_dat2 : fir_dataword18;
289
	
290
	-- output control
291
	signal oc_iclk  : std_logic;
292
	signal oc_ichan : unsigned(log2(2*N)-1 downto 0);
293
	signal oc_idata : fir_dataword18;
294
	
295
	-- FIR input
296
	signal fir_iclk  : std_logic;
297
	signal fir_iack  : std_logic;
298
	signal fir_idata : fir_dataword18;
299
	signal fir_ichan : unsigned(log2(2*N)-1 downto 0);
300
	
301
	-- FIR output
302
	signal fir_oclk  : std_logic;
303
	signal fir_ochan : unsigned(log2(2*N)-1 downto 0);
304
	signal fir_odata : fir_dataword18;
305
			
306
	-- center samples
307
	signal cent_i : fir_databus18(N-1 downto 0);
308
	signal cent_q : fir_databus18(N-1 downto 0);
309
	
310
	-- coefficients for 2x-FIR-interpolator
311
	-- (halfband, order 48, wpass 0.40)
312
	constant coeffs : fir_coefficients(0 to 11) := ( 
313
		  -52,    151,   -354,    715,
314
		-1307,   2227,  -3614,   5691,
315
		-8907,  14403, -26386,  82957
316
	);
317
	
318
begin
319

    
320
	-- control logic
321
	process(clk)
322
		variable sel : natural range 0 to N-1;
323
	begin
324
		if rising_edge(clk) then
325
			-- set default values
326
			fir_iclk <= '0';
327
			oc_iclk  <= '0';
328
			on_clk   <= '0';
329
		
330
			-- filter control
331
			case state is
332
				when S_IDLE =>
333
					-- wait for new sample-pair
334
					if ic_clk='1' then
335
						-- start filter (I)
336
						fir_iclk  <= '1';
337
						fir_idata <= ic_i1;
338
						fir_ichan <= resize(ic_chan & "0", fir_ichan'length);
339

    
340
						-- update status
341
						state <= S_FILTER_I;
342
					end if;
343
					
344
				when S_FILTER_I =>
345
					-- wait until filtering is done
346
					if fir_iack='1' then
347
						-- start filter (Q)
348
						fir_iclk  <= '1';
349
						fir_idata <= ic_q1;
350
						fir_ichan <= resize(ic_chan & "1", fir_ichan'length);
351
						
352
						-- update status
353
						state <= S_FILTER_Q;
354
					end if;
355
					
356
				when S_FILTER_Q =>
357
					-- wait until filtering is done
358
					if fir_iack='1' then
359
						-- update status
360
						state <= S_COOLDOWN;
361
					end if;
362
					
363
				when S_COOLDOWN =>
364
					-- TODO: get rid of state
365
					if fir_oclk='1' then
366
						state <= S_IDLE;
367
					end if;
368
			end case;
369
			
370
			-- fetch FIR result and corresonding center-sample
371
			if fir_oclk='1' then
372
				on_clk  <= '1';
373
				on_chan <= fir_ochan;
374
				on_dat1 <= fir_odata; 
375
				sel := to_integer(fir_ochan)/2;
376
				if fir_ochan(0)='0' 
377
					then on_dat2 <= cent_i(sel);
378
					else on_dat2 <= cent_q(sel);
379
				end if;
380
			end if;
381
			
382
			-- create final result
383
			if on_clk='1' then
384
				oc_iclk  <= '1';
385
				oc_ichan <= on_chan;
386
				oc_idata <= resize((resize(on_dat1,19) + resize(on_dat2,19)) / 2,18);
387
			end if;
388
			
389
			-- handle reset
390
			if reset='1' then
391
				state     <= S_IDLE;
392
				fir_iclk  <= '0';
393
				fir_idata <= (others=>'0');
394
				fir_ichan <= (others=>'0');
395
				oc_iclk   <= '0';
396
				oc_ichan  <= (others=>'0');
397
				oc_idata  <= (others=>'0');
398
				on_clk    <= '0';
399
				on_chan   <= (others=>'0');
400
				on_dat1   <= (others=>'0');
401
				on_dat2   <= (others=>'0');
402
			end if;
403
		end if;
404
	end process;
405
	
406
	-- create ready-flag
407
	ic_ready <= '1' when state=S_IDLE else '0';
408
	
409
	-- shift register for center-sample
410
	sreg: for i in 0 to N-1 generate
411
		subtype entry_t is signed(35 downto 0);
412
		type sreg_t is array(natural range<>) of entry_t;
413
		signal sreg : sreg_t(11 downto 0) := (others=>(others=>'0'));
414
	begin
415
		
416
		-- infer shift-register
417
		process(clk)
418
			variable temp : entry_t;
419
		begin
420
			if rising_edge(clk) then
421
				if ic_clk='1' and to_integer(ic_chan)=i then
422
					temp := ic_q0 & ic_i0;
423
					sreg <= sreg(sreg'left-1 downto 0) & temp;
424
				end if;
425
			end if;
426
		end process;
427
		
428
		-- output center-sample
429
		cent_i(i) <= sreg(sreg'left)(17 downto  0);
430
		cent_q(i) <= sreg(sreg'left)(35 downto 18);
431
	end generate;
432
	
433
	-- input control
434
	ic: entity usbrx_halfband_ictrl
435
		generic map (
436
			N        => N
437
		)
438
		port map (
439
			-- common
440
			clk      => clk,
441
			reset    => reset,
442
			
443
			-- input
444
			in_clk   => in_clk,
445
			in_i     => in_i,
446
			in_q     => in_q,
447
			
448
			-- output
449
			out_ready => ic_ready,
450
			out_clk   => ic_clk,
451
			out_chan  => ic_chan,
452
			out_i0    => ic_i0,
453
			out_i1    => ic_i1,
454
			out_q0    => ic_q0,
455
			out_q1    => ic_q1
456
		);
457

    
458
	-- FIR filter core
459
	fir: entity mt_fir_symmetric_slow
460
		generic map (
461
			CHANNELS  => 2*N,
462
			TAPS      => 12,
463
			COEFFS    => coeffs,
464
			RAMSTYLE  => "block_ram",
465
			ROMSTYLE  => "logic"
466
		)
467
		port map (
468
			-- common
469
			clk        => clk,
470
			reset      => reset,
471
			
472
			-- input port
473
			in_clk     => fir_iclk,
474
			in_ack     => fir_iack,
475
			in_data    => fir_idata,
476
			in_chan    => fir_ichan,
477
			
478
			-- output port
479
			out_clk    => fir_oclk,
480
			out_chan   => fir_ochan,
481
			out_data   => fir_odata
482
		);
483
	
484
	-- output control
485
	oc: entity usbrx_halfband_octrl
486
		generic map (
487
			N        => N
488
		)
489
		port map (
490
			-- common
491
			clk      => clk,
492
			reset    => reset,
493
			
494
			-- input
495
			in_clk   => oc_iclk,
496
			in_chan  => oc_ichan,
497
			in_data  => oc_idata,
498
			
499
			-- output
500
			out_clk  => out_clk,
501
			out_i    => out_i,
502
			out_q    => out_q
503
		);
504

    
505
end rtl;
    (1-1/1)
    Add picture from clipboard (Maximum size: 48.8 MB)