OpenCores
URL https://opencores.org/ocsvn/astron_wb_fft/astron_wb_fft/trunk

Subversion Repositories astron_wb_fft

[/] [astron_wb_fft/] [trunk/] [fft_sepa.vhd] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 danv
--------------------------------------------------------------------------------
2
-- Author: Harm Jan Pepping : HJP at astron.nl: April 2012
3
--------------------------------------------------------------------------------
4
--
5
-- Copyright (C) 2012
6
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
7
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
8
--
9
-- This program is free software: you can redistribute it and/or modify
10
-- it under the terms of the GNU General Public License as published by
11
-- the Free Software Foundation, either version 3 of the License, or
12
-- (at your option) any later version.
13
--
14
-- This program is distributed in the hope that it will be useful,
15
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
16
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
-- GNU General Public License for more details.
18
--
19
-- You should have received a copy of the GNU General Public License
20
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
--
22
--------------------------------------------------------------------------------
23
 
24
-- Purpose: Perform the separate function to support two real inputs  
25
--
26
-- Description: It composes an output stream where the bins for input A and B are
27
--              interleaved in the stream: A, B, A, B etc (for both real and imaginary part)
28
--
29
--              It is assumed that the incoming data is as follows for a 1024 point FFT: 
30
-- 
31
--              X(0), X(1024), X(1), X(1023), X(2), X(1022), etc...              
32
--                       |
33
--                       |
34
--                    This value is X(0)!!! 
35
--                                          
36
--              The function that is performed is based on the following equation: 
37
--
38
--              A.real(m) = (X.real(N-m) + X.real(m))/2
39
--              A.imag(m) = (X.imag(m)   - X.imag(N-m))/2
40
--              B.real(m) = (X.imag(m)   + X.imag(N-m))/2
41
--              B.imag(m) = (X.real(N-m) - X.real(m))/2
42
--
43
-- Remarks:
44
-- . The add and sub output of the separate have 1 bit growth that needs to be
45
--   rounded. Simply skipping 1 LSbit is not suitable, because it yields
46
--   asymmetry around 0 and thus a DC offset. For example for N = 3-bit data:
47
--              x =  -4 -3 -2 -1  0  1  2  3
48
--     round(x/2) =  -2 -2 -1 -1  0  1  1  2  = common_round for signed
49
--     floor(x/2) =  -2 -2 -1 -1  0  0  1  1  = truncation
50
--   The most negative value can be ignored:
51
--              x : mean(-3 -2 -1  0  1  2  3) = 0
52
--   . round(x/2) : mean(-2 -1 -1  0  1  1  2) = 0
53
--   . floor(x/2) : mean(-2 -1 -1  0  0  1  1) = -2/8 = -0.25 = -2^(N-1)/2 / 2^N
54
--   So the DC offset due to truncation is -0.25 LSbit, independent of N.
55
 
56
library IEEE, common_pkg_lib, common_add_sub_lib, common_requantize_lib;
57
use IEEE.std_logic_1164.ALL;
58
use IEEE.numeric_std.ALL;
59
use common_pkg_lib.common_pkg.ALL;
60
 
61
entity fft_sepa is
62
  port (
63
    clk     : in  std_logic;
64
    rst     : in  std_logic;
65
    in_dat  : in  std_logic_vector;
66
    in_val  : in  std_logic;
67
    out_dat : out std_logic_vector;
68
    out_val : out std_logic
69
  );
70
end entity fft_sepa;
71
 
72
architecture rtl of fft_sepa is
73
 
74
  constant c_sepa_round  : boolean := true;  -- must be true, because separate should round the 1 bit growth
75
 
76
  constant c_data_w   : natural := in_dat'length/c_nof_complex;
77
  constant c_c_data_w : natural := c_nof_complex*c_data_w;
78
  constant c_pipeline : natural := 3;
79
 
80
  type reg_type is record
81
    switch    : std_logic;                                 -- Register used to toggle between A & B definitionn
82
    val_dly   : std_logic_vector(c_pipeline-1 downto 0);   -- Register that delays the incoming valid signal
83
    xn_m_reg  : std_logic_vector(c_c_data_w-1 downto 0);   -- Register to hold the X(N-m) value for one cycle
84
    xm_reg    : std_logic_vector(c_c_data_w-1 downto 0);   -- Register to hold the X(m) value for one cycle
85
    add_reg_a : std_logic_vector(c_data_w-1   downto 0);   -- Input register A for the adder
86
    add_reg_b : std_logic_vector(c_data_w-1   downto 0);   -- Input register B for the adder
87
    sub_reg_a : std_logic_vector(c_data_w-1   downto 0);   -- Input register A for the subtractor
88
    sub_reg_b : std_logic_vector(c_data_w-1   downto 0);   -- Input register B for the subtractor
89
    out_dat   : std_logic_vector(c_c_data_w-1 downto 0);   -- Registered output value
90
    out_val   : std_logic;                                 -- Registered data valid signal  
91
  end record;
92
 
93
  signal r, rin     : reg_type;
94
  signal sub_result : std_logic_vector(c_data_w downto 0); -- Result of the subtractor   
95
  signal add_result : std_logic_vector(c_data_w downto 0); -- Result of the adder   
96
 
97
  signal sub_result_q : std_logic_vector(c_data_w-1 downto 0); -- Requantized result of the subtractor   
98
  signal add_result_q : std_logic_vector(c_data_w-1 downto 0); -- Requantized result of the adder
99
 
100
begin
101
 
102
  ---------------------------------------------------------------
103
  -- ADDER AND SUBTRACTOR
104
  ---------------------------------------------------------------
105
  adder : entity common_add_sub_lib.common_add_sub
106
  generic map (
107
    g_direction       => "ADD",
108
    g_representation  => "SIGNED",
109
    g_pipeline_input  => 0,
110
    g_pipeline_output => 1,
111
    g_in_dat_w        => c_data_w,
112
    g_out_dat_w       => c_data_w + 1
113
  )
114
  port map (
115
    clk     => clk,
116
    in_a    => r.add_reg_a,
117
    in_b    => r.add_reg_b,
118
    result  => add_result
119
  );
120
 
121
  subtractor : entity common_add_sub_lib.common_add_sub
122
  generic map (
123
    g_direction       => "SUB",
124
    g_representation  => "SIGNED",
125
    g_pipeline_input  => 0,
126
    g_pipeline_output => 1,
127
    g_in_dat_w        => c_data_w,
128
    g_out_dat_w       => c_data_w + 1
129
  )
130
  port map (
131
    clk     => clk,
132
    in_a    => r.sub_reg_a,
133
    in_b    => r.sub_reg_b,
134
    result  => sub_result
135
  );
136
 
137
  gen_sepa_truncate : IF c_sepa_round=FALSE GENERATE
138
    -- truncate the one LSbit
139
    add_result_q <= add_result(c_data_w downto 1);
140
    sub_result_q <= sub_result(c_data_w downto 1);
141
  end generate;
142
 
143
  gen_sepa_round : IF c_sepa_round=TRUE GENERATE
144
    -- round the one LSbit
145
    round_add : ENTITY common_requantize_lib.common_round
146
    GENERIC MAP (
147
      g_representation  => "SIGNED",  -- SIGNED (round +-0.5 away from zero to +- infinity) or UNSIGNED rounding (round 0.5 up to + inifinity)
148
      g_round           => TRUE,      -- when TRUE round the input, else truncate the input
149
      g_round_clip      => FALSE,     -- when TRUE clip rounded input >= +max to avoid wrapping to output -min (signed) or 0 (unsigned)
150
      g_pipeline_input  => 0,         -- >= 0
151
      g_pipeline_output => 0,         -- >= 0, use g_pipeline_input=0 and g_pipeline_output=0 for combinatorial output
152
      g_in_dat_w        => c_data_w+1,
153
      g_out_dat_w       => c_data_w
154
    )
155
    PORT MAP (
156
      clk        => clk,
157
      in_dat     => add_result,
158
      out_dat    => add_result_q
159
    );
160
 
161
    round_sub : ENTITY common_requantize_lib.common_round
162
    GENERIC MAP (
163
      g_representation  => "SIGNED",  -- SIGNED (round +-0.5 away from zero to +- infinity) or UNSIGNED rounding (round 0.5 up to + inifinity)
164
      g_round           => TRUE,      -- when TRUE round the input, else truncate the input
165
      g_round_clip      => FALSE,     -- when TRUE clip rounded input >= +max to avoid wrapping to output -min (signed) or 0 (unsigned)
166
      g_pipeline_input  => 0,         -- >= 0
167
      g_pipeline_output => 0,         -- >= 0, use g_pipeline_input=0 and g_pipeline_output=0 for combinatorial output
168
      g_in_dat_w        => c_data_w+1,
169
      g_out_dat_w       => c_data_w
170
    )
171
    PORT MAP (
172
      clk        => clk,
173
      in_dat     => sub_result,
174
      out_dat    => sub_result_q
175
    );
176
  end generate;
177
 
178
  ---------------------------------------------------------------
179
  -- CONTROL PROCESS
180
  ---------------------------------------------------------------
181
  comb : process(r, rst, in_val, in_dat, add_result_q, sub_result_q)
182
    variable v : reg_type;
183
  begin
184
    v := r;
185
 
186
    -- Shift register for the valid signal
187
    v.val_dly(c_pipeline-1 downto 1) := v.val_dly(c_pipeline-2 downto 0);
188
    v.val_dly(0) := in_val;
189
 
190
    -- Composition of the output registers:
191
    v.out_dat := sub_result_q & add_result_q;
192
    v.out_val := r.val_dly(c_pipeline-1);
193
 
194
    -- Compose the inputs for the adder and subtractor
195
    -- for both A and B 
196
    if in_val = '1' or r.val_dly(0) = '1' then
197
      if r.switch = '0' then
198
        v.xm_reg    := in_dat;
199
        v.add_reg_a := r.xm_reg(c_c_data_w-1   downto c_data_w);  -- Xm   imag
200
        v.add_reg_b := r.xn_m_reg(c_c_data_w-1 downto c_data_w);  -- Xn-m imag
201
        v.sub_reg_a := r.xn_m_reg(c_data_w-1   downto 0);         -- Xn-m real
202
        v.sub_reg_b := r.xm_reg(c_data_w-1     downto 0);         -- Xm   real
203
      else
204
        v.xn_m_reg  := in_dat;
205
        v.add_reg_a := r.xm_reg(c_data_w-1   downto 0);           -- Xm   real 
206
        v.add_reg_b := in_dat(c_data_w-1     downto 0);           -- Xn-m real
207
        v.sub_reg_a := r.xm_reg(c_c_data_w-1 downto c_data_w);    -- Xm   imag
208
        v.sub_reg_b := in_dat(c_c_data_w-1   downto c_data_w);    -- Xn-m imag
209
      end if;
210
    end if;
211
 
212
    if in_val = '1' then
213
      v.switch := not r.switch;
214
    end if;
215
 
216
    if(rst = '1') then
217
      v.switch    := '0';
218
      v.val_dly   := (others => '0');
219
      v.xn_m_reg  := (others => '0');
220
      v.xm_reg    := (others => '0');
221
      v.add_reg_a := (others => '0');
222
      v.add_reg_b := (others => '0');
223
      v.sub_reg_a := (others => '0');
224
      v.sub_reg_b := (others => '0');
225
      v.out_dat   := (others => '0');
226
      v.out_val   := '0';
227
    end if;
228
 
229
    rin <= v;
230
 
231
  end process comb;
232
 
233
  regs : process(clk)
234
  begin
235
    if rising_edge(clk) then
236
      r <= rin;
237
    end if;
238
  end process;
239
 
240
  ---------------------------------------------------------------
241
  -- OUTPUT STAGE
242
  ---------------------------------------------------------------
243
  out_dat <= r.out_dat;
244
  out_val <= r.out_val;
245
 
246
end rtl;
247
 
248
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.