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