aboutsummaryrefslogtreecommitdiffstats
path: root/testsuite/gna/bug24065/cic_up.vhd
blob: a07c48396be8753746d215c5366beb547dfbae6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

entity cic_up is
   generic(
      num_bits   : natural := 16;   -- How many bits in our incoming data?
      num_stages : natural :=  3;   -- How many stages in the CIC? (N)
      resamp     : natural := 32;   -- By what factor are we changing our data rate? (R)
      diff_dly   : natural :=  1;   -- The differential delay (M)
      out_rate   : natural :=  8);  -- Number of clocks per output sample
                                    --  Must be a power of two
   port(
      clk_i   : in  std_logic;
      rst_i   : in  std_logic;
      -- Input ports
      data_i  : in  std_logic_vector(num_bits-1 downto 0);
      valid_i : in  std_logic;
      -- Output samples
      data_o  : out std_logic_vector;
      valid_o : out std_logic);
end entity cic_up;

architecture behavior of cic_up is
   -----------------------------------------------------------------------------
   -- Functions
   -----------------------------------------------------------------------------
   function log(b,n: positive) return natural is
      variable temp   : natural := 1;
      variable answer : natural := 0;
   begin
      while temp < n loop
         answer := answer + 1;
         temp   := temp * b;
      end loop;
      return answer;
   end function log;

   -----------------------------------------------------------------------------
   function signed_add(l,r: std_logic_vector) return std_logic_vector is
      variable resized_r : signed(r'high+1 downto r'low);
   begin
      resized_r := resize(signed(r), r'length+1);
      return std_logic_vector(signed(l) + resized_r);
   end function signed_add;

   -----------------------------------------------------------------------------
   function signed_sub(l,r: std_logic_vector) return std_logic_vector is
      variable resized_r : signed(r'high+1 downto r'low);
   begin
      resized_r := resize(signed(r), r'length+1);
      return std_logic_vector(signed(l) - resized_r);
   end function signed_sub;

   -----------------------------------------------------------------------------
   impure function input_bits return natural is
      variable a, b, c : integer;
   begin
      a := (num_bits   + 1);
      b := (num_stages - 2)*(log(2,resamp));
      c := (num_stages - 1)*(log(2,diff_dly));
      return a + b + c;
   end function input_bits;

   -----------------------------------------------------------------------------
   impure function output_bits return natural is
      variable a, b, c : integer;
   begin
      a := (num_bits   + 0);
      b := (num_stages - 1)*(log(2,resamp));
      c := (num_stages - 0)*(log(2,diff_dly));
      return a + b + c;
   end function output_bits;

   -----------------------------------------------------------------------------
   -- Types, subtypes, and constants
   -----------------------------------------------------------------------------
   -- Bit growth constants
   constant direction     : string    := "up";
   subtype int_i_range    is natural range  input_bits-1     downto 0;
   subtype int_o_range    is natural range output_bits-1     downto 0;
   subtype comb_sum_range is natural range num_bits          downto 0;
   subtype count_range    is natural range log(2,out_rate)-1 downto 0;
   -- Array type for differential delay
   subtype word      is std_logic_vector(num_bits-1 downto 0);
   type comb_reg_type   is array (integer range <>) of word;
   -----------------------------------------------------------------------------
   -- Signals
   -----------------------------------------------------------------------------
   signal comb_reg : comb_reg_type(0 to diff_dly-1)  := (others => (others => '0'));
   signal comb_sum : std_logic_vector(comb_sum_range):= (others => '0');
   signal int_in   : std_logic_vector(int_i_range);
   signal int_sum  : signed          (int_o_range)   := (others => '0');
   signal int_en   : std_logic;
   signal count    : unsigned(count_range)           := (others => '0');
   signal c_dly    : std_logic;
begin
   -----------------------------------------------------------------------------
   -- Map outputs
   -----------------------------------------------------------------------------
   data_o <= std_logic_vector(int_sum);

   -----------------------------------------------------------------------------
   -- Comb (derivative) section
   -----------------------------------------------------------------------------
   comb_proc : process(clk_i)
   begin
      if rising_edge(clk_i) then
         -- Comb registers
         if rst_i = '1' then
            comb_reg <= (others => (others => '0'));
            comb_sum <= (others => '0');
         elsif valid_i = '1' then
            comb_reg <= data_i & comb_reg(0 to comb_reg'high-1);
            comb_sum <= signed_sub(data_i, comb_reg(comb_reg'high));
         end if;
      end if;
   end process comb_proc;

   -----------------------------------------------------------------------------
   -- Integrator section
   -----------------------------------------------------------------------------
   int_proc : process(clk_i)
   begin
      if rising_edge(clk_i) then
         -- Integrator registers
         if rst_i = '1' then
            int_sum  <= (others => '0');
         else
            if num_stages = 1 then
               -- The connection between the ints and the combs is determined
               --  by the generic out_rate.  This is indirectly controlled by
               --  the top bit in count, which counts to out_rate.
               if out_rate = 1 then
                  valid_o <= '1';
               else
                  valid_o <= count(count'left) and not c_dly;
               end if;

               -- The size of the first integrator register could be a different
               --  size from the last stage of the combs.  This should make up
               --  that difference.
               if valid_i = '1' then
                  int_sum <= resize(int_sum + signed(comb_sum), int_sum'length);
               end if;

            -- Every other stage of the integrators is controlled by the enable
            --  signal of the previous stage
            elsif int_en = '1' then
               int_sum <= int_sum + signed(int_in);
               valid_o <= '1';
            else
               valid_o <= '0';
            end if;
         end if;
      end if;
   end process int_proc;

   -----------------------------------------------------------------------------
   -- Recursive instantiation and termination
   -----------------------------------------------------------------------------
   cic_gen : if num_stages > 1 generate
   begin
      cic_inst : entity work.cic_up
         generic map(
            num_bits   => num_bits+1,
            num_stages => num_stages-1,
            diff_dly   => diff_dly,
            resamp     => resamp,
            out_rate   => out_rate)
         port map(
            clk_i   => clk_i,
            rst_i   => rst_i,
            -- Input ports
            data_i  => comb_sum,
            valid_i => valid_i,
            -- Output samples
            data_o  => int_in,
            valid_o => int_en);
   end generate cic_gen;

   valid_gen : if num_stages = 1 generate
   begin
      vary_valid_o : if out_rate /= 1 generate
      begin
         valid_o_proc : process(clk_i)
         begin
            if rising_edge(clk_i) then
               if rst_i = '1' then
                  count <= (others => '0');
                  c_dly <= '0';
               else
                  count <= count + 1;
                  c_dly <= count(count'left);
               end if;
            end if;
         end process valid_o_proc;
      end generate vary_valid_o;
   end generate valid_gen;

end architecture behavior;