4 ; Various routines of a division-related nature (MDW/TMA)
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 ;----- Simple mathematics ---------------------------------------------------
34 AREA |Sapphire$$Code|,CODE,READONLY
38 ; On entry: R0 == dividend
41 ; On exit: R0 == quotient
44 ; Use: A standard divide routine. Fairly speedy, hopefully.
45 ; The results are always such that
47 ; |quotient| <= |(divisor/dividend)|,
49 ; |remainder| < |divisor|
53 ; quotient * divisor + remainder == dividend
58 STMFD R13!,{R2,R14} ;Save some registers
60 ; --- First, mess about with the signs ---
62 ANDS R2,R0,#&80000000 ;Get the dividend's sign bit
63 ORR R2,R2,R2,LSR #1 ;Copy -- this is sign of mod
64 RSBNE R0,R0,#0 ;Take absolute value of R0
65 ANDS R14,R1,#&80000000 ;Get the divisor's sign too
66 RSBNE R1,R1,#0 ;Take absolute value of R1
67 EOR R2,R2,R14 ;Calculate sign of quotient
69 ; --- Now do the division ---
71 BL div_unsigned ;That's done for us elsewhere
73 ; --- Now tidy everything up ---
75 TST R2,#&40000000 ;Is remainder to be negative?
76 RSBNE R1,R1,#0 ;Yes -- negate it
77 TST R2,#&80000000 ;Is quotient to be negative?
78 RSBNE R0,R0,#0 ;Yes -- negate it
80 LDMFD R13!,{R2,PC}^ ;Return to caller
84 ; --- div_unsigned ---
86 ; On entry: R0 == dividend
89 ; On exit: R0 == quotient
92 ; Use: As for divide, except that it considers its operands to be
99 CMP R1,#0 ;Check for divide by zero
100 BEQ div_byZero ;Yes -- make the error
101 STMFD R13!,{R2,R3,R14} ;Save some registers
103 ; --- A note about the method ---
105 ; We use traditional long division, but unroll the loop a
106 ; lot to keep the thing ticking over at a good rate.
108 MOV R14,R1 ;Look after the divisor
109 ANDS R3,R0,#&80000000 ;Is the top dividend bit set?
110 MOVEQ R3,R0 ;No -- use the real thing
112 ; --- Shift divisor up for long division ---
114 ; We keep shifting the divisor up until it's greater than
115 ; the dividend, and then we skip ahead to the divide section
117 MOV R2,#0 ;Quotient starts off at 0
118 00div_unsigned CMP R3,R14,LSL #0
136 ; --- Now we have the shift-down loop ---
138 ; This is where the actual job of dividing is performed.
139 ; We shift the divisor back down until it's back where we
142 17div_unsigned CMP R0,R14,LSL #7
144 SUBCS R0,R0,R14,LSL #7
145 16div_unsigned CMP R0,R14,LSL #6
147 SUBCS R0,R0,R14,LSL #6
148 15div_unsigned CMP R0,R14,LSL #5
150 SUBCS R0,R0,R14,LSL #5
151 14div_unsigned CMP R0,R14,LSL #4
153 SUBCS R0,R0,R14,LSL #4
154 13div_unsigned CMP R0,R14,LSL #3
156 SUBCS R0,R0,R14,LSL #3
157 12div_unsigned CMP R0,R14,LSL #2
159 SUBCS R0,R0,R14,LSL #2
160 11div_unsigned CMP R0,R14,LSL #1
162 SUBCS R0,R0,R14,LSL #1
163 10div_unsigned CMP R0,R14,LSL #0
165 SUBCS R0,R0,R14,LSL #0
167 CMP R14,R1 ;Have we finished dividing?
168 MOVHI R14,R14,LSR #8 ;No -- shift down a byte
169 BHI %17div_unsigned ;And loop round again
171 ; --- Now tidy everything up ---
173 MOV R1,R0 ;Copy results into registers
176 LDMFD R13!,{R2,R3,PC}^ ;Return to caller
178 div_byZero ADR R0,divByZero
182 DCB "Division by zero",0
188 ; On entry: R0 == integer to divide
190 ; On exit: R0 == quotient after division by 10
191 ; R1 == remainder after division by 10
193 ; Use: Divides an integer very quickly by 10.
195 ; [Generated by Straylight divc]
227 ; On entry: R0 == dividend
230 ; On exit: R0 == quotient, rounded to nearest integer
233 ; Use: Calculates a rounded-to-nearest quotient, rather than one
234 ; rounded towards zero, which is what divide returns you.
236 ; The remainder is fiddled during this process, so that the
239 ; quotient * divisor + remainder == dividend
243 ; |remainder| < |divisor|
245 ; still hold (so the remainder's sign may well change).
250 STMFD R13!,{R2,R14} ;Save some registers
251 MOV R2,R0 ;Keep a copy of the dividend
252 CMP R1,#0 ;Is the divisor positive?
253 MOVGE R14,R1 ;Yes -- just copy it
254 RSBLT R14,R1,#0 ;No -- negate it on the way
255 CMP R0,#0 ;Is the dividend positive?
256 ADDGE R0,R0,R14,ASR #1 ;Yes -- add half the divisor
257 SUBLT R0,R0,R14,ASR #1 ;No -- subtract it
258 SUB R2,R2,R0 ;Remember this difference
259 BL divide ;Do the division
260 ADD R1,R1,R2 ;Modify remainder suitably
261 LDMFD R13!,{R2,PC}^ ;Return to caller
267 ; On entry: R0,R1 == dividend (high word in R1)
270 ; On exit: R0 == quotient
273 ; Use: Divides a 64-bit unsigned value by a 32-bit unsigned value
274 ; yielding 32-bit unsigned quotient and remainder. If there
275 ; are more than 32 bits of quotient, the return values are
281 STMFD R13!,{R14} ;Save the link register
283 MOV R14,#8 ;Initialise the loop counter
292 CMP R1,R2 ;Can we subtract here?
293 SUBCS R1,R1,R2 ;Yes -- do that then
294 ADCS R0,R0,R0 ;Shift up quotient/dividend
295 ADC R1,R1,R1 ;Put next dividend bit in R1
300 SUBS R14,R14,#1 ;Decrement loop counter
301 BGT %00div_u64x32 ;If more to do, loop round
303 CMP R1,R2 ;Can we subtract here?
304 SUBCS R1,R1,R2 ;Yes -- do that then
305 ADCS R0,R0,R0 ;Shift up quotient
307 LDMFD R13!,{PC}^ ;And return to caller
311 ;----- That's all, folks ----------------------------------------------------