Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / rand
1 ;
2 ; rand.s
3 ;
4 ; Generating random numbers
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
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)
16 ; any later version.
17 ;
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.
22 ;
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.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 ;----- External dependencies ------------------------------------------------
33
34 GET sapphire:divide
35 GET sapphire:sapphire
36
37 ;----- Main code ------------------------------------------------------------
38
39 AREA |Sapphire$$Code|,CODE,READONLY
40
41 ; --- rand ---
42 ;
43 ; On entry: --
44 ;
45 ; On exit: R0 == a pseudorandom number between 0 and &7FFFFFFF
46 ;
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.
51
52 EXPORT rand
53 rand ROUT
54
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
70
71 LTORG
72
73 ; --- rand_setSeed ---
74 ;
75 ; On entry: R0 == a pseudorandom seed
76 ;
77 ; On exit: --
78 ;
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
82 ; generator.
83
84 EXPORT rand_setSeed
85 rand_setSeed ROUT
86
87 STMFD R13!,{R0-R2,R12,R14} ;Save some registers
88 WSPACE rand__wSpace ;Find my workspace address
89
90 ; --- Reset the indices ---
91
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
95
96 ; --- Now start populating the table ---
97
98 ADR R1,rand__table ;Point to the ring buffer
99 MOV R2,#55 ;Counter for the items
100
101 00rand_setSeed ADD R14,R0,R0,LSR #16 ;Mangle the seed a little
102 STR R14,[R1],#4 ;Save it in the table
103
104 ADD R14,R0,R0,LSL #2 ;Do multiply op in generator
105 RSB R14,R14,R14,LSL #4
106 RSB R0,R0,R14,LSL #2
107 RSB R0,R0,R0,LSL #3
108 ADD R0,R0,R0,LSL #5
109
110 ADD R0,R0,#&66000000 ;Do add op in generator
111 ADD R0,R0,#&00D60000
112 ADD R0,R0,#&00001900
113 ADD R0,R0,#&000000E1
114
115 SUBS R2,R2,#1 ;Decrement the counter
116 BGT %00rand_setSeed ;If not finished, go again
117
118 LDMFD R13!,{R0-R2,R12,PC}^ ;Return to caller
119
120 LTORG
121
122 ; --- rnd ---
123 ;
124 ; On entry: R0 == start value (inclusive)
125 ; R1 == end value (inclusive)
126 ;
127 ; On exit: R0 == random number between the boundaries given
128 ;
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.
132
133 EXPORT rnd
134 rnd ROUT
135
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
144
145 LTORG
146
147 ; --- rand_init ---
148 ;
149 ; On entry: --
150 ;
151 ; On exit: --
152 ;
153 ; Use: Initialise the random number table.
154
155 EXPORT rand_init
156 rand_init ROUT
157
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
163
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
170
171 LTORG
172
173 rand__wSpace DCD 0
174
175 ;------ Workspace -----------------------------------------------------------
176
177 ^ 0,R12
178 rand__wStart # 0
179
180 rand__flags # 4 ;Various flaglike objects
181
182 rand__24 # 4 ;Offset to item 24 in buffer
183 rand__55 # 4 ;Offset to item 55 in buffer
184
185 rand__table # 55*4 ;The random number table
186
187 rand__wSize EQU {VAR}-rand__wStart
188
189 rFlag__inited EQU (1<<0) ;Am I initialised yet?
190
191 AREA |Sapphire$$LibData|,CODE,READONLY
192
193 DCD rand__wSize
194 DCD rand__wSpace
195 DCD 0
196 DCD rand_init
197
198 ;----- That's all, folks ----------------------------------------------------
199
200 END