1 |
4 |
Juzujka |
`timescale 1ns / 1ns
|
2 |
|
|
module cic_d_tb
|
3 |
|
|
(
|
4 |
|
|
);
|
5 |
|
|
`include "../../../rtl/verilog/cic_functions.vh"
|
6 |
|
|
`define M_PI 3.14159265359 // not all simulators defines PI
|
7 |
|
|
/*
|
8 |
|
|
// U. Meyer-Baese, Digital Signal Processing with Field Programmable Gate Arrays, 2nd Edition, Spinger, 2004.
|
9 |
|
|
// Example 5.5: Three-Stages CIC Decimator II
|
10 |
|
|
localparam CIC_R = 32;
|
11 |
|
|
localparam SAMP_INP_DW = 8;
|
12 |
|
|
localparam SAMP_OUT_DW = 10;
|
13 |
|
|
localparam CIC_N = 3;
|
14 |
|
|
localparam CIC_M = 2;*/
|
15 |
|
|
localparam CIC_R = 100;
|
16 |
|
|
localparam SAMP_INP_DW = 18;
|
17 |
|
|
localparam SAMP_OUT_DW = 18;
|
18 |
|
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 2;
|
19 |
|
|
localparam CIC_N = 7;
|
20 |
|
|
localparam CIC_M = 1;
|
21 |
|
|
localparam SMALL_FOOTPRINT = 1; ///< set to 1 for less registers usage, but for every sample CIC_N clocks required
|
22 |
|
|
/*
|
23 |
|
|
//https://www.so-logic.net/documents/trainings/03_so_implementation_of_filters.pdf
|
24 |
|
|
localparam CIC_R = 16;
|
25 |
|
|
localparam SAMP_INP_DW = 16;
|
26 |
|
|
localparam SAMP_OUT_DW = 16;
|
27 |
|
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 1;
|
28 |
|
|
localparam CIC_N = 3;
|
29 |
|
|
localparam CIC_M = 1;
|
30 |
|
|
localparam SMALL_FOOTPRINT = 1;
|
31 |
|
|
*/
|
32 |
|
|
/*localparam CIC_R = 25;
|
33 |
|
|
localparam SAMP_INP_DW = 16;
|
34 |
|
|
localparam SAMP_OUT_DW = 16;
|
35 |
|
|
localparam CIC_N = 4;
|
36 |
|
|
localparam CIC_M = 1;*/
|
37 |
|
|
/*localparam R = 8;
|
38 |
|
|
localparam SAMP_INP_DW = 12;
|
39 |
|
|
localparam SAMP_OUT_DW = 12;
|
40 |
|
|
localparam M = 3;
|
41 |
|
|
localparam G = 1;*/
|
42 |
|
|
/*localparam CIC_R = 100;
|
43 |
|
|
localparam SAMP_INP_DW = 17;
|
44 |
|
|
localparam SAMP_OUT_DW = 14;
|
45 |
|
|
localparam CIC_N = 7;
|
46 |
|
|
localparam CIC_M = 1;*/
|
47 |
|
|
|
48 |
|
|
/*************************************************************/
|
49 |
|
|
localparam integer CIC_RM = CIC_R * CIC_M;
|
50 |
|
|
localparam real T_clk_ns = 8;//ns
|
51 |
|
|
localparam time half_T = T_clk_ns/2;
|
52 |
|
|
/// parameters of CIC filter with bits prune
|
53 |
|
|
localparam B_max = B_max_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW);
|
54 |
|
|
localparam B_out = B_out_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW, SAMP_OUT_DW);
|
55 |
|
|
localparam B_2Np1 = B_max - SAMP_OUT_DW + 1;
|
56 |
|
|
|
57 |
|
|
localparam delta_f_offs = 200; /// clock number to start delta-function in simulation
|
58 |
|
|
/*************************************************************/
|
59 |
|
|
reg clk; ///< clock
|
60 |
|
|
reg reset_n; ///< reset, active 0
|
61 |
|
|
wire signed [SAMP_INP_DW-1:0] filter_inp_data; ///< input test data of filter
|
62 |
|
|
reg signed [SAMP_INP_DW-1:0] filter_inp_data_d[0:2]; ///< delayed filter_inp_data, for reference model
|
63 |
|
|
wire filter_out_str; ///< filter output sample ready strobe
|
64 |
|
|
reg filter_out_str_d; ///< filter_out_str delayed
|
65 |
|
|
wire signed [SAMP_OUT_DW-1:0] filter_out; ///< filter output data
|
66 |
|
|
reg signed [SAMP_OUT_DW-1:0] filter_out_reg; ///<
|
67 |
|
|
wire signed [SAMP_OUT_DW-1:0] filter_out_ref_wire; ///< reference filter output data
|
68 |
|
|
reg signed [SAMP_OUT_DW-1:0] filter_out_ref; ///<
|
69 |
|
|
reg signed [SAMP_OUT_DW-1:0] filter_out_diff; ///< subtracting tested filter output and reference filter output
|
70 |
|
|
integer clk_counter; ///< counter of clock periods
|
71 |
|
|
integer samp_counter; ///< counter of input samples
|
72 |
|
|
real phase_curr; ///< phase of input signal
|
73 |
|
|
real phase_step; ///< step of input signal phase increment
|
74 |
|
|
integer N_t_samp = 2; ///< period of input samples frequency in clocks
|
75 |
|
|
integer samples_period_ctr; ///< counter for generating input samples period
|
76 |
|
|
integer samples_period_val; ///< period of input samples in clocks
|
77 |
|
|
wire samples_period_rdy; ///< signal is set at the end of input samples period
|
78 |
|
|
real carry_freq; ///< frequency of test sin signal
|
79 |
|
|
longint cic_taps[CIC_R * CIC_M * CIC_N]; ///< storage of internal state of reference CIC filter model
|
80 |
|
|
integer cic_push_ptr; ///< pointer to the FIFO buffer of reference CIC model
|
81 |
|
|
integer cic_model_out_int; ///< output of reference CIC model
|
82 |
|
|
integer cic_B_prune;
|
83 |
|
|
integer cic_B_prune_last_stage;
|
84 |
|
|
longint cic_S_prune;
|
85 |
|
|
longint cic_S_prune_last_stage;
|
86 |
|
|
|
87 |
|
|
/// the reference model of a CIC filter
|
88 |
|
|
task cic_model_reset; ///< set filter to the initial state
|
89 |
|
|
integer i_s;
|
90 |
|
|
integer i_t;
|
91 |
|
|
for(i_s = CIC_N - 1; i_s >= 0; i_s = i_s - 1)
|
92 |
|
|
for(i_t = 0; i_t < CIC_RM; i_t = i_t + 1)
|
93 |
|
|
cic_taps[i_t + i_s * CIC_RM] = 0;
|
94 |
|
|
cic_push_ptr = 0;
|
95 |
|
|
endtask
|
96 |
|
|
|
97 |
|
|
task cic_model_push(longint inp_samp); ///< add input sample
|
98 |
|
|
integer i_s;
|
99 |
|
|
for (i_s = CIC_N - 1; i_s >= 1; i_s = i_s - 1)
|
100 |
|
|
cic_taps[cic_push_ptr + i_s * CIC_RM] = cic_model_stage_get_out(i_s - 1);
|
101 |
|
|
cic_taps[cic_push_ptr] = inp_samp;
|
102 |
|
|
if (cic_push_ptr < CIC_RM - 1) cic_push_ptr = cic_push_ptr + 1;
|
103 |
|
|
else cic_push_ptr = 0;
|
104 |
|
|
endtask
|
105 |
|
|
|
106 |
|
|
function longint cic_model_stage_get_out(integer stage); ///< get output of stage
|
107 |
|
|
integer i_t;
|
108 |
|
|
cic_model_stage_get_out = 0;
|
109 |
|
|
for(i_t = 0; i_t < CIC_RM; i_t = i_t + 1)
|
110 |
|
|
cic_model_stage_get_out = cic_model_stage_get_out + cic_taps[i_t + stage * CIC_RM];
|
111 |
|
|
cic_model_stage_get_out = cic_model_stage_get_out / cic_S_prune;
|
112 |
|
|
if (stage == CIC_N - 1)
|
113 |
|
|
cic_model_stage_get_out = cic_model_stage_get_out / cic_S_prune_last_stage;
|
114 |
|
|
endfunction
|
115 |
|
|
|
116 |
|
|
/*************************************************************/
|
117 |
|
|
initial begin : clk_gen
|
118 |
|
|
clk = 1'b0;
|
119 |
|
|
clk_counter = 0;
|
120 |
|
|
carry_freq = 10000;
|
121 |
|
|
samples_period_val = 6;
|
122 |
|
|
samples_period_ctr = 0;
|
123 |
|
|
phase_curr <= 0;
|
124 |
|
|
phase_step = T_clk_ns * samples_period_val * 2 * carry_freq * `M_PI * 0.000000001;
|
125 |
|
|
cic_model_reset();
|
126 |
|
|
samp_counter <= 0;
|
127 |
|
|
#half_T forever #half_T clk = ~clk;
|
128 |
|
|
end
|
129 |
|
|
/*************************************************************/
|
130 |
|
|
|
131 |
|
|
initial begin
|
132 |
|
|
$dumpfile("../out/cic_d_tb.vcd");
|
133 |
|
|
$dumpvars(4, cic_d_tb);
|
134 |
|
|
end
|
135 |
|
|
|
136 |
|
|
|
137 |
|
|
initial begin : reset_gen
|
138 |
|
|
|
139 |
|
|
reg [127:0] h_f0_pre;
|
140 |
|
|
integer log2_h_f0_pre;
|
141 |
|
|
integer h_f0_pre_limit_prec;
|
142 |
|
|
integer h_f0_pre_divider;
|
143 |
|
|
integer h_f0_divider_exp;
|
144 |
|
|
real h_f0;
|
145 |
|
|
integer B_max;
|
146 |
|
|
integer B_out;
|
147 |
|
|
integer B_2Np1;
|
148 |
|
|
$display("tb CIC INP_DW %d", SAMP_INP_DW);
|
149 |
|
|
$display("tb CIC OUT_DW %d", SAMP_OUT_DW);
|
150 |
|
|
$display("tb CIC R %d", CIC_R);
|
151 |
|
|
$display("tb CIC N %d", CIC_N);
|
152 |
|
|
$display("tb CIC M %d", CIC_M);
|
153 |
|
|
B_max = B_max_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW);
|
154 |
|
|
B_out = B_out_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW, SAMP_OUT_DW);
|
155 |
|
|
B_2Np1 = B_max - B_out + 1;
|
156 |
|
|
$display("B_max= %2d, B_out = %2d, B_2N+1 = %2d", B_max, B_out, B_2Np1);
|
157 |
|
|
h_f0_pre = (CIC_R*CIC_M)**CIC_N;
|
158 |
|
|
h_f0_divider_exp = (B_2Np1 + 1);
|
159 |
|
|
h_f0_pre_limit_prec = 30;
|
160 |
|
|
log2_h_f0_pre = clog2_l(h_f0_pre);
|
161 |
|
|
if (log2_h_f0_pre > h_f0_pre_limit_prec) begin
|
162 |
|
|
$display(" log2_h_f0_pre = %2d, lim %2d", log2_h_f0_pre, h_f0_pre_limit_prec);
|
163 |
|
|
h_f0_pre_divider = log2_h_f0_pre - h_f0_pre_limit_prec;
|
164 |
|
|
$display(" h_f0_pre_divider = %2d", h_f0_pre_divider);
|
165 |
|
|
h_f0_pre = h_f0_pre >> h_f0_pre_divider;
|
166 |
|
|
h_f0_divider_exp = h_f0_divider_exp - h_f0_pre_divider;
|
167 |
|
|
$display(" log2_h_f0_pre limited = %2d, divider_exp limited %2d", log2_h_f0_pre, h_f0_divider_exp);
|
168 |
|
|
h_f0 = 1.0 * h_f0_pre / 2**(h_f0_divider_exp);
|
169 |
|
|
end
|
170 |
|
|
else begin
|
171 |
|
|
h_f0 = h_f0 / 2**(B_2Np1 + 1);
|
172 |
|
|
end
|
173 |
|
|
$display("tb CIC h fwd %2.8f", h_f0);
|
174 |
|
|
// to avoid overflow in reference model, use cic_B_prune to
|
175 |
|
|
//cic_B_prune = B_2Np1 / CIC_N;
|
176 |
|
|
cic_B_prune = 0;
|
177 |
|
|
cic_S_prune = 1 << cic_B_prune;
|
178 |
|
|
cic_B_prune_last_stage = B_2Np1 + 1 - cic_B_prune * CIC_N;
|
179 |
|
|
cic_S_prune_last_stage = 1 << cic_B_prune_last_stage;
|
180 |
|
|
$display("cic_B_prune = %2d, cic_B_prune_last = %2d, ", cic_B_prune, cic_B_prune_last_stage);
|
181 |
|
|
$display($time, " << Starting the Simulation >>");
|
182 |
|
|
reset_n = 1'b0;
|
183 |
|
|
repeat (2) @(negedge clk);
|
184 |
|
|
$display($time, " << Coming out of reset >>");
|
185 |
|
|
reset_n = 1'b1;
|
186 |
|
|
repeat (40000) @(posedge clk);
|
187 |
|
|
@(posedge clk);
|
188 |
|
|
$display($time, " << Simulation done >>");
|
189 |
|
|
$finish;
|
190 |
|
|
|
191 |
|
|
end
|
192 |
|
|
|
193 |
|
|
always @(posedge clk) if (~clk) clk_counter <= clk_counter + 1;
|
194 |
|
|
/*************************************************************/
|
195 |
|
|
assign samples_period_rdy = samples_period_ctr >= (samples_period_val - 1);
|
196 |
|
|
always @(posedge clk)
|
197 |
|
|
if (samples_period_rdy) samples_period_ctr <= 0;
|
198 |
|
|
else samples_period_ctr <= samples_period_ctr + 1;
|
199 |
|
|
|
200 |
|
|
always @(posedge clk)
|
201 |
|
|
begin
|
202 |
|
|
if (samples_period_rdy == 1'b1) begin
|
203 |
|
|
for (int i1 = 2; i1 >= 1; i1 = i1 - 1) filter_inp_data_d[i1] <= filter_inp_data_d[i1 - 1];
|
204 |
|
|
filter_inp_data_d[0] <= filter_inp_data;
|
205 |
|
|
cic_model_push(filter_inp_data_d[1]);
|
206 |
|
|
samp_counter <= samp_counter + 1;
|
207 |
|
|
phase_curr <= phase_curr + phase_step;
|
208 |
|
|
end
|
209 |
|
|
end
|
210 |
|
|
/*************************************************************/
|
211 |
|
|
assign filter_inp_data = $rtoi((2**(SAMP_INP_DW - INP_SAMP_WIDTH_TO_SIGNAL_WIDTH - 1) - 1)*($sin(phase_curr)));
|
212 |
|
|
//assign filter_inp_data = samp_counter == delta_f_offs ? 10000 : 0; ///< delta function
|
213 |
|
|
//assign filter_inp_data = samp_counter >= delta_f_offs && samp_counter < delta_f_offs + CIC_N ? 10000 : 0;
|
214 |
|
|
//assign filter_inp_data = samp_counter >= delta_f_offs ? 10000 : 0; ///< Hamming function
|
215 |
|
|
/*************************************************************/
|
216 |
|
|
cic_d #(
|
217 |
|
|
.INP_DW (SAMP_INP_DW),
|
218 |
|
|
.OUT_DW (SAMP_OUT_DW),
|
219 |
|
|
.CIC_R (CIC_R),
|
220 |
|
|
.CIC_N (CIC_N),
|
221 |
|
|
.CIC_M (CIC_M),
|
222 |
|
|
.SMALL_FOOTPRINT (SMALL_FOOTPRINT)
|
223 |
|
|
)
|
224 |
|
|
dut1
|
225 |
|
|
(
|
226 |
|
|
.clk (clk),
|
227 |
|
|
.reset_n (reset_n),
|
228 |
|
|
.clear (1'b0),
|
229 |
|
|
.inp_samp_data (filter_inp_data),
|
230 |
|
|
.inp_samp_str (samples_period_rdy),
|
231 |
|
|
.out_samp_data (filter_out),
|
232 |
|
|
.out_samp_str (filter_out_str)
|
233 |
|
|
);
|
234 |
|
|
always @(posedge clk)
|
235 |
|
|
filter_out_str_d <= filter_out_str;
|
236 |
|
|
always @(posedge clk)
|
237 |
|
|
begin
|
238 |
|
|
if (filter_out_str == 1'b1) begin
|
239 |
|
|
filter_out_reg <= filter_out;
|
240 |
|
|
filter_out_ref <= cic_model_stage_get_out(CIC_N - 1);
|
241 |
|
|
end
|
242 |
|
|
end
|
243 |
|
|
always @(posedge clk)
|
244 |
|
|
begin
|
245 |
|
|
if (filter_out_str_d == 1'b1) begin
|
246 |
|
|
filter_out_diff <= filter_out - filter_out_ref;
|
247 |
|
|
end
|
248 |
|
|
end
|
249 |
|
|
|
250 |
|
|
/*************************************************************/
|
251 |
|
|
endmodule
|
252 |
|
|
|