altos: Rename 'core' to 'kernel'
[fw/altos] / src / kernel / ao_int64.c
1 /*
2  * Copyright © 2013 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao_int64.h>
19
20 __pdata ao_int64_t *__data ao_64r, *__data ao_64a, *__data ao_64b;
21
22 void ao_plus64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, __pdata ao_int64_t *b) __FATTR {
23         __LOCAL uint32_t        t;
24
25         r->high = a->high + b->high;
26         t = a->low + b->low;
27         if (t < a->low)
28                 r->high++;
29         r->low = t;
30 }
31
32 void ao_minus64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, __pdata ao_int64_t *b) __FATTR {
33         __LOCAL uint32_t        t;
34
35         r->high = a->high - b->high;
36         t = a->low - b->low;
37         if (t > a->low)
38                 r->high--;
39         r->low = t;
40 }
41
42 void ao_rshift64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, uint8_t d) __FATTR {
43         if (d < 32) {
44                 r->low = a->low >> d;
45                 if (d)
46                         r->low |= a->high << (32 - d);
47                 r->high = (int32_t) a->high >> d;
48         } else {
49                 d &= 0x1f;
50                 r->low = (int32_t) a->high >> d;
51                 r->high = 0;
52         }
53 }
54
55 void ao_lshift64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, uint8_t d) __FATTR {
56         if (d < 32) {
57                 r->high = a->high << d;
58                 if (d)
59                         r->high |= a->low >> (32 - d);
60                 r->low = a->low << d;
61         } else {
62                 d &= 0x1f;
63                 r->high = a->low << d;
64                 r->low = 0;
65         }
66 }
67
68 static void ao_umul64_32_32(__ARG ao_int64_t *r, uint32_t a, uint32_t b) __reentrant {
69         __LOCAL uint32_t        s;
70         __LOCAL ao_int64_t      t;
71         r->low = (uint32_t) (uint16_t) a * (uint16_t) b;
72         r->high = (uint32_t) (uint16_t) (a >> 16) * (uint16_t) (b >> 16);
73
74         s = (uint32_t) (uint16_t) (a >> 16) * (uint16_t) b;
75
76         t.high = s >> 16;
77         t.low = s << 16;
78         ao_plus64(r, r, &t);
79
80         s = (uint32_t) (uint16_t) a * (uint16_t) (b >> 16);
81
82         t.high = s >> 16;
83         t.low = s << 16;
84         ao_plus64(r, r, &t);
85 }
86
87 void ao_neg64(__pdata ao_int64_t *r, __pdata ao_int64_t *a) __FATTR {
88         r->high = ~a->high;
89         if (!(r->low = ~a->low + 1))
90                 r->high++;
91 }
92
93 void ao_mul64_32_32(__ARG ao_int64_t *r, int32_t a, int32_t b) __FATTR {
94         uint8_t         negative = 0;
95
96         if (a < 0) {
97                 a = -a;
98                 ++negative;
99         }
100         if (b < 0) {
101                 b = -b;
102                 --negative;
103         }
104         ao_umul64_32_32(r, a, b);
105         if (negative)
106                 ao_neg64(r, r);
107 }
108
109 static void ao_umul64(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG ao_int64_t *b) __reentrant {
110         __LOCAL ao_int64_t      r2, r3;
111
112         ao_umul64_32_32(&r2, a->high, b->low);
113         ao_umul64_32_32(&r3, a->low, b->high);
114         ao_umul64_32_32(r, a->low, b->low);
115
116         r->high += r2.low + r3.low;
117 }
118
119 static __ARG ao_int64_t ap, bp;
120
121 void ao_mul64(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG ao_int64_t *b) __FATTR {
122         uint8_t negative = 0;
123
124         if (ao_int64_negativep(a)) {
125                 ao_neg64(&ap, a);
126                 a = &ap;
127                 ++negative;
128         }
129         if (ao_int64_negativep(b)) {
130                 ao_neg64(&bp, b);
131                 b = &bp;
132                 --negative;
133         }
134         ao_umul64(r, a, b);
135         if (negative)
136                 ao_neg64(r, r);
137 }
138
139 static void ao_umul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, uint16_t b) __reentrant {
140         __LOCAL uint32_t h;
141
142         h = a->high * b;
143         ao_umul64_32_32(r, a->low, b);
144         r->high += h;
145 }
146
147 void ao_mul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG uint16_t b) __FATTR {
148         uint8_t         negative = 0;
149
150         if ((int32_t) a->high < 0) {
151                 ao_neg64(&ap, a);
152                 a = &ap;
153                 negative++;
154         } else
155                 ao_umul64_64_16(r, a, b);
156         if (negative)
157                 ao_neg64(r, r);
158 }