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;
|