
//////////////////////////////////////////////////////////////////////////////////
// Company: NPK TAIR
// Engineer: Mikhail Zaytsev
// 
// Create Date: 21.02.2023
// Design Name: 
// Module Name: ComplPrng
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: Pseudorandom number generator (PRNG) based on 
//				Linear Feedback Shift Register (LFSR). Taus88
//
// Dependencies: None
// 
//////////////////////////////////////////////////////////////////////////////////
module ComplPrng
#(
	parameter DataPrngWidth = 4,
	parameter InDataWidth = 14,
	parameter OutDataWidth = 20
)
(
	// input [InDataWidth-1:0] Data_i,
	input Clk_i,
	input Rst_i,

	// output signed	[OutDataWidth-1:0] DataAndPrng_o
	output signed	[OutDataWidth-1:0] PrngData_o
);
//================================================================================
//	REG/WIRE
//================================================================================
reg [31:0] s1;
reg [31:0] s2;
reg [31:0] s3;
reg signed	[31:0] dataPrng;

wire	signed	[OutDataWidth-1:0]	adcDataExtended;

wire	signed	[DataPrngWidth-1:0]	dataPrngCut;
// wire	signed	[OutDataWidth-1:0]	dataPrngCutExtended;
reg		signed	[OutDataWidth-1:0]	dataPrngCutExtended;

reg	signed	[OutDataWidth-1:0]	dataAndPrngReg;
//================================================================================
//	ASSIGNMENTS
//================================================================================
// assign	adcDataExtended		=	{Data_i[InDataWidth-1], Data_i[InDataWidth-1], Data_i, 4'b0};
assign	dataPrngCut			=	dataPrng[31-:DataPrngWidth];
// assign	dataPrngCutExtended	=	{{OutDataWidth-DataPrngWidth{dataPrngCut[DataPrngWidth-1]}}, dataPrngCut};
// assign	DataAndPrng_o		=	adcDataExtended+dataPrngCutExtended;
// assign	DataAndPrng_o		=	dataAndPrngReg;
assign	PrngData_o			=	dataPrngCutExtended;
//================================================================================
//	CODING
//================================================================================
always @(posedge Clk_i) begin
	if (Rst_i) begin
		s1 <= 32'd12345;
		s2 <= 32'd12345;
		s3 <= 32'd12345;
	end else begin
		s1 <= (((s1 & 32'd4294967294) << 12) ^ (((s1 << 13) ^ s1) >> 19));
		s2 <= (((s2 & 32'd4294967288) << 4) ^ (((s2 << 2) ^ s2) >> 25));
		s3 <= (((s3 & 32'd4294967280) << 17) ^ (((s3 << 3) ^ s3) >> 11));
	end
end

always @(posedge Clk_i) begin
	if (Rst_i) begin
		dataPrng <= 32'b0;
	end else begin
		dataPrng <= s1 ^ s2 ^ s3;
	end
end

always @(posedge Clk_i) begin
	if (Rst_i) begin
		dataPrngCutExtended	<=	0;
	end else begin
		dataPrngCutExtended	<=	{{OutDataWidth-DataPrngWidth{dataPrngCut[DataPrngWidth-1]}}, dataPrngCut};
	end
end

// always @(posedge Clk_i) begin
	// if (Rst_i) begin
		// dataAndPrngReg	<=	0;
	// end else begin
		// dataAndPrngReg	<=	Data_i+dataPrngCutExtended;
	// end
// end

endmodule
