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