Line 1... |
Line 1... |
`timescale 1ns / 1ns
|
`timescale 1ns / 1ns
|
module cic_d_tb
|
module cic_d_tb
|
(
|
(
|
);
|
);
|
`include "../../../rtl/verilog/cic_functions.vh"
|
`include "../../rtl/verilog/cic_functions.vh"
|
`define M_PI 3.14159265359 // not all simulators defines PI
|
`define M_PI 3.14159265359 // not all simulators defines PI
|
/*
|
|
// U. Meyer-Baese, Digital Signal Processing with Field Programmable Gate Arrays, 2nd Edition, Spinger, 2004.
|
// U. Meyer-Baese, Digital Signal Processing with Field Programmable Gate Arrays, 2nd Edition, Spinger, 2004.
|
// Example 5.5: Three-Stages CIC Decimator II
|
// Example 5.5: Three-Stages CIC Decimator II
|
|
/*
|
localparam CIC_R = 32;
|
localparam CIC_R = 32;
|
localparam SAMP_INP_DW = 8;
|
localparam SAMP_INP_DW = 8;
|
localparam SAMP_OUT_DW = 10;
|
localparam SAMP_OUT_DW = 10;
|
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 2;
|
localparam CIC_N = 3;
|
localparam CIC_N = 3;
|
localparam CIC_M = 2;*/
|
localparam CIC_M = 2;
|
localparam CIC_R = 100;
|
localparam SMALL_FOOTPRINT = 1;
|
|
*/
|
|
/*localparam CIC_R = 100;
|
localparam SAMP_INP_DW = 18;
|
localparam SAMP_INP_DW = 18;
|
localparam SAMP_OUT_DW = 18;
|
localparam SAMP_OUT_DW = 18;
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 2;
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 2;
|
localparam CIC_N = 7;
|
localparam CIC_N = 7;
|
localparam CIC_M = 1;
|
localparam CIC_M = 1;
|
localparam SMALL_FOOTPRINT = 1; ///< set to 1 for less registers usage, but for every sample CIC_N clocks required
|
localparam SMALL_FOOTPRINT = 1; ///< set to 1 for less registers usage, but for every sample CIC_N clocks required
|
|
*/
|
/*
|
/*
|
//https://www.so-logic.net/documents/trainings/03_so_implementation_of_filters.pdf
|
//https://www.so-logic.net/documents/trainings/03_so_implementation_of_filters.pdf
|
localparam CIC_R = 16;
|
localparam CIC_R = 16;
|
localparam SAMP_INP_DW = 16;
|
localparam SAMP_INP_DW = 16;
|
localparam SAMP_OUT_DW = 16;
|
localparam SAMP_OUT_DW = 16;
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 1;
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 1;
|
localparam CIC_N = 3;
|
localparam CIC_N = 3;
|
localparam CIC_M = 1;
|
localparam CIC_M = 1;
|
localparam SMALL_FOOTPRINT = 1;
|
localparam SMALL_FOOTPRINT = 1;
|
*/
|
*/
|
/*localparam CIC_R = 25;
|
/*
|
|
// Eugene B. Hogenauer paper
|
|
// B: 1, 6, 9, 13, 14, 15, 16, 17
|
|
localparam CIC_R = 25;
|
localparam SAMP_INP_DW = 16;
|
localparam SAMP_INP_DW = 16;
|
localparam SAMP_OUT_DW = 16;
|
localparam SAMP_OUT_DW = 16;
|
localparam CIC_N = 4;
|
localparam CIC_N = 4;
|
localparam CIC_M = 1;*/
|
localparam CIC_M = 1;
|
|
localparam SMALL_FOOTPRINT = 1;
|
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 0;
|
|
*/
|
/*localparam R = 8;
|
/*localparam R = 8;
|
localparam SAMP_INP_DW = 12;
|
localparam SAMP_INP_DW = 12;
|
localparam SAMP_OUT_DW = 12;
|
localparam SAMP_OUT_DW = 12;
|
localparam M = 3;
|
localparam M = 3;
|
localparam G = 1;*/
|
localparam G = 1;*/
|
/*localparam CIC_R = 100;
|
|
|
localparam CIC_R = 100;
|
localparam SAMP_INP_DW = 17;
|
localparam SAMP_INP_DW = 17;
|
localparam SAMP_OUT_DW = 14;
|
localparam SAMP_OUT_DW = 14;
|
localparam CIC_N = 7;
|
localparam CIC_N = 7;
|
localparam CIC_M = 1;*/
|
localparam CIC_M = 1;
|
|
localparam SMALL_FOOTPRINT = 1;
|
|
localparam INP_SAMP_WIDTH_TO_SIGNAL_WIDTH = 0;
|
|
|
/*************************************************************/
|
/*************************************************************/
|
localparam integer CIC_RM = CIC_R * CIC_M;
|
localparam integer CIC_RM = CIC_R * CIC_M;
|
localparam real T_clk_ns = 8;//ns
|
localparam real T_clk_ns = 8;//ns
|
localparam time half_T = T_clk_ns/2;
|
localparam time half_T = T_clk_ns/2;
|
Line 77... |
Line 91... |
wire samples_period_rdy; ///< signal is set at the end of input samples period
|
wire samples_period_rdy; ///< signal is set at the end of input samples period
|
real carry_freq; ///< frequency of test sin signal
|
real carry_freq; ///< frequency of test sin signal
|
longint cic_taps[CIC_R * CIC_M * CIC_N]; ///< storage of internal state of reference CIC filter model
|
longint cic_taps[CIC_R * CIC_M * CIC_N]; ///< storage of internal state of reference CIC filter model
|
integer cic_push_ptr; ///< pointer to the FIFO buffer of reference CIC model
|
integer cic_push_ptr; ///< pointer to the FIFO buffer of reference CIC model
|
integer cic_model_out_int; ///< output of reference CIC model
|
integer cic_model_out_int; ///< output of reference CIC model
|
|
integer cic_B_scale_out;
|
integer cic_B_prune;
|
integer cic_B_prune;
|
integer cic_B_prune_last_stage;
|
integer cic_B_prune_last_stage;
|
longint cic_S_prune;
|
longint cic_S_prune;
|
longint cic_S_prune_last_stage;
|
longint cic_S_prune_last_stage;
|
|
|
Line 150... |
Line 165... |
$display("tb CIC R %d", CIC_R);
|
$display("tb CIC R %d", CIC_R);
|
$display("tb CIC N %d", CIC_N);
|
$display("tb CIC N %d", CIC_N);
|
$display("tb CIC M %d", CIC_M);
|
$display("tb CIC M %d", CIC_M);
|
B_max = B_max_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW);
|
B_max = B_max_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW);
|
B_out = B_out_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW, SAMP_OUT_DW);
|
B_out = B_out_calc(CIC_N, CIC_R, CIC_M, SAMP_INP_DW, SAMP_OUT_DW);
|
B_2Np1 = B_max - B_out + 1;
|
//B_2Np1 = B_max - B_out + 1;
|
|
B_2Np1 = B_calc(CIC_N * 2, CIC_N, CIC_R, CIC_M, SAMP_INP_DW, SAMP_OUT_DW);
|
$display("B_max= %2d, B_out = %2d, B_2N+1 = %2d", B_max, B_out, B_2Np1);
|
$display("B_max= %2d, B_out = %2d, B_2N+1 = %2d", B_max, B_out, B_2Np1);
|
h_f0_pre = (CIC_R*CIC_M)**CIC_N;
|
h_f0_pre = (CIC_R*CIC_M)**CIC_N;
|
h_f0_divider_exp = (B_2Np1 + 1);
|
h_f0_divider_exp = (B_2Np1 + 1);
|
h_f0_pre_limit_prec = 30;
|
h_f0_pre_limit_prec = 30;
|
log2_h_f0_pre = clog2_l(h_f0_pre);
|
log2_h_f0_pre = clog2_l(h_f0_pre);
|
if (log2_h_f0_pre > h_f0_pre_limit_prec) begin
|
|
$display(" log2_h_f0_pre = %2d, lim %2d", log2_h_f0_pre, h_f0_pre_limit_prec);
|
$display(" log2_h_f0_pre = %2d, lim %2d", log2_h_f0_pre, h_f0_pre_limit_prec);
|
|
if (log2_h_f0_pre > h_f0_pre_limit_prec) begin
|
h_f0_pre_divider = log2_h_f0_pre - h_f0_pre_limit_prec;
|
h_f0_pre_divider = log2_h_f0_pre - h_f0_pre_limit_prec;
|
$display(" h_f0_pre_divider = %2d", h_f0_pre_divider);
|
$display(" h_f0_pre_divider = %2d", h_f0_pre_divider);
|
h_f0_pre = h_f0_pre >> h_f0_pre_divider;
|
h_f0_pre = h_f0_pre >> h_f0_pre_divider;
|
h_f0_divider_exp = h_f0_divider_exp - h_f0_pre_divider;
|
h_f0_divider_exp = h_f0_divider_exp - h_f0_pre_divider;
|
$display(" log2_h_f0_pre limited = %2d, divider_exp limited %2d", log2_h_f0_pre, h_f0_divider_exp);
|
$display(" log2_h_f0_pre limited = %2d, divider_exp limited %2d", log2_h_f0_pre, h_f0_divider_exp);
|
h_f0 = 1.0 * h_f0_pre / 2**(h_f0_divider_exp);
|
h_f0 = 1.0 * h_f0_pre / 2**(h_f0_divider_exp);
|
end
|
end
|
else begin
|
else begin
|
h_f0 = h_f0 / 2**(B_2Np1 + 1);
|
h_f0 = h_f0_pre / 2**(B_2Np1 + 1);
|
end
|
end
|
$display("tb CIC h fwd %2.8f", h_f0);
|
$display("tb CIC h fwd %2.8f", h_f0);
|
// to avoid overflow in reference model, use cic_B_prune to
|
// to avoid overflow in reference model, use cic_B_prune to
|
//cic_B_prune = B_2Np1 / CIC_N;
|
//cic_B_prune = B_2Np1 / CIC_N;
|
|
cic_B_scale_out = B_max + 1 - SAMP_OUT_DW;
|
cic_B_prune = 0;
|
cic_B_prune = 0;
|
cic_S_prune = 1 << cic_B_prune;
|
cic_S_prune = 1 << cic_B_prune;
|
cic_B_prune_last_stage = B_2Np1 + 1 - cic_B_prune * CIC_N;
|
//cic_B_prune_last_stage = B_2Np1 + 1 - cic_B_prune * CIC_N;
|
|
cic_B_prune_last_stage = cic_B_scale_out - cic_B_prune * CIC_N;
|
cic_S_prune_last_stage = 1 << cic_B_prune_last_stage;
|
cic_S_prune_last_stage = 1 << cic_B_prune_last_stage;
|
|
$display("model:");
|
|
$display(" B_max=%2d; B_out=%2d; cic_B_scale_out=%2d", B_max, B_out, cic_B_scale_out);
|
$display("cic_B_prune = %2d, cic_B_prune_last = %2d, ", cic_B_prune, cic_B_prune_last_stage);
|
$display("cic_B_prune = %2d, cic_B_prune_last = %2d, ", cic_B_prune, cic_B_prune_last_stage);
|
$display($time, " << Starting the Simulation >>");
|
$display($time, " << Starting the Simulation >>");
|
reset_n = 1'b0;
|
reset_n = 1'b0;
|
repeat (2) @(negedge clk);
|
repeat (2) @(negedge clk);
|
|
//$finish;
|
$display($time, " << Coming out of reset >>");
|
$display($time, " << Coming out of reset >>");
|
reset_n = 1'b1;
|
reset_n = 1'b1;
|
repeat (40000) @(posedge clk);
|
repeat (40000) @(posedge clk);
|
@(posedge clk);
|
@(posedge clk);
|
$display($time, " << Simulation done >>");
|
$display($time, " << Simulation done >>");
|
Line 209... |
Line 230... |
end
|
end
|
/*************************************************************/
|
/*************************************************************/
|
assign filter_inp_data = $rtoi((2**(SAMP_INP_DW - INP_SAMP_WIDTH_TO_SIGNAL_WIDTH - 1) - 1)*($sin(phase_curr)));
|
assign filter_inp_data = $rtoi((2**(SAMP_INP_DW - INP_SAMP_WIDTH_TO_SIGNAL_WIDTH - 1) - 1)*($sin(phase_curr)));
|
//assign filter_inp_data = samp_counter == delta_f_offs ? 10000 : 0; ///< delta function
|
//assign filter_inp_data = samp_counter == delta_f_offs ? 10000 : 0; ///< delta function
|
//assign filter_inp_data = samp_counter >= delta_f_offs && samp_counter < delta_f_offs + CIC_N ? 10000 : 0;
|
//assign filter_inp_data = samp_counter >= delta_f_offs && samp_counter < delta_f_offs + CIC_N ? 10000 : 0;
|
//assign filter_inp_data = samp_counter >= delta_f_offs ? 10000 : 0; ///< Hamming function
|
//assign filter_inp_data = samp_counter >= delta_f_offs ? 1 << (SAMP_INP_DW / 2) : 0; ///< Hamming function
|
|
//assign filter_inp_data = samp_counter >= delta_f_offs ? 1 << (SAMP_INP_DW - INP_SAMP_WIDTH_TO_SIGNAL_WIDTH -1 ) : 0; ///< Hamming function
|
/*************************************************************/
|
/*************************************************************/
|
|
|
cic_d #(
|
cic_d #(
|
.INP_DW (SAMP_INP_DW),
|
.INP_DW (SAMP_INP_DW),
|
.OUT_DW (SAMP_OUT_DW),
|
.OUT_DW (SAMP_OUT_DW),
|
.CIC_R (CIC_R),
|
.CIC_R (CIC_R),
|
.CIC_N (CIC_N),
|
.CIC_N (CIC_N),
|