`timescale 1ns / 1ps
(* keep_hierarchy = "yes" *)
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    14:12:30 06/03/2020 
// Design Name: 
// Module Name:    WinParameters 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: kek
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//18.01.2022	AdcData_I is 1.0.13 now changing to 1.2.17 for further calculation. The integer part added to avoid the overflow of the corrected data.
//////////////////////////////////////////////////////////////////////////////////

module AdcCalibration 
#(	
	parameter	AccNum			=	128,
	parameter	AdcDataWidth	=	14
)
(	
	input		Clk_i,
	input		Rst_i,
	input		CalModeEn_i,
	input		[AdcDataWidth-1:0]	AdcData_i,
	
	output		CalDone_o,
	output		[AdcDataWidth-1:0]	CalibratedAdcData_o
);

//================================================================================
//  Func
//================================================================================
	function integer Log2;
	input integer value;
		begin
			Log2 = 0;
			while (value > 1) begin
				value   = value >> 1;
				Log2    = Log2 + 1;
			end
		end
	endfunction
	
	localparam ShiftValue	= Log2(AccNum);
	localparam AccWidth		= AdcDataWidth+ShiftValue;
	
//================================================================================
//  REG/WIRE
//================================================================================
	reg signed	[AccWidth:0]	adcAcc;
	reg signed	[AdcDataWidth-1:0]	calValue;
	reg signed	[AdcDataWidth-1:0]	calValueR;
	reg [ShiftValue-1:0]	accCnt;
	reg calDone;
	
	wire	[AccWidth:0]	adcDataCompl	=	{{ShiftValue+1{AdcData_i[AdcDataWidth-1]}},AdcData_i};
	
	wire	signed	[AdcDataWidth-1:0]	calibratedData	=	AdcData_i-calValue;
	
//================================================================================
//  ASSIGNMENTS
//================================================================================	
	assign	CalDone_o	=	calDone;
	assign	CalibratedAdcData_o	=	calibratedData;
//================================================================================
//  CODING
//================================================================================	

always	@(posedge	Clk_i)	begin
	if	(!Rst_i)	begin
		if	(CalModeEn_i)	begin
			if	(!calDone)	begin
				accCnt	<=	accCnt+1;
			end	else	begin
				accCnt	<=	0;
			end
		end	else	begin
			accCnt	<=	0;
		end
	end	else	begin
		accCnt	<=	0;
	end
end

always	@(posedge	Clk_i)	begin
	if	(!Rst_i)	begin
		if	(accCnt	==	AccNum-1)	begin
			calDone	<=	1'b1;
		end	else	begin
			calDone	<=	1'b0;
		end
	end	else	begin
		calDone	<=	1'b0;
	end
end

always	@(posedge	Clk_i)	begin
	if	(!Rst_i)	begin
		if	(CalModeEn_i)	begin
			if	(!calDone)	begin
				adcAcc	<=	adcAcc+adcDataCompl;
			end	else	begin
				adcAcc	<=	adcDataCompl;
			end
		end	else	begin
			adcAcc	<=	adcDataCompl;
		end
	end	
end

always	@(posedge	Clk_i)	begin
	if	(!Rst_i)	begin
		if	(calDone)	begin
			calValue	<=	adcAcc>>ShiftValue;
		end	
	end	else	begin
		calValue	<=	14'h0;
	end
end

endmodule

