rev |
line source |
nuclear@4
|
1 #include "fixed.h"
|
nuclear@4
|
2
|
nuclear@4
|
3 #if 0
|
nuclear@4
|
4 /* fast 16.16 division ripped from http://me.henri.net/fp-div.html */
|
nuclear@4
|
5 int32_t x16div(register int32_t numerator, register int32_t denominator)
|
nuclear@4
|
6 {
|
nuclear@4
|
7 register int32_t quotient;
|
nuclear@4
|
8 asm("num .req %[numerator] @ Map Register Equates\n\t"
|
nuclear@4
|
9 "den .req %[denominator]\n\t"
|
nuclear@4
|
10 "mod .req r2\n\t"
|
nuclear@4
|
11 "cnt .req r3\n\t"
|
nuclear@4
|
12 "quo .req r4\n\t"
|
nuclear@4
|
13 "sign .req r12\n\t"
|
nuclear@4
|
14 /* set sign and ensure numerator and denominator are positive */
|
nuclear@4
|
15 "cmp den, #0 @ exceptioin if den == zero\n\t"
|
nuclear@4
|
16 "beq .div0\n\t"
|
nuclear@4
|
17 "eor sign, num, den @ sign = num ^ den\n\t"
|
nuclear@4
|
18 "rsbmi den, den, #0 @ den = -den if den < 0\n\t"
|
nuclear@4
|
19 "subs mod, den, #1 @ mod = den - 1\n\t"
|
nuclear@4
|
20 "beq .div1 @ return if den == 1\n\t"
|
nuclear@4
|
21 "movs cnt, num @ num = -num if num < 0\n\t"
|
nuclear@4
|
22 "rsbmi num, num, #0\n\t"
|
nuclear@4
|
23 /* skip if deniminator >= numerator */
|
nuclear@4
|
24 "movs cnt, num, lsr #16 @ return if den >= num << 16\n\t"
|
nuclear@4
|
25 "bne .cont\n\t"
|
nuclear@4
|
26 "cmp den, num, lsl #16\n\t"
|
nuclear@4
|
27 "bhs .numLeDen\n\t"
|
nuclear@4
|
28 "\n.cont:\n\t"
|
nuclear@4
|
29 /* test if denominator is a power of two */
|
nuclear@4
|
30 "tst den, mod @ if(den & (den - 1) == 0)\n\t"
|
nuclear@4
|
31 "beq .powerOf2 @ den is power of 2\n\t"
|
nuclear@4
|
32 /* count leading zeros */
|
nuclear@4
|
33 "stmfd sp!, {r4} @ push r4 (quo) onto the stack\n\t"
|
nuclear@4
|
34 "mov cnt, #28 @ count difference in leading zeros\n\t"
|
nuclear@4
|
35 "mov mod, num, lsr #4 @ between num and den\n\t"
|
nuclear@4
|
36 "cmp den, mod, lsr #12; subls cnt, cnt, #16; movls mod, mod, lsr #16\n\t"
|
nuclear@4
|
37 "cmp den, mod, lsr #4 ; subls cnt, cnt, #8 ; movls mod, mod, lsr #8\n\t"
|
nuclear@4
|
38 "cmp den, mod ; subls cnt, cnt, #4 ; movls mod, mod, lsr #4\n\t"
|
nuclear@4
|
39 /* shift numerator left by cnt bits */
|
nuclear@4
|
40 "mov num, num, lsl cnt @ mod:num = num << cnt\n\t"
|
nuclear@4
|
41 "mov quo, #0\n\t"
|
nuclear@4
|
42 "rsb den, den, #0 @ negate den for divide loop\n\t"
|
nuclear@4
|
43 /* skip cnt iterations in the divide loop */
|
nuclear@4
|
44 "adds num, num, num @ start: num = mod:num / den\n\t"
|
nuclear@4
|
45 "add pc, pc, cnt, lsl #4 @ skip cnt x 4 x 4 iterations\n\t"
|
nuclear@4
|
46 "nop @ nop instruction takes care of pipeline\n\t"
|
nuclear@4
|
47 /* inner loop unrolled x 48 */
|
nuclear@4
|
48 ".rept 47 @ inner loop x 48\n\t"
|
nuclear@4
|
49 " adcs mod, den, mod, lsl #1\n\t"
|
nuclear@4
|
50 " subcc mod, mod, den\n\t"
|
nuclear@4
|
51 " adc quo, quo, quo\n\t"
|
nuclear@4
|
52 " adds num, num, num\n\t"
|
nuclear@4
|
53 ".endr\n\t"
|
nuclear@4
|
54 "adcs mod, den, mod, lsl #1\n\t"
|
nuclear@4
|
55 "subcc mod, mod, den\n\t"
|
nuclear@4
|
56 "adc quo, quo, quo\n\t"
|
nuclear@4
|
57 /* negate quotient if signed */
|
nuclear@4
|
58 "cmp sign, #0 @ negate quotient if sign < 0\n\t"
|
nuclear@4
|
59 "mov num, quo\n\t"
|
nuclear@4
|
60 "rsbmi num, num, #0\n\t"
|
nuclear@4
|
61 "ldmfd sp!, {r4} @ pop r4 (quo) off the stack\n\t"
|
nuclear@4
|
62 "mov pc, lr @return\n\t"
|
nuclear@4
|
63 /* divide by zero handler */
|
nuclear@4
|
64 "\n.div0:\n\t"
|
nuclear@4
|
65 "mov num, #0\n\t"
|
nuclear@4
|
66 "mov pc, lr @return\n\t"
|
nuclear@4
|
67 /* divide by one handler */
|
nuclear@4
|
68 "\n.div1:\n\t"
|
nuclear@4
|
69 "cmp sign, #0\n\t"
|
nuclear@4
|
70 "mov num, num, asl #16\n\t"
|
nuclear@4
|
71 "rsbmi num, num, #0\n\t"
|
nuclear@4
|
72 "mov pc, lr @return\n\t"
|
nuclear@4
|
73 /* numerator less than or equal to denominator handler */
|
nuclear@4
|
74 "\n.numLeDen:\n\t"
|
nuclear@4
|
75 "mov num, #0 @ quotient = 0 if num < den\n\t"
|
nuclear@4
|
76 "moveq num, sign, asr #31 @ negate quotient if sign < 0\n\t"
|
nuclear@4
|
77 "orreq num, num, #1 @ quotient = 1 if num == den\n\t"
|
nuclear@4
|
78 "mov pc, lr @return\n\t"
|
nuclear@4
|
79 /* power of two handler */
|
nuclear@4
|
80 "\n.powerOf2:\n\t"
|
nuclear@4
|
81 "mov cnt, #0\n\t"
|
nuclear@4
|
82 "cmp den, #(1 << 16); movhs cnt, #16 ; movhs den, den, lsr #16\n\t"
|
nuclear@4
|
83 "cmp den, #(1 << 8) ; addhs cnt, cnt, #8; movhs den, den, lsr #8\n\t"
|
nuclear@4
|
84 "cmp den, #(1 << 4) ; addhs cnt, cnt, #4; movhs den, den, lsr #4\n\t"
|
nuclear@4
|
85 "cmp den, #(1 << 2) ; addhi cnt, cnt, #3; addls cnt, cnt, den, lsr #1\n\t"
|
nuclear@4
|
86 "rsb mod, cnt, #32\n\t"
|
nuclear@4
|
87 "mov den, num, lsr #16 @ den:num = num << 16\n\t"
|
nuclear@4
|
88 "mov num, num, lsl #16\n\t"
|
nuclear@4
|
89 "mov num, num, lsr cnt @ num = num >> cnt | den << mod\n\t"
|
nuclear@4
|
90 "orr num, num, den, lsl mod\n\t"
|
nuclear@4
|
91 "cmp sign, #0\n\t"
|
nuclear@4
|
92 "rsbmi num, num, #0 @ negate quotient if sign < 0"
|
nuclear@4
|
93 /* output registers */
|
nuclear@4
|
94 : [quotient] "=r" (quotient)
|
nuclear@4
|
95 /* input registers */
|
nuclear@4
|
96 : [numerator] "0" (numerator), [denominator] "r" (denominator)
|
nuclear@4
|
97 /* clobbered registers */
|
nuclear@4
|
98 : "r2" /* mod */, "r3" /* cnt */, "r12" /* sign */);
|
nuclear@4
|
99 return quotient;
|
nuclear@4
|
100 }
|
nuclear@4
|
101 #endif
|