module rnd_vec_gen(

	clk,

	init,

	save,
	restore,
	next,


	out
);

parameter OUT_SIZE = 16; // size of output port, independent of LFSR register size

parameter LFSR_LENGTH   = 55; // LFSR
parameter LFSR_FEEDBACK = 24; //     definition


	input clk;

	input init; // positive initialization strobe, synchronous to clock, its length will determine initial state

	input save,restore,next; // strobes for required events: positive, one clock cycle long


	reg init2;


	output  [OUT_SIZE-1:0] out;
	wire    [OUT_SIZE-1:0] out;


	reg [OUT_SIZE-1:0] rndbase_main  [0:LFSR_LENGTH-1];
	reg [OUT_SIZE-1:0] rndbase_store [0:LFSR_LENGTH-1];




	assign out = rndbase_main[0];



	initial
	begin : clr_arrays_for_sim
		integer i;

		for(i=0;i<LFSR_LENGTH;i=i+1)
		begin
			rndbase_main [i] = 'd0;
			rndbase_store[i] = 'd0;
		end
	end




	always @(posedge clk)
	begin

		init2 <= init;

		if( init && !init2 ) // begin of initialization
		begin
			rndbase_main[0][0] <= 1'b1; // any non-zero init possible
		end
		else if( init && init2 ) // continue of initialization
		begin
			shift_lfsr;
		end
		else // no init, normal work
		begin

			if( restore ) // restore event: higher priority
			begin : blk1
				integer i;
				for(i=0;i<LFSR_LENGTH;i=i+1)
					rndbase_main[i] <= rndbase_store[i];
			end
			else
			begin
				if( next ) // step to next value
				begin
					shift_lfsr;
				end

				if( save ) // save current state
				begin : blk2
					integer j;
					for(j=0;j<LFSR_LENGTH;j=j+1)
						rndbase_store[j] <= rndbase_main[j];
				end
			end
		end
	end



/*	function [LFSR_LENGTH-1:0] shift_lfsr;

		input [LFSR_LENGTH-1:0] old_lfsr;

		begin
			if( |old_lfsr ) // prevent spurious stalls if all LFSR is zeros
				shift_lfsr[LFSR_LENGTH-1:0] = { old_lfsr[LFSR_LENGTH-2:0], old_lfsr[LFSR_LENGTH-1]^old_lfsr[LFSR_FEEDBACK-1] };
			else
               		shift_lfsr[LFSR_LENGTH-1:0] = 2'd1;
		end
	endfunction
*/

	task shift_lfsr;
	begin : blk3
		reg [OUT_SIZE-1:0] sum;
		reg [LFSR_LENGTH-1:0] lsbs;

		integer i;

		for(i=0;i<LFSR_LENGTH;i=i+1)
			lsbs[i] = rndbase_main[i][0];

		sum = rndbase_main[LFSR_LENGTH-1] + rndbase_main[LFSR_FEEDBACK-1];

//		integer j;
		for(i=1;i<LFSR_LENGTH;i=i+1)
			rndbase_main[i] <= rndbase_main[i-1];

		rndbase_main[0] <= { sum[OUT_SIZE-1:1], (|lsbs)?sum[0]:1'b1 };
	end
	endtask


endmodule





