// Filename:	mersenne.v
// Author:	David Ljung Madison <DaveSource.com>
// See License:	http://MarginalHacks.com/License
// Version:	1.0
// Description:	Verilog implementation of the Mersenne Twister, a great
//		random number generator
//
// Other implementations at: http://www.math.keio.ac.jp/~matumoto/emt.html
//
module mersenne;
`define MERSENNE_N		624
`define MERSENNE_M		397
`define MERSENNE_MATRIX_A	32'h9908b0df	/* constant vector a */ 
`define MERSENNE_UPPER_MASK	32'h80000000	/* most significant w-r bits */
`define MERSENNE_LOWER_MASK	32'h7fffffff	/* least significant r bits */

/* Tempering parameters */
`define TEMPERING_MASK_B	32'h9d2c5680
`define TEMPERING_MASK_C	32'hefc60000
`define TEMPERING_SHIFT_U	11
`define TEMPERING_SHIFT_S	7
`define TEMPERING_SHIFT_T	15
`define TEMPERING_SHIFT_L	18

	integer	mt	[0:`MERSENNE_N];	/* the array for the state vector  */
	integer	mti;

	task	srand;
		input	[31:0]	seed;
	begin
		// Setting initial seeds to mt[N] using the generator 
		// Line 25 of Table 1 in [KNUTH 1981, The Art of Computer
		// Programming Vol. 2 (2nd Ed.), pp102]
		mt[0] = seed;
		for (mti=1; mti<`MERSENNE_N; mti=mti+1)
	    	mt[mti] = (69069 * mt[mti-1]);
	end
	endtask

	task	rand;
		output [31:0]	out;
		integer	y;
		integer	kk;
	begin

		if (|mti===1'bx || mti>=`MERSENNE_N) begin
			if (|mti===1'bx) srand(4357);		// Default seed

			for (kk=0; kk<`MERSENNE_N-`MERSENNE_M; kk=kk+1) begin
				y = (mt[kk]&`MERSENNE_UPPER_MASK)|(mt[kk+1]&`MERSENNE_LOWER_MASK);
				mt[kk] = mt[kk+`MERSENNE_M] ^ (y >> 1) ^ (y&1 ? `MERSENNE_MATRIX_A : 0);
			end

			for (kk=kk; kk<`MERSENNE_N-1; kk=kk+1) begin
				y = (mt[kk]&`MERSENNE_UPPER_MASK)|(mt[kk+1]&`MERSENNE_LOWER_MASK);
				mt[kk] = mt[kk+(`MERSENNE_M-`MERSENNE_N)] ^ (y >> 1) ^ (y&1 ? `MERSENNE_MATRIX_A : 0);
			end
			y = (mt[`MERSENNE_N-1]&`MERSENNE_UPPER_MASK)|(mt[0]&`MERSENNE_LOWER_MASK);
			mt[`MERSENNE_N-1] = mt[`MERSENNE_M-1] ^ (y >> 1) ^ (y&1 ? `MERSENNE_MATRIX_A : 0);
			
			mti = 0;

		end

		y = mt[mti];
		mti = mti + 1;
		y = y ^ (y >> `TEMPERING_SHIFT_U);
		y = y ^ ((y << `TEMPERING_SHIFT_S) & `TEMPERING_MASK_B);
		y = y ^ ((y << `TEMPERING_SHIFT_T) & `TEMPERING_MASK_C);
		y = y ^ (y >> `TEMPERING_SHIFT_L);

		out = y;
	end
	endtask
endmodule

module top;

	mersenne r1 ();
	mersenne r2 ();

	integer	x;
	integer	c;

	initial begin
		r1.srand(8833);
		for (c=0; c<8; c=c+1) begin
			r1.rand(x);
			$write("%x ",x);
		end
		$write("\n");

	end

endmodule

