| 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, common_components_lib, astron_adder_lib;
 | 
      
         | 22 | 2 | danv | USE IEEE.std_logic_1164.ALL;
 | 
      
         | 23 |  |  | USE IEEE.numeric_std.ALL;
 | 
      
         | 24 |  |  | USE common_pkg_lib.common_pkg.ALL;
 | 
      
         | 25 |  |  |  
 | 
      
         | 26 |  |  |  
 | 
      
         | 27 |  |  | -- Purpose:
 | 
      
         | 28 |  |  | --   Accumulate input data to an accumulator that is stored externally. In this
 | 
      
         | 29 |  |  | --   way blocks of input samples (e.g. subband products) can be accumulated to
 | 
      
         | 30 |  |  | --   a set of external accumulators. At the in_load the accumulator input value
 | 
      
         | 31 |  |  | --   is ignored so that the accumulation restarts with the in_dat.
 | 
      
         | 32 |  |  | --
 | 
      
         | 33 |  |  | -- Description:
 | 
      
         | 34 |  |  | --   if in_load = '1' then
 | 
      
         | 35 |  |  | --     out_acc = in_dat + 0         -- restart accumulation
 | 
      
         | 36 |  |  | --   else
 | 
      
         | 37 |  |  | --     out_acc = in_dat + in_acc    -- accumulate
 | 
      
         | 38 |  |  | --
 | 
      
         | 39 |  |  | -- Remarks:
 | 
      
         | 40 |  |  | -- . in_val propagates to out_val after the pipeline latency but does not 
 | 
      
         | 41 |  |  | --   affect the sum
 | 
      
         | 42 |  |  |  
 | 
      
         | 43 |  |  | ENTITY st_acc IS
 | 
      
         | 44 |  |  |   GENERIC (
 | 
      
         | 45 |  |  |     g_dat_w            : NATURAL;
 | 
      
         | 46 |  |  |     g_acc_w            : NATURAL;  -- g_acc_w >= g_dat_w
 | 
      
         | 47 |  |  |     g_hold_load        : BOOLEAN := TRUE;
 | 
      
         | 48 |  |  |     g_pipeline_input   : NATURAL;  -- 0 no input registers, else register input after in_load
 | 
      
         | 49 |  |  |     g_pipeline_output  : NATURAL   -- pipeline for the adder
 | 
      
         | 50 |  |  |   );
 | 
      
         | 51 |  |  |   PORT (
 | 
      
         | 52 |  |  |     clk         : IN  STD_LOGIC;
 | 
      
         | 53 |  |  |     clken       : IN  STD_LOGIC := '1';
 | 
      
         | 54 |  |  |     in_load     : IN  STD_LOGIC;
 | 
      
         | 55 |  |  |     in_dat      : IN  STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
 | 
      
         | 56 |  |  |     in_acc      : IN  STD_LOGIC_VECTOR(g_acc_w-1 DOWNTO 0);
 | 
      
         | 57 |  |  |     in_val      : IN  STD_LOGIC := '1';
 | 
      
         | 58 |  |  |     out_acc     : OUT STD_LOGIC_VECTOR(g_acc_w-1 DOWNTO 0);
 | 
      
         | 59 |  |  |     out_val     : OUT STD_LOGIC
 | 
      
         | 60 |  |  |   );
 | 
      
         | 61 |  |  | END st_acc;
 | 
      
         | 62 |  |  |  
 | 
      
         | 63 |  |  |  
 | 
      
         | 64 |  |  | ARCHITECTURE rtl OF st_acc IS
 | 
      
         | 65 |  |  |  
 | 
      
         | 66 |  |  |   CONSTANT c_pipeline  : NATURAL := g_pipeline_input + g_pipeline_output;
 | 
      
         | 67 |  |  |  
 | 
      
         | 68 |  |  |   -- Input signals
 | 
      
         | 69 |  |  |   SIGNAL hld_load        : STD_LOGIC := '0';
 | 
      
         | 70 |  |  |   SIGNAL nxt_hld_load    : STD_LOGIC;
 | 
      
         | 71 |  |  |   SIGNAL acc_clr        : STD_LOGIC;
 | 
      
         | 72 |  |  |  
 | 
      
         | 73 |  |  |   SIGNAL reg_dat        : STD_LOGIC_VECTOR(g_acc_w-1 DOWNTO 0) := (OTHERS=>'0');
 | 
      
         | 74 |  |  |   SIGNAL nxt_reg_dat    : STD_LOGIC_VECTOR(g_acc_w-1 DOWNTO 0);
 | 
      
         | 75 |  |  |   SIGNAL reg_acc        : STD_LOGIC_VECTOR(g_acc_w-1 DOWNTO 0) := (OTHERS=>'0');
 | 
      
         | 76 |  |  |   SIGNAL nxt_reg_acc    : STD_LOGIC_VECTOR(g_acc_w-1 DOWNTO 0);
 | 
      
         | 77 |  |  |  
 | 
      
         | 78 |  |  |   -- Pipeline control signals, map to slv to be able to use common_pipeline
 | 
      
         | 79 |  |  |   SIGNAL in_val_slv     : STD_LOGIC_VECTOR(0 DOWNTO 0);
 | 
      
         | 80 |  |  |   SIGNAL out_val_slv    : STD_LOGIC_VECTOR(0 DOWNTO 0);
 | 
      
         | 81 |  |  |  
 | 
      
         | 82 |  |  | BEGIN
 | 
      
         | 83 |  |  |  
 | 
      
         | 84 |  |  |   ASSERT NOT(g_acc_w < g_dat_w)
 | 
      
         | 85 |  |  |     REPORT "st_acc: output accumulator width must be >= input data width"
 | 
      
         | 86 |  |  |     SEVERITY FAILURE;
 | 
      
         | 87 |  |  |  
 | 
      
         | 88 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 89 |  |  |   -- Input load control
 | 
      
         | 90 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 91 |  |  |  
 | 
      
         | 92 |  |  |   p_clk : PROCESS(clk)
 | 
      
         | 93 |  |  |   BEGIN
 | 
      
         | 94 |  |  |     IF rising_edge(clk) THEN
 | 
      
         | 95 |  |  |       IF clken='1' THEN
 | 
      
         | 96 |  |  |         hld_load <= nxt_hld_load;
 | 
      
         | 97 |  |  |       END IF;
 | 
      
         | 98 |  |  |     END IF;
 | 
      
         | 99 |  |  |   END PROCESS;
 | 
      
         | 100 |  |  |  
 | 
      
         | 101 |  |  |   nxt_hld_load <= in_load WHEN in_val='1' ELSE hld_load;
 | 
      
         | 102 |  |  |  
 | 
      
         | 103 |  |  |   -- Hold in_load to save power by avoiding unneccessary out_acc toggling when in_val goes low  
 | 
      
         | 104 |  |  |   -- . For g_pipeline_input>0 this is fine
 | 
      
         | 105 |  |  |   -- . For g_pipeline_input=0 this may cause difficulty in achieving timing closure for synthesis
 | 
      
         | 106 |  |  |   use_in_load : IF g_hold_load = FALSE GENERATE
 | 
      
         | 107 |  |  |     acc_clr <= in_load;  -- the in_load may already be extended during in_val
 | 
      
         | 108 |  |  |   END GENERATE;
 | 
      
         | 109 |  |  |   use_hld_load : IF g_hold_load = TRUE GENERATE
 | 
      
         | 110 |  |  |     acc_clr <= in_load OR (hld_load AND NOT in_val);
 | 
      
         | 111 |  |  |   END GENERATE;
 | 
      
         | 112 |  |  |  
 | 
      
         | 113 |  |  |   -- Do not use g_pipeline_input of u_adder, to allow registered acc clear if g_pipeline_input=1
 | 
      
         | 114 |  |  |   nxt_reg_dat <= RESIZE_SVEC(in_dat, g_acc_w);
 | 
      
         | 115 |  |  |   nxt_reg_acc <= in_acc WHEN acc_clr='0' ELSE (OTHERS=>'0');
 | 
      
         | 116 |  |  |  
 | 
      
         | 117 |  |  |   no_input_reg : IF g_pipeline_input=0 GENERATE
 | 
      
         | 118 |  |  |     reg_dat <= nxt_reg_dat;
 | 
      
         | 119 |  |  |     reg_acc <= nxt_reg_acc;
 | 
      
         | 120 |  |  |   END GENERATE;
 | 
      
         | 121 |  |  |   gen_input_reg : IF g_pipeline_input>0 GENERATE
 | 
      
         | 122 |  |  |     p_reg : PROCESS(clk)
 | 
      
         | 123 |  |  |     BEGIN
 | 
      
         | 124 |  |  |       IF rising_edge(clk) THEN
 | 
      
         | 125 |  |  |         IF clken='1' THEN
 | 
      
         | 126 |  |  |           reg_dat <= nxt_reg_dat;
 | 
      
         | 127 |  |  |           reg_acc <= nxt_reg_acc;
 | 
      
         | 128 |  |  |         END IF;
 | 
      
         | 129 |  |  |       END IF;
 | 
      
         | 130 |  |  |     END PROCESS;
 | 
      
         | 131 |  |  |   END GENERATE;
 | 
      
         | 132 |  |  |  
 | 
      
         | 133 |  |  |  
 | 
      
         | 134 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 135 |  |  |   -- Adder for the external accumulator
 | 
      
         | 136 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 137 |  |  |  
 | 
      
         | 138 | 4 | danv |   u_adder : ENTITY astron_adder_lib.common_add_sub
 | 
      
         | 139 | 2 | danv |   GENERIC MAP (
 | 
      
         | 140 |  |  |     g_direction       => "ADD",
 | 
      
         | 141 |  |  |     g_representation  => "SIGNED",  -- not relevant because g_out_dat_w = g_in_dat_w
 | 
      
         | 142 |  |  |     g_pipeline_input  => 0,
 | 
      
         | 143 |  |  |     g_pipeline_output => g_pipeline_output,
 | 
      
         | 144 |  |  |     g_in_dat_w        => g_acc_w,
 | 
      
         | 145 |  |  |     g_out_dat_w       => g_acc_w
 | 
      
         | 146 |  |  |   )
 | 
      
         | 147 |  |  |   PORT MAP (
 | 
      
         | 148 |  |  |     clk     => clk,
 | 
      
         | 149 |  |  |     clken   => clken,
 | 
      
         | 150 |  |  |     in_a    => reg_dat,
 | 
      
         | 151 |  |  |     in_b    => reg_acc,
 | 
      
         | 152 |  |  |     result  => out_acc
 | 
      
         | 153 |  |  |   );
 | 
      
         | 154 |  |  |  
 | 
      
         | 155 |  |  |  
 | 
      
         | 156 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 157 |  |  |   -- Parallel output control pipeline
 | 
      
         | 158 |  |  |   ------------------------------------------------------------------------------
 | 
      
         | 159 |  |  |  
 | 
      
         | 160 |  |  |   in_val_slv(0) <= in_val;
 | 
      
         | 161 |  |  |   out_val       <= out_val_slv(0);
 | 
      
         | 162 |  |  |  
 | 
      
         | 163 |  |  |   u_out_val : ENTITY common_components_lib.common_pipeline
 | 
      
         | 164 |  |  |   GENERIC MAP (
 | 
      
         | 165 |  |  |     g_representation => "UNSIGNED",
 | 
      
         | 166 |  |  |     g_pipeline       => c_pipeline,
 | 
      
         | 167 |  |  |     g_reset_value    => 0,
 | 
      
         | 168 |  |  |     g_in_dat_w       => 1,
 | 
      
         | 169 |  |  |     g_out_dat_w      => 1
 | 
      
         | 170 |  |  |   )
 | 
      
         | 171 |  |  |   PORT MAP (
 | 
      
         | 172 |  |  |     clk     => clk,
 | 
      
         | 173 |  |  |     clken   => clken,
 | 
      
         | 174 |  |  |     in_dat  => slv(in_val),
 | 
      
         | 175 |  |  |     out_dat => out_val_slv
 | 
      
         | 176 |  |  |   );
 | 
      
         | 177 |  |  |  
 | 
      
         | 178 |  |  | END rtl;
 |