4 ; Generating random numbers
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Sapphire library.
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ;----- Standard header ------------------------------------------------------
32 ;----- External dependencies ------------------------------------------------
37 ;----- Main code ------------------------------------------------------------
39 AREA |Sapphire$$Code|,CODE,READONLY
45 ; On exit: R0 == a pseudorandom number between 0 and &7FFFFFFF
47 ; Use: Returns a pseudorandom number. The algorithm used is the
48 ; additive generator found in Knuth. The table is generated
49 ; from the current monotonic time using a linear congruential
50 ; generator. Randomness is fairly good, and it's very quick.
55 STMFD R13!,{R1-R3,R12,R14} ;Save some registers
56 WSPACE rand__wSpace ;Find my workspace address
57 LDMIB R12,{R1,R2} ;Load the table indices
58 ADR R3,rand__table ;Find the ring buffer
59 LDR R0,[R3,R1,LSL #2] ;Load the value x[n-24]
60 LDR R14,[R3,R2,LSL #2] ;Load the value x[n-55]
61 ADD R0,R0,R14 ;And form the new number
62 STR R0,[R3,R2,LSL #2] ;Store new number in buffer
63 SUBS R1,R1,#1 ;Decrement x-24 index
64 MOVLT R1,#54 ;If too small, wrap it round
65 SUBS R2,R2,#1 ;Decrement x-55 index
66 MOVLT R2,#54 ;If too small, wrap it round
67 STMIB R12,{R1,R2} ;Save the indices back again
68 BIC R0,R0,#&80000000 ;Clear the top bit (positive)
69 LDMFD R13!,{R1-R3,R12,PC}^ ;Return to caller
73 ; --- rand_setSeed ---
75 ; On entry: R0 == a pseudorandom seed
79 ; Use: Sets up the random number generator (rand) to the given start
80 ; position. The table of values is initialised from the seed
81 ; in a psuedorandom manner, using a linear congruential
87 STMFD R13!,{R0-R2,R12,R14} ;Save some registers
88 WSPACE rand__wSpace ;Find my workspace address
90 ; --- Reset the indices ---
92 MOV R1,#23 ;Start 24-index at 24-1
93 MOV R2,#54 ;Start 55-index at 55-1
94 STMIB R12,{R1,R2} ;Save them away
96 ; --- Now start populating the table ---
98 ADR R1,rand__table ;Point to the ring buffer
99 MOV R2,#55 ;Counter for the items
101 00rand_setSeed ADD R14,R0,R0,LSR #16 ;Mangle the seed a little
102 STR R14,[R1],#4 ;Save it in the table
104 ADD R14,R0,R0,LSL #2 ;Do multiply op in generator
105 RSB R14,R14,R14,LSL #4
110 ADD R0,R0,#&66000000 ;Do add op in generator
115 SUBS R2,R2,#1 ;Decrement the counter
116 BGT %00rand_setSeed ;If not finished, go again
118 LDMFD R13!,{R0-R2,R12,PC}^ ;Return to caller
124 ; On entry: R0 == start value (inclusive)
125 ; R1 == end value (inclusive)
127 ; On exit: R0 == random number between the boundaries given
129 ; Use: Returns a random integer between the boundaries given.
130 ; The distribution is slightly skewed towards lower numbers,
131 ; but there's not a lot I can do about this, folks.
136 STMFD R13!,{R1,R2,R14} ;Save a bunch of registers
137 MOV R2,R0 ;Look after the start value
138 SUB R1,R1,R0 ;Subtract the initial value
139 ADD R1,R1,#1 ;Make it inclusive nicely
140 BL rand ;Get a random number
141 BL divide ;Force it to be in range
142 ADD R0,R1,R2 ;And add the start value
143 LDMFD R13!,{R1,R2,PC}^ ;Return to caller
153 ; Use: Initialise the random number table.
158 STMFD R13!,{R12,R14} ;Save a register or two
159 WSPACE rand__wSpace ;Find my workspace
160 LDR R14,rand__flags ;Load my flags word
161 TST R14,#rFlag__inited ;Am I initialised yet?
162 LDMNEFD R13!,{R12,PC}^ ;Yes -- don't do it again
164 ORR R14,R14,#rFlag__inited ;Set the flag then
165 STR R14,rand__flags ;And save back the new flags
166 STMFD R13!,{R0} ;Save another register
167 SWI OS_ReadMonotonicTime ;Load the current time
168 BL rand_setSeed ;Set up the random table
169 LDMFD R13!,{R0,R12,PC}^ ;And return to caller
175 ;------ Workspace -----------------------------------------------------------
180 rand__flags # 4 ;Various flaglike objects
182 rand__24 # 4 ;Offset to item 24 in buffer
183 rand__55 # 4 ;Offset to item 55 in buffer
185 rand__table # 55*4 ;The random number table
187 rand__wSize EQU {VAR}-rand__wStart
189 rFlag__inited EQU (1<<0) ;Am I initialised yet?
191 AREA |Sapphire$$LibData|,CODE,READONLY
198 ;----- That's all, folks ----------------------------------------------------