cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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