rand.s (4002B)
1;/*************************************************************************** 2; * * 3; * Module : rand.s * 4; * * 5; * Purpose : A rand() generator using the linear congruential method * 6; * * 7; * Version : 1.01, January 7 1998 * 8; * Added _initrand to set seed without recompiling * 9; * 1, January 6 1998 * 10; * * 11; * Author : Luc Van den Borre ( Homepage : NOC.BASE.ORG ) * 12; * * 13; **************************************************************************/ 14 15 ;; Why use an algorithm for generating random numbers? 16 ;; 17 ;; - Given a certain seed value, the same sequence of random numbers is generated 18 ;; every time. This is a good thing when debugging (reproducible). On the other 19 ;; hand, you've got 2^16 seed values, each of which will produce a sequence of 20 ;; numbers that stays different for any of the other sequences for 'an appreciable 21 ;; time.' (I can't say how long exactly.) 22 ;; 23 ;; - The linear congruential method is one of the 'best' random number generators 24 ;; around. However, this implementation uses a 16 bit accumulator, while at least 25 ;; 32 bits are needed for a generator that passes all the statistical tests. 26 ;; Still, I'm relatively confident that this is random enough for even the most 27 ;; demanding game. 28 ;; 29 ;; Compare this to getting random values from one of the hardware registers 30 ;; (not reproducible, might not have all values). An array might be the best bet 31 ;; if you don't need a lot of values (or have lots of memory spare), 32 ;; or if you want values to be within a certain range. 33 ;; And both would be faster than this. Also, this definitely isn't the fastest 34 ;; algorithm I know, and certainly for games less strict algorithms might be 35 ;; appropriate (shift and xor ?). 36 ;; It's your choice - but if you're doing Monte Carlo physics simulations on the 37 ;; GameBoy, this is a safe bet! 38 39 .area _DATA 40___rand_seed:: 41.randlo: ; Storage for last random number (or seed) 42 .ds 0x01 43.randhi: 44 .ds 0x01 45 46 .area _HOME 47 48 ;; Random number generator using the linear congruential method 49 ;; X(n+1) = (a*X(n)+c) mod m 50 ;; with a = 17, m = 16 and c = $5c93 (arbitrarily) 51 ;; The seed value is also chosen arbitrarily as $a27e 52 ;; Ref : D. E. Knuth, "The Art of Computer Programming" , Volume 2 53 ;; 54 ;; Exit conditions 55 ;; DE = Random number [0,2^16-1] 56 ;; 57 ;; Registers used: 58 ;; A, HL (need not be saved) and DE (return register) 59 ;; 60 61_rand:: ; Banked 62_randw:: ; Banked 63 LD A,(.randlo) 64 LD L,A 65 LD E,A ; Save randlo 66 LD A,(.randhi) 67 LD D,A ; Save randhi 68 69 SLA L ; * 16 70 RLA 71 SLA L 72 RLA 73 SLA L 74 RLA 75 SLA L 76 RLA 77 LD H,A ; Save randhi*16 78 79 LD A,E ; Old randlo 80 ADD A,L ; Add randlo*16 81 LD L,A ; Save randlo*17 82 83 LD A,H ; randhi*16 84 ADC A,D ; Add old randhi 85 LD H,A ; Save randhi*17 86 87 LD A,L ; randlo*17 88 ADD A,#0x93 89 LD (.randlo),A 90 LD D,A ; Return register 91 LD A,H ; randhi*17 92 ADC A,#0x5c 93 LD (.randhi),A 94 LD E,A ; Return register 95 96 ;; Note D is the low byte,E the high byte. This is intentional because 97 ;; the high byte can be slightly 'more random' than the low byte, and I presume 98 ;; most will cast the return value to a uint8_t. As if someone will use this, tha! 99 RET 100 101 ;; This sets the seed value. Call it whenever you like 102 ;; 103 ;; Exit conditions 104 ;; None 105 ;; 106 ;; Registers used: 107 ;; A, HL (need not be saved) and DE (return register) 108 ;; 109 110_initrand:: 111 LDA HL,2(SP) 112.initrand:: 113 LD A,(HL+) 114 LD (.randlo),A 115 LD A,(HL) 116 LD (.randhi),A 117 RET