1 /*
2 * ARM generic helpers for various arithmetical operations.
3 *
4 * This code is licensed under the GNU GPL v2 or later.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 #include "qemu/osdep.h"
9 #include "cpu.h"
10 #include "exec/helper-proto.h"
11 #include "qemu/crc32c.h"
12 #include <zlib.h> /* for crc32 */
13
14 /*
15 * Note that signed overflow is undefined in C. The following routines are
16 * careful to use unsigned types where modulo arithmetic is required.
17 * Failure to do so _will_ break on newer gcc.
18 */
19
20 /* Signed saturating arithmetic. */
21
22 /* Perform 16-bit signed saturating addition. */
add16_sat(uint16_t a,uint16_t b)23 static inline uint16_t add16_sat(uint16_t a, uint16_t b)
24 {
25 uint16_t res;
26
27 res = a + b;
28 if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
29 if (a & 0x8000) {
30 res = 0x8000;
31 } else {
32 res = 0x7fff;
33 }
34 }
35 return res;
36 }
37
38 /* Perform 8-bit signed saturating addition. */
add8_sat(uint8_t a,uint8_t b)39 static inline uint8_t add8_sat(uint8_t a, uint8_t b)
40 {
41 uint8_t res;
42
43 res = a + b;
44 if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
45 if (a & 0x80) {
46 res = 0x80;
47 } else {
48 res = 0x7f;
49 }
50 }
51 return res;
52 }
53
54 /* Perform 16-bit signed saturating subtraction. */
sub16_sat(uint16_t a,uint16_t b)55 static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
56 {
57 uint16_t res;
58
59 res = a - b;
60 if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
61 if (a & 0x8000) {
62 res = 0x8000;
63 } else {
64 res = 0x7fff;
65 }
66 }
67 return res;
68 }
69
70 /* Perform 8-bit signed saturating subtraction. */
sub8_sat(uint8_t a,uint8_t b)71 static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
72 {
73 uint8_t res;
74
75 res = a - b;
76 if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
77 if (a & 0x80) {
78 res = 0x80;
79 } else {
80 res = 0x7f;
81 }
82 }
83 return res;
84 }
85
86 #define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
87 #define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
88 #define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8);
89 #define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8);
90 #define PFX q
91
92 #include "op_addsub.c.inc"
93
94 /* Unsigned saturating arithmetic. */
add16_usat(uint16_t a,uint16_t b)95 static inline uint16_t add16_usat(uint16_t a, uint16_t b)
96 {
97 uint16_t res;
98 res = a + b;
99 if (res < a) {
100 res = 0xffff;
101 }
102 return res;
103 }
104
sub16_usat(uint16_t a,uint16_t b)105 static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
106 {
107 if (a > b) {
108 return a - b;
109 } else {
110 return 0;
111 }
112 }
113
add8_usat(uint8_t a,uint8_t b)114 static inline uint8_t add8_usat(uint8_t a, uint8_t b)
115 {
116 uint8_t res;
117 res = a + b;
118 if (res < a) {
119 res = 0xff;
120 }
121 return res;
122 }
123
sub8_usat(uint8_t a,uint8_t b)124 static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
125 {
126 if (a > b) {
127 return a - b;
128 } else {
129 return 0;
130 }
131 }
132
133 #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
134 #define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
135 #define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8);
136 #define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8);
137 #define PFX uq
138
139 #include "op_addsub.c.inc"
140
141 /* Signed modulo arithmetic. */
142 #define SARITH16(a, b, n, op) do { \
143 int32_t sum; \
144 sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
145 RESULT(sum, n, 16); \
146 if (sum >= 0) \
147 ge |= 3 << (n * 2); \
148 } while (0)
149
150 #define SARITH8(a, b, n, op) do { \
151 int32_t sum; \
152 sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
153 RESULT(sum, n, 8); \
154 if (sum >= 0) \
155 ge |= 1 << n; \
156 } while (0)
157
158
159 #define ADD16(a, b, n) SARITH16(a, b, n, +)
160 #define SUB16(a, b, n) SARITH16(a, b, n, -)
161 #define ADD8(a, b, n) SARITH8(a, b, n, +)
162 #define SUB8(a, b, n) SARITH8(a, b, n, -)
163 #define PFX s
164 #define ARITH_GE
165
166 #include "op_addsub.c.inc"
167
168 /* Unsigned modulo arithmetic. */
169 #define ADD16(a, b, n) do { \
170 uint32_t sum; \
171 sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
172 RESULT(sum, n, 16); \
173 if ((sum >> 16) == 1) \
174 ge |= 3 << (n * 2); \
175 } while (0)
176
177 #define ADD8(a, b, n) do { \
178 uint32_t sum; \
179 sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
180 RESULT(sum, n, 8); \
181 if ((sum >> 8) == 1) \
182 ge |= 1 << n; \
183 } while (0)
184
185 #define SUB16(a, b, n) do { \
186 uint32_t sum; \
187 sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
188 RESULT(sum, n, 16); \
189 if ((sum >> 16) == 0) \
190 ge |= 3 << (n * 2); \
191 } while (0)
192
193 #define SUB8(a, b, n) do { \
194 uint32_t sum; \
195 sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
196 RESULT(sum, n, 8); \
197 if ((sum >> 8) == 0) \
198 ge |= 1 << n; \
199 } while (0)
200
201 #define PFX u
202 #define ARITH_GE
203
204 #include "op_addsub.c.inc"
205
206 /* Halved signed arithmetic. */
207 #define ADD16(a, b, n) \
208 RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
209 #define SUB16(a, b, n) \
210 RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
211 #define ADD8(a, b, n) \
212 RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
213 #define SUB8(a, b, n) \
214 RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
215 #define PFX sh
216
217 #include "op_addsub.c.inc"
218
219 /* Halved unsigned arithmetic. */
220 #define ADD16(a, b, n) \
221 RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
222 #define SUB16(a, b, n) \
223 RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
224 #define ADD8(a, b, n) \
225 RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
226 #define SUB8(a, b, n) \
227 RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
228 #define PFX uh
229
230 #include "op_addsub.c.inc"
231
do_usad(uint8_t a,uint8_t b)232 static inline uint8_t do_usad(uint8_t a, uint8_t b)
233 {
234 if (a > b) {
235 return a - b;
236 } else {
237 return b - a;
238 }
239 }
240
241 /* Unsigned sum of absolute byte differences. */
HELPER(usad8)242 uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
243 {
244 uint32_t sum;
245 sum = do_usad(a, b);
246 sum += do_usad(a >> 8, b >> 8);
247 sum += do_usad(a >> 16, b >> 16);
248 sum += do_usad(a >> 24, b >> 24);
249 return sum;
250 }
251
252 /* For ARMv6 SEL instruction. */
HELPER(sel_flags)253 uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
254 {
255 uint32_t mask;
256
257 mask = 0;
258 if (flags & 1) {
259 mask |= 0xff;
260 }
261 if (flags & 2) {
262 mask |= 0xff00;
263 }
264 if (flags & 4) {
265 mask |= 0xff0000;
266 }
267 if (flags & 8) {
268 mask |= 0xff000000;
269 }
270 return (a & mask) | (b & ~mask);
271 }
272
273 /*
274 * CRC helpers.
275 * The upper bytes of val (above the number specified by 'bytes') must have
276 * been zeroed out by the caller.
277 */
HELPER(crc32)278 uint32_t HELPER(crc32)(uint32_t acc, uint32_t val, uint32_t bytes)
279 {
280 uint8_t buf[4];
281
282 stl_le_p(buf, val);
283
284 /* zlib crc32 converts the accumulator and output to one's complement. */
285 return crc32(acc ^ 0xffffffff, buf, bytes) ^ 0xffffffff;
286 }
287
HELPER(crc32c)288 uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
289 {
290 uint8_t buf[4];
291
292 stl_le_p(buf, val);
293
294 /* Linux crc32c converts the output to one's complement. */
295 return crc32c(acc, buf, bytes) ^ 0xffffffff;
296 }
297