-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcic.v
138 lines (118 loc) · 4.37 KB
/
cic.v
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
//
// cic - A Cascaded Integrator-Comb filter
//
// Copyright (c) 2008 Alex Shovkoplyas, VE3NEA
// Copyright (c) 2013 Phil Harman, VK6PH
// Copyright (c) 2015 Jeremy McDermond, NH6Z
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
// Boston, MA 02110-1301, USA.
// 2013 Jan 26 - Modified to accept decimation values from 1-40. VK6APH
module cic(reset, decimation, clock, in_strobe, out_strobe, in_data, out_data);
//design parameters
parameter STAGES = 5; // Sections of both Comb and Integrate
parameter MIN_DECIMATION = 2; // If MIN = MAX, we are single-rate filter
parameter MAX_DECIMATION = 40;
parameter IN_WIDTH = 18;
parameter OUT_WIDTH = 18;
// derived parameters
parameter ACC_WIDTH = IN_WIDTH + (STAGES * $clog2(MAX_DECIMATION));
input [$clog2(MAX_DECIMATION):0] decimation;
input reset;
input clock;
input in_strobe;
output reg out_strobe;
input signed [IN_WIDTH-1:0] in_data;
output signed [OUT_WIDTH-1:0] out_data;
//------------------------------------------------------------------------------
// control
//------------------------------------------------------------------------------
reg [$clog2(MAX_DECIMATION)-1:0] sample_no = 0;
generate
if(MIN_DECIMATION == MAX_DECIMATION)
always @(posedge clock)
if (in_strobe)
if (sample_no == (MAX_DECIMATION - 1'd1)) begin
sample_no <= 0;
out_strobe <= 1;
end else begin
sample_no <= sample_no + 1'd1;
out_strobe <= 0;
end
else
out_strobe <= 0;
else
always @(posedge clock)
if (in_strobe)
if (sample_no == (decimation - 1'd1)) begin
sample_no <= 0;
out_strobe <= 1;
end else begin
sample_no <= sample_no + 1'd1;
out_strobe <= 0;
end
else
out_strobe <= 0;
endgenerate
//------------------------------------------------------------------------------
// stages
//------------------------------------------------------------------------------
reg signed [ACC_WIDTH-1:0] integrator_data [1:STAGES] = '{default: '0};
reg signed [ACC_WIDTH-1:0] comb_data [1:STAGES] = '{default: '0};
reg signed [ACC_WIDTH-1:0] comb_last [0:STAGES] = '{default: '0};
always @(posedge clock) begin
integer index;
// Integrators
if (reset) begin
for(index = 1; index < STAGES + 1; index = index + 1) begin
integrator_data[index] <= 0;
end
end
else
if(in_strobe) begin
integrator_data[1] <= integrator_data[1] + in_data;
for(index = 1; index < STAGES; index = index + 1) begin
integrator_data[index + 1] <= integrator_data[index] + integrator_data[index+1];
end
end
// Combs
if(reset) begin
for(index = 1; index < STAGES + 1; index = index + 1) begin
comb_data[index] <= 0;
end
end
if(out_strobe) begin
comb_data[1] <= integrator_data[STAGES] - comb_last[0];
comb_last[0] <= integrator_data[STAGES];
for(index = 1; index < STAGES; index = index + 1) begin
comb_data[index + 1] <= comb_data[index] - comb_last[index];
comb_last[index] <= comb_data[index];
end
end
end
//------------------------------------------------------------------------------
// output rounding
//------------------------------------------------------------------------------
genvar i;
generate
if(MIN_DECIMATION == MAX_DECIMATION) begin
assign out_data = comb_data[STAGES][ACC_WIDTH - 1 -: OUT_WIDTH] + comb_data[STAGES][ACC_WIDTH - OUT_WIDTH - 1];
end else begin
wire [$clog2(ACC_WIDTH)-1:0] msb [MAX_DECIMATION:MIN_DECIMATION];
for(i = MIN_DECIMATION; i <= MAX_DECIMATION; i = i + 1) begin: round_position
assign msb[i] = IN_WIDTH + ($clog2(i) * STAGES) - 1 ;
end
assign out_data = comb_data[STAGES][msb[decimation] -: OUT_WIDTH] + comb_data[STAGES][msb[decimation] - OUT_WIDTH];
end
endgenerate
endmodule