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

Subversion Repositories astron_statistics

[/] [astron_statistics/] [trunk/] [st_calc.vhd] - Blame information for rev 4

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 4 danv
LIBRARY IEEE, common_pkg_lib, astron_ram_lib, astron_multiplier_lib;
22 2 danv
USE IEEE.std_logic_1164.ALL;
23 4 danv
--USE technology_lib.technology_select_pkg.ALL;
24 2 danv
USE common_pkg_lib.common_pkg.ALL;
25 4 danv
USE astron_ram_lib.common_ram_pkg.ALL;
26 2 danv
 
27
-- Purpose:
28
--   Maintain a set of accumulators and output their values at every in_sync.
29
-- Description:
30
-- . The products of two input streams are accumulated per block. The block
31
--   size is g_nof_mux*g_nof_stat. The nof accumulators is equal to the block
32
--   size. The nof blocks that get accumulated depends on in_sync, because a
33
--   new accumulation starts every time when in_sync pulses. Also when in_sync
34
--   pulses then after some latency the accumulation values of the previous
35
--   in_sync interval become available at the out_* ports.
36
-- . If g_complex = FALSE then only the real power statistic out_re is calculated,
37
--   else also the imaginary power statistic out_im. The real power statistic
38
--   is used for auto power calulations of a complex input, by connecting the
39
--   signal to both input a and b. The imaginary is power statistic is used when
40
--   the cross power needs to be calculated between 2 different complex inputs.
41
-- Remarks:
42
-- . The required accumulator width depends the input data width and the nof of
43
--   block, i.e. the nof accumulations. E.g. for 18b*18b = 36b products and
44
--   200000 accumulations yielding 18b bit growth so in total 36b+18b = 54b for
45
--   the accumulators.
46
-- . The nof accumulators determines the size (c_mem_acc) of the internal
47
--   accumulator memory.
48
-- . Using g_nof_mux>1 allows distinghuising different streams with a block.
49
--   The g_nof_mux does not impact the address range instead it impacts the
50
--   out_val_m strobes that can be used as wr_en to the corresponding statistics
51
--   output register in a range of g_nof_mux statistics output registers.
52
 
53
ENTITY st_calc IS
54
  GENERIC (
55 4 danv
    g_technology   : NATURAL := 0;
56 2 danv
    g_nof_mux      : NATURAL := 1;
57
    g_nof_stat     : NATURAL := 512;
58
    g_in_dat_w     : NATURAL := 18;  -- = input data width
59
    g_out_dat_w    : NATURAL := 54;  -- = accumulator width for the input data products, so >> 2*g_in_dat_w
60
    g_out_adr_w    : NATURAL := 9;   -- = ceil_log2(g_nof_stat)
61
    g_complex      : BOOLEAN := FALSE
62
  );
63
  PORT (
64
    rst            : IN   STD_LOGIC;
65
    clk            : IN   STD_LOGIC;
66
    clken          : IN   STD_LOGIC := '1';
67
    in_ar          : IN   STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
68
    in_ai          : IN   STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
69
    in_br          : IN   STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
70
    in_bi          : IN   STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
71
    in_val         : IN   STD_LOGIC;
72
    in_sync        : IN   STD_LOGIC;
73
    out_adr        : OUT  STD_LOGIC_VECTOR(g_out_adr_w-1 DOWNTO 0);
74
    out_re         : OUT  STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
75
    out_im         : OUT  STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
76
    out_val        : OUT  STD_LOGIC;                                -- Use when g_nof_mux = 1, else leave OPEN
77
    out_val_m      : OUT  STD_LOGIC_VECTOR(g_nof_mux-1 DOWNTO 0)    -- Use when g_nof_mux > 1, else leave OPEN
78
  );
79
END;
80
 
81
 
82
ARCHITECTURE str OF st_calc IS
83
 
84
  CONSTANT c_mux_w           : NATURAL := true_log2(g_nof_mux);
85
  CONSTANT c_adr_w           : NATURAL := c_mux_w+g_out_adr_w;   -- = = ceil_log2(g_nof_mux*g_nof_stat)
86
 
87
  CONSTANT c_dly_rd          : NATURAL := 2;
88
  CONSTANT c_dly_mul         : NATURAL := 3;
89
  CONSTANT c_dly_acc         : NATURAL := 2;
90
  CONSTANT c_dly_out         : NATURAL := 0;
91
 
92
  CONSTANT c_mult_w          : NATURAL := 2*g_in_dat_w;
93
 
94
  CONSTANT c_acc_w           : NATURAL := g_out_dat_w;
95
  CONSTANT c_acc_hold_load   : BOOLEAN := TRUE;
96
 
97
  CONSTANT c_rd_latency      : NATURAL := 2;
98
  CONSTANT c_mem_acc         : t_c_mem := (c_rd_latency, c_adr_w,  c_acc_w, g_nof_mux*g_nof_stat, 'X');  -- 1 M9K
99
 
100
 
101
  SIGNAL mult_re       : STD_LOGIC_VECTOR(c_mult_w-1 DOWNTO 0);
102
  SIGNAL mult_im       : STD_LOGIC_VECTOR(c_mult_w-1 DOWNTO 0);
103
 
104
  SIGNAL reg_ar        : STD_LOGIC_VECTOR(in_ar'RANGE);
105
  SIGNAL reg_ai        : STD_LOGIC_VECTOR(in_ai'RANGE);
106
  SIGNAL reg_br        : STD_LOGIC_VECTOR(in_br'RANGE);
107
  SIGNAL reg_bi        : STD_LOGIC_VECTOR(in_bi'RANGE);
108
  SIGNAL reg_val       : STD_LOGIC;
109
  SIGNAL reg_sync      : STD_LOGIC;
110
 
111
  SIGNAL nxt_reg_ar    : STD_LOGIC_VECTOR(in_ar'RANGE);
112
  SIGNAL nxt_reg_ai    : STD_LOGIC_VECTOR(in_ai'RANGE);
113
  SIGNAL nxt_reg_br    : STD_LOGIC_VECTOR(in_br'RANGE);
114
  SIGNAL nxt_reg_bi    : STD_LOGIC_VECTOR(in_bi'RANGE);
115
  SIGNAL nxt_reg_val   : STD_LOGIC;
116
  SIGNAL nxt_reg_sync  : STD_LOGIC;
117
 
118
  SIGNAL acc_load      : STD_LOGIC;
119
 
120
  SIGNAL rd_en         : STD_LOGIC;
121
  SIGNAL rd_adr        : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0);
122
  SIGNAL rd_re         : STD_LOGIC_VECTOR(c_acc_w-1 DOWNTO 0);
123
  SIGNAL rd_im         : STD_LOGIC_VECTOR(c_acc_w-1 DOWNTO 0);
124
 
125
  SIGNAL wr_en         : STD_LOGIC;
126
  SIGNAL wr_adr        : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0);
127
  SIGNAL wr_re         : STD_LOGIC_VECTOR(c_acc_w-1 DOWNTO 0);
128
  SIGNAL wr_im         : STD_LOGIC_VECTOR(c_acc_w-1 DOWNTO 0);
129
 
130
  SIGNAL out_adr_m     : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0);
131
 
132
BEGIN
133
 
134
  regs: PROCESS(rst,clk)
135
  BEGIN
136
    IF rst='1' THEN
137
      reg_ar   <= (OTHERS => '0');
138
      reg_ai   <= (OTHERS => '0');
139
      reg_br   <= (OTHERS => '0');
140
      reg_bi   <= (OTHERS => '0');
141
      reg_val  <= '0';
142
      reg_sync <= '0';
143
    ELSIF rising_edge(clk) THEN
144
      reg_ar   <= nxt_reg_ar;
145
      reg_ai   <= nxt_reg_ai;
146
      reg_br   <= nxt_reg_br;
147
      reg_bi   <= nxt_reg_bi;
148
      reg_val  <= nxt_reg_val;
149
      reg_sync <= nxt_reg_sync;
150
    END IF;
151
  END PROCESS;
152
 
153
  nxt_reg_ar   <= in_ar WHEN in_val='1' ELSE reg_ar;
154
  nxt_reg_ai   <= in_ai WHEN in_val='1' ELSE reg_ai;
155
  nxt_reg_br   <= in_br WHEN in_val='1' ELSE reg_br;
156
  nxt_reg_bi   <= in_bi WHEN in_val='1' ELSE reg_bi;
157
  nxt_reg_val  <= in_val;
158
  nxt_reg_sync <= in_sync;
159
 
160
  -- ctrl block: generates all ctrl signals   
161
  ctrl: ENTITY work.st_ctrl
162
  GENERIC MAP (
163
    g_nof_mux    => g_nof_mux,
164
    g_nof_stat   => g_nof_stat,
165
    g_adr_w      => c_adr_w,
166
    g_dly_rd     => c_dly_rd,
167
    g_dly_mul    => c_dly_mul,
168
    g_dly_acc    => c_dly_acc,
169
    g_dly_out    => c_dly_out
170
  )
171
  PORT MAP (
172
    rst          => rst,
173
    clk          => clk,
174
    in_sync      => reg_sync,
175
    in_val       => reg_val,
176
    rd_en        => rd_en,
177
    rd_adr       => rd_adr,
178
    rd_val       => OPEN,
179
    mult_val     => OPEN,
180
    acc_load     => acc_load,
181
    wr_en        => wr_en,
182
    wr_adr       => wr_adr,
183
    out_val      => out_val,
184
    out_val_m    => out_val_m,
185
    out_adr      => out_adr_m
186
  );
187
 
188
  out_adr <= out_adr_m(c_adr_w-1 DOWNTO c_mux_w);
189
 
190
  -- complex multiplier: computes a * conj(b)
191
  --mul: ENTITY common_lib.common_complex_mult(str)
192 4 danv
  mul: ENTITY astron_multiplier_lib.common_complex_mult
193 2 danv
  GENERIC MAP (
194
    g_technology       => g_technology,
195
    g_variant          => "IP",
196
    g_in_a_w           => in_ar'LENGTH,
197
    g_in_b_w           => in_br'LENGTH,
198
    g_out_p_w          => mult_re'LENGTH,
199
    g_conjugate_b      => TRUE,  -- use conjugate product for cross power
200
    g_pipeline_input   => 1,
201
    g_pipeline_product => 0,
202
    g_pipeline_adder   => 1,
203
    g_pipeline_output  => 1   -- 1+0+1+1 = 3 = c_dly_mul
204
  )
205
  PORT MAP (
206
    clk        => clk,
207
    clken      => clken,
208
    in_ar      => reg_ar,
209
    in_ai      => reg_ai,
210
    in_br      => reg_br,
211
    in_bi      => reg_bi,
212
    out_pr     => mult_re,
213
    out_pi     => mult_im
214
  );
215
 
216
  -- accumulator for real part  
217
  acc_re: ENTITY work.st_acc
218
  GENERIC MAP (
219
    g_dat_w           => c_mult_w,
220
    g_acc_w           => c_acc_w,
221
    g_hold_load       => c_acc_hold_load,
222
    g_pipeline_input  => 1,
223
    g_pipeline_output => c_dly_acc-1
224
  )
225
  PORT MAP (
226
    clk         => clk,
227
    clken       => clken,
228
    in_load     => acc_load,
229
    in_dat      => mult_re,
230
    in_acc      => rd_re,
231
    out_acc     => wr_re
232
  );
233
 
234
  -- accumulator memory for real part  
235 4 danv
  ram_re: ENTITY astron_ram_lib.common_ram_r_w
236 2 danv
  GENERIC MAP (
237
    g_technology => g_technology,
238
    g_ram        => c_mem_acc,
239
    g_init_file  => "UNUSED"
240
  )
241
  PORT MAP (
242
    rst       => rst,
243
    clk       => clk,
244
    clken     => clken,
245
    wr_en     => wr_en,
246
    wr_adr    => wr_adr,
247
    wr_dat    => wr_re,
248
    rd_en     => rd_en,
249
    rd_adr    => rd_adr,
250
    rd_dat    => rd_re,
251
    rd_val    => OPEN
252
  );
253
 
254
  out_re <= rd_re;  -- c_dly_out = 0
255
 
256
  -- imaginary part is optional  
257
  no_im: IF g_complex=FALSE GENERATE
258
    out_im <= (OTHERS => '0');
259
  END GENERATE;
260
 
261
  gen_im: IF g_complex=TRUE GENERATE
262
    -- accumulator
263
    acc_im: ENTITY work.st_acc
264
    GENERIC MAP (
265
      g_dat_w           => c_mult_w,
266
      g_acc_w           => c_acc_w,
267
      g_hold_load       => c_acc_hold_load,
268
      g_pipeline_input  => 1,
269
      g_pipeline_output => c_dly_acc-1
270
    )
271
    PORT MAP (
272
      clk         => clk,
273
      clken       => clken,
274
      in_load     => acc_load,
275
      in_dat      => mult_im,
276
      in_acc      => rd_im,
277
      out_acc     => wr_im
278
    );
279
 
280
    -- dual port memory
281 4 danv
    ram_im: ENTITY astron_ram_lib.common_ram_r_w
282 2 danv
    GENERIC MAP (
283
      g_technology => g_technology,
284
      g_ram        => c_mem_acc,
285
      g_init_file  => "UNUSED"
286
    )
287
    PORT MAP (
288
      rst       => rst,
289
      clk       => clk,
290
      clken     => clken,
291
      wr_en     => wr_en,
292
      wr_adr    => wr_adr,
293
      wr_dat    => wr_im,
294
      rd_en     => rd_en,
295
      rd_adr    => rd_adr,
296
      rd_dat    => rd_im,
297
      rd_val    => OPEN
298
    );
299
 
300
    out_im <= rd_im;  -- c_dly_out = 0
301
  END GENERATE;
302
 
303
END str;

powered by: WebSVN 2.1.0

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