`timescale 1ns / 1ps

module DecimFilterWrapperTb	();

//================================================================================
//	PARAMETERS
//================================================================================

parameter	N	=   4; // Order of the filter
parameter	M	=	1;// Delay in CIC filter
// parameter   M2nd = (M/2)*M; // Delay in 2nd CIC filter
parameter   R = 4; // Decimation factor
parameter  	M2nd = M*R; // Delay in 2nd CIC filter
parameter   M3rd = M*R;
// parameter   M3rd = (M/2)**2*M; // Delay in 3rd CIC filter
parameter	InDataWidth	=	14;
parameter	integer DECIM_WIDTH	=	$ceil($clog2(2*M)) + 4; // Decimation factor width

parameter	K = N*20*($log10(M));
parameter	BitGworth = $ceil(2**(K/20));

// parameter	integer BitGrowth = $ceil(N*$clog2((M/2)*M));
parameter   integer BitGrowth =   $ceil(N*$clog2(M*R));
// parameter 	integer BitGrowth2nd = $ceil(N*$clog2(M2nd*(M/2)));
// parameter 	integer BitGrowth3rd = $ceil(N*$clog2(M3rd*(M/2)));

parameter  integer BitGrowth2nd = $ceil(N*$clog2(M*R));
parameter  integer BitGrowth3rd = $ceil(N*$clog2(M*R));

parameter	integer MaxWidth = InDataWidth+BitGrowth;
parameter	integer MaxWidth2nd = InDataWidth+BitGrowth2nd;
parameter	integer MaxWidth3rd = InDataWidth+BitGrowth3rd;

// parameter	[31:0]	Nco1PhaseInc	=	32'h40000000;//12.5 MHz 
parameter	[31:0]	Nco1PhaseInc	=	32'h23d70a3d;//7 MHz 
parameter	[31:0]	Nco2PhaseInc	=	32'h0f5c28f6;// 3 MHz



//================================================================================
//	REG/WIRE
//================================================================================


reg		Clk50;
reg		Rst;

reg		[DECIM_WIDTH-1:0]	decimFactor;

reg		[31:0]	tbCnt;

wire	oscWind	=	(tbCnt>=100&tbCnt<=(1123 + 1024*1))?1'b1:1'b0;

wire	resultVal;
wire	impResponseVal;
wire	respVal;

wire	signed	[InDataWidth-1:0]	ncoSin1;
wire	signed	[InDataWidth-1:0]	ncoSin2;
wire	signed	[InDataWidth-1:0]	ncoSin3;

wire	signed	[MaxWidth-1:0]		filteredDataOut;
logic 	signed	[31:0]				firDataOut;
logic 	signed 	[15:0]				firDataOut16;
wire	signed	[MaxWidth-1:0]		impResponse;
wire 	signed	[31:0]				impResp32;
assign 	impResp32 = impResponse[MaxWidth-1:MaxWidth-32];

wire	signed	[InDataWidth*2-1:0]	adcDataMixed	=	(ncoSin1*ncoSin2);
wire	signed	[InDataWidth-1:0]	adcDataMixedCut	=	adcDataMixed[26-:14];

// wire	signed	[InDataWidth-1:0]	sinAdd	=	(ncoSin1>>>1)+(ncoSin2>>>1);
wire    signed  [2*InDataWidth-1:0] sinMultFull = (ncoSin2*ncoSin1);
wire	signed	[InDataWidth-1:0]	sinMult =	sinMultFull[(2*InDataWidth-1)-:InDataWidth];

wire	signed	[InDataWidth-1:0]	singlePulse	=	(tbCnt==100)?	14'h1fff:14'h0;
wire    signed  [15:0] 				singlePulse16 = (tbCnt==100) ? 16'h1fff : 16'h0;

// wire signed [(MaxWidth < 32 ? MaxWidth : InDataWidth+18)-1:0] impRespCut;
// assign impRespCut = MaxWidth < 32 ? impResponse : 
//                                    impResponse[MaxWidth-1:MaxWidth-(InDataWidth+18)];
wire signed [InDataWidth -1 : 0] impRespCut = impResponse [MaxWidth-1:MaxWidth-InDataWidth];

longint inSignal,filteredData, impResp,impResp2,impResp3, afterFir;

/* 2nd CIC */
wire signed [MaxWidth-1:0] impResponse2nd;

// wire signed [(MaxWidth < 32 ? MaxWidth : InDataWidth+18)-1:0] impResp2ndCut;
// assign impResp2ndCut = MaxWidth < 32 ? impResponse2nd : 
//                                    impResponse2nd[MaxWidth-1:MaxWidth-(InDataWidth+18)];
wire signed [31:0] impResp2ndCut32 = (MaxWidth < 32) ? impResponse2nd : 
									impResponse2nd[MaxWidth-1:MaxWidth-32];
// wire signed [InDataWidth -1 : 0] impResp2ndCut = impResponse2nd [MaxWidth-1:MaxWidth-InDataWidth];
wire signed [InDataWidth -1 : 0] impResp2ndCut = impResponse2nd [MaxWidth-1:MaxWidth-InDataWidth];
wire impResp2ndVal;

/* 3rd CIC */
wire signed [MaxWidth3rd-1:0] impResponse3rd;

wire signed [31:0] impResp3rd32;
assign impResp3rd32 = (MaxWidth3rd < 32) ? impResponse3rd : 
									impResponse3rd[MaxWidth3rd-1:MaxWidth3rd-32];
wire impResp3rdVal;

/* FIR Filt */
wire signed [35:0] firFiltTestData;
wire 					firFiltVal;  

//================================================================================
//	CLK GEN
//================================================================================

always	#10 Clk50	=	~Clk50;

//================================================================================
//	CODING
//================================================================================
	
initial begin
	Clk50		=	1'b1;
	Rst			=	1'b1;
#200;
	Rst			=	1'b0;
end	

always	@(posedge	Clk50)	begin
	if	(!Rst)	begin
		tbCnt	<=	tbCnt+32'd1;
	end	else	begin
		tbCnt	<=	32'd0;
	end
end
	
always	@(posedge	Clk50)	begin
	if	(!Rst)	begin
		if (tbCnt == 100) begin
			decimFactor	<= R;
		end
		// end else if (tbCnt == 5400) begin
			// decimFactor	<= 1;
		// end else if (tbCnt == 6400) begin
			// decimFactor	<= 2;
		// end else if (tbCnt == 7400) begin
			// decimFactor	<= 3;
		// end else if (tbCnt == 8400) begin
			// decimFactor	<= 4;
		// end else if (tbCnt == 9400) begin
			// decimFactor	<= 5;
		// end else if (tbCnt == 10400) begin
			// decimFactor	<= 6;
		// end else if (tbCnt == 11400) begin
			// decimFactor	<= 7;
		// end
	end else begin
	 decimFactor <= R; // 
	end 
end

CordicNco		
#(	
	.ODatWidth	(14),
	.PhIncWidth	(32),
	.IterNum	(10),
	.EnSinN		(1)
)
ncoInst1
(
	.Clk_i		(Clk50),
	.Rst_i		(Rst),
	.Val_i		(1'b1),
	.PhaseInc_i	(Nco1PhaseInc),
	.WindVal_i	(1'b1),
	.WinType_i	(),
	.Wind_o		(),
	.Sin_o		(ncoSin1),
	.Cos_o		(),
	.Val_o		()
);

CordicNco		
#(	
	.ODatWidth	(14),
	.PhIncWidth	(32),
	.IterNum	(10),
	.EnSinN		(1)
)
ncoInst2
(
	.Clk_i		(Clk50),
	.Rst_i		(Rst),
	.Val_i		(1'b1),
	.PhaseInc_i	(Nco2PhaseInc),
	.WindVal_i	(1'b1),
	.WinType_i	(),
	.Wind_o		(),
	.Sin_o		(ncoSin2),
	.Cos_o		(),
	.Val_o		()
);

CicFilterNewWrapperNoIntDiff	
#(	
	.InDataWidth	(InDataWidth),
	.N	(N),
	.M	(M),
	.DECIM_WIDTH	(DECIM_WIDTH),
	.OutDataWidth	(MaxWidth+20)
)
DecimFilter
(
	.Clk_i			(Clk50),
	.DecimFactor_i	(decimFactor),
	.Rst_i			(Rst),
	.DataVal_i		(oscWind),

	.Data_i		(sinMult),
	
	.Data_o	(filteredDataOut),
	.DataVal_o	(resultVal)
);

CicFilterNewWrapperNoIntDiff	
#(	
	.InDataWidth	(InDataWidth),
	.N	(N),
	.M	(M),
	.DECIM_WIDTH	(DECIM_WIDTH)
	// .OutDataWidth	(MaxWidth)
)
ImpulseResponseFilter
(
	.Clk_i			(Clk50),
	.DecimFactor_i	(decimFactor),
	.Rst_i			(Rst),
	.DataVal_i		(oscWind),

	.Data_i			(singlePulse),
	
	.Data_o			(impResponse),
	.DataVal_o		(impResponseVal)
);

// CicFilterNewWrapperNoIntDiff	
// #(
// 	.InDataWidth	(InDataWidth),
// 	.N	(N),
// 	.M	((M/2)*M),
// 	.DECIM_WIDTH	(DECIM_WIDTH),
// 	.OutDataWidth	(MaxWidth)
// )
// ImpulseResponseFilter2ndStage
// (
// 	.Clk_i			(Clk50),
// 	.DecimFactor_i	(decimFactor),
// 	.Rst_i			(Rst),
// 	.DataVal_i		(impResponseVal),

// 	.Data_i			(impRespCut),
	
// 	.Data_o			(impResponse2nd),
// 	.DataVal_o		(impResp2ndVal)
// );

// CicFilterNewWrapperNoIntDiff	
// #(
// 	.InDataWidth	(InDataWidth),
// 	.N	(N),
// 	.M	((M/2)**2*M),
// 	.DECIM_WIDTH	(DECIM_WIDTH),
// 	.OutDataWidth	(MaxWidth3rd)
// )
// ImpulseResponseFilter3rdStage
// (
// 	.Clk_i			(Clk50),
// 	.DecimFactor_i	(decimFactor),
// 	.Rst_i			(Rst),
// 	.DataVal_i		(impResp2ndVal),

// 	.Data_i			(impResp2ndCut),

// 	.Data_o			(impResponse3rd),
// 	.DataVal_o		(impResp3rdVal)
// );

FirFilter #(
	.DATA_WIDTH 	(16),
	.COEFF_WIDTH 	(16),
	.NUM_TAPS		(32)
)
FirFiltTest
(
	.Clk_i			(Clk50),
	.Rst_i			(Rst),
	.DecimFactor_i	(decimFactor),
	.Data_i			(impResponse), // 16 bits for FIR filter
	.Val_i			(impResponseVal),

	.Data_o			(firFiltTestData),
	.Val_o			(firFiltVal)
);

CicFilterNewWrapperNoIntDiff
#(
	.InDataWidth	(InDataWidth),
	.N	(N),
	.M	(M),
	.OutDataWidth	(MaxWidth)
)
CicFilterInst
(
	.Clk_i				(Clk50),
	.DecimFactor_i		(decimFactor),
	.Rst_i				(Rst),
	.DataVal_i			(oscWind),
	.Data_i				(sinMult),
	.Data_o				(),
	.DataVal_o			()
);

always_ff @(posedge Clk50) begin
	if (Rst) begin 
		firDataOut <= '0;
	end
	else begin 
		if (firFiltVal) begin
			firDataOut <= firFiltTestData[35:35-32];
		end
	end
end

	
always	@(posedge	Clk50)	begin
	if	(tbCnt==32'd1)	begin
		inSignal = $fopen("C:/S5243_FFT_REPO/src/src/Sim/InputSignal.txt","w");
	end	else	begin
		if	(oscWind)	begin
			// $display("AdcData is %d", sinAdd);
			// $fwrite(inSignal,"%d\n",   sinAddExt18);
			// $fwrite(inSignal,"%d\n",   adcDataMixedCut);
			$fwrite(inSignal,"%d\n",   sinMult);
		end	
	end	
end

always	@(posedge	Clk50)	begin
	if	(tbCnt==32'd1)	begin
		filteredData = $fopen("C:/S5243_FFT_REPO/src/src/Sim/FilteredData.txt","w");
	end	else	begin
		if	(resultVal)	begin
			$fwrite(filteredData,"%d\n",   filteredDataOut[15:0]);
			// $fwrite(filteredData,"%d\n",   firDataOut);
		end	
	end	
end

always @(posedge Clk50) begin
	if (tbCnt == 32'd1) begin
		impResp = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp1.txt","w");
	end
	else begin 
		if (impResponseVal) begin
			// $fwrite(impResp,"%d\n",   impResponse);
			$fwrite(impResp,"%d\n",   impResponse[15:0]);
		end
	end
end

always @(posedge Clk50) begin
	if (tbCnt == 32'd1) begin
		impResp2 = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp2.txt","w");
	end else begin
		if (impResp2ndVal) begin
			// $fwrite(impResp,"%d\n",   firRespout);
			$fwrite(impResp2,"%d\n",   impResp2ndCut32);
		end	
	end
end

always @(posedge Clk50) begin
	if (tbCnt == 32'd1) begin
		impResp3 = $fopen("C:/S5243_FFT_REPO/src/src/Sim/ImpResp3.txt","w");
	end else begin
		if (impResp3rdVal) begin
			// $fwrite(impResp,"%d\n",   firRespout);
			$fwrite(impResp3,"%d\n",   impResponse3rd);
		end	
	end
end



always @(posedge Clk50) begin 
	if (tbCnt == 32'd1) begin
		afterFir  <= $fopen("C:/S5243_FFT_REPO/src/src/Sim/AfterFir.txt","w");
	end
	else begin 
		if (firFiltVal) begin
			$fwrite(afterFir,"%d\n",   firFiltTestData);
		end
	end
end


always @(posedge Clk50) begin
	if (tbCnt == 32'd1500 + (1024*1)) begin
		$fclose(inSignal);
		$fclose(filteredData);
		$fclose(impResp);
		$fclose(impResp2);
		$fclose(impResp3);
		$fclose(afterFir);
		$finish;
	end
end

endmodule



















