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 3

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

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

powered by: WebSVN 2.1.0

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