xref: /qemu/target/arm/tcg/arith_helper.c (revision 5cb8b0988bdf1e1b22f66925604fe9a44a568993)
1538b764dSPeter Maydell /*
2538b764dSPeter Maydell  * ARM generic helpers for various arithmetical operations.
3538b764dSPeter Maydell  *
4538b764dSPeter Maydell  * This code is licensed under the GNU GPL v2 or later.
5538b764dSPeter Maydell  *
6538b764dSPeter Maydell  * SPDX-License-Identifier: GPL-2.0-or-later
7538b764dSPeter Maydell  */
8538b764dSPeter Maydell #include "qemu/osdep.h"
9538b764dSPeter Maydell #include "qemu/crc32c.h"
10538b764dSPeter Maydell #include <zlib.h> /* for crc32 */
11538b764dSPeter Maydell 
12*c0b623cbSPierrick Bouvier #define HELPER_H "tcg/helper.h"
13*c0b623cbSPierrick Bouvier #include "exec/helper-proto.h.inc"
14*c0b623cbSPierrick Bouvier 
15538b764dSPeter Maydell /*
16538b764dSPeter Maydell  * Note that signed overflow is undefined in C.  The following routines are
17538b764dSPeter Maydell  * careful to use unsigned types where modulo arithmetic is required.
18538b764dSPeter Maydell  * Failure to do so _will_ break on newer gcc.
19538b764dSPeter Maydell  */
20538b764dSPeter Maydell 
21538b764dSPeter Maydell /* Signed saturating arithmetic.  */
22538b764dSPeter Maydell 
23538b764dSPeter Maydell /* Perform 16-bit signed saturating addition.  */
add16_sat(uint16_t a,uint16_t b)24538b764dSPeter Maydell static inline uint16_t add16_sat(uint16_t a, uint16_t b)
25538b764dSPeter Maydell {
26538b764dSPeter Maydell     uint16_t res;
27538b764dSPeter Maydell 
28538b764dSPeter Maydell     res = a + b;
29538b764dSPeter Maydell     if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
30538b764dSPeter Maydell         if (a & 0x8000) {
31538b764dSPeter Maydell             res = 0x8000;
32538b764dSPeter Maydell         } else {
33538b764dSPeter Maydell             res = 0x7fff;
34538b764dSPeter Maydell         }
35538b764dSPeter Maydell     }
36538b764dSPeter Maydell     return res;
37538b764dSPeter Maydell }
38538b764dSPeter Maydell 
39538b764dSPeter Maydell /* Perform 8-bit signed saturating addition.  */
add8_sat(uint8_t a,uint8_t b)40538b764dSPeter Maydell static inline uint8_t add8_sat(uint8_t a, uint8_t b)
41538b764dSPeter Maydell {
42538b764dSPeter Maydell     uint8_t res;
43538b764dSPeter Maydell 
44538b764dSPeter Maydell     res = a + b;
45538b764dSPeter Maydell     if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
46538b764dSPeter Maydell         if (a & 0x80) {
47538b764dSPeter Maydell             res = 0x80;
48538b764dSPeter Maydell         } else {
49538b764dSPeter Maydell             res = 0x7f;
50538b764dSPeter Maydell         }
51538b764dSPeter Maydell     }
52538b764dSPeter Maydell     return res;
53538b764dSPeter Maydell }
54538b764dSPeter Maydell 
55538b764dSPeter Maydell /* Perform 16-bit signed saturating subtraction.  */
sub16_sat(uint16_t a,uint16_t b)56538b764dSPeter Maydell static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
57538b764dSPeter Maydell {
58538b764dSPeter Maydell     uint16_t res;
59538b764dSPeter Maydell 
60538b764dSPeter Maydell     res = a - b;
61538b764dSPeter Maydell     if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
62538b764dSPeter Maydell         if (a & 0x8000) {
63538b764dSPeter Maydell             res = 0x8000;
64538b764dSPeter Maydell         } else {
65538b764dSPeter Maydell             res = 0x7fff;
66538b764dSPeter Maydell         }
67538b764dSPeter Maydell     }
68538b764dSPeter Maydell     return res;
69538b764dSPeter Maydell }
70538b764dSPeter Maydell 
71538b764dSPeter Maydell /* Perform 8-bit signed saturating subtraction.  */
sub8_sat(uint8_t a,uint8_t b)72538b764dSPeter Maydell static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
73538b764dSPeter Maydell {
74538b764dSPeter Maydell     uint8_t res;
75538b764dSPeter Maydell 
76538b764dSPeter Maydell     res = a - b;
77538b764dSPeter Maydell     if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
78538b764dSPeter Maydell         if (a & 0x80) {
79538b764dSPeter Maydell             res = 0x80;
80538b764dSPeter Maydell         } else {
81538b764dSPeter Maydell             res = 0x7f;
82538b764dSPeter Maydell         }
83538b764dSPeter Maydell     }
84538b764dSPeter Maydell     return res;
85538b764dSPeter Maydell }
86538b764dSPeter Maydell 
87538b764dSPeter Maydell #define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
88538b764dSPeter Maydell #define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
89538b764dSPeter Maydell #define ADD8(a, b, n)  RESULT(add8_sat(a, b), n, 8);
90538b764dSPeter Maydell #define SUB8(a, b, n)  RESULT(sub8_sat(a, b), n, 8);
91538b764dSPeter Maydell #define PFX q
92538b764dSPeter Maydell 
93538b764dSPeter Maydell #include "op_addsub.c.inc"
94538b764dSPeter Maydell 
95538b764dSPeter Maydell /* Unsigned saturating arithmetic.  */
add16_usat(uint16_t a,uint16_t b)96538b764dSPeter Maydell static inline uint16_t add16_usat(uint16_t a, uint16_t b)
97538b764dSPeter Maydell {
98538b764dSPeter Maydell     uint16_t res;
99538b764dSPeter Maydell     res = a + b;
100538b764dSPeter Maydell     if (res < a) {
101538b764dSPeter Maydell         res = 0xffff;
102538b764dSPeter Maydell     }
103538b764dSPeter Maydell     return res;
104538b764dSPeter Maydell }
105538b764dSPeter Maydell 
sub16_usat(uint16_t a,uint16_t b)106538b764dSPeter Maydell static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
107538b764dSPeter Maydell {
108538b764dSPeter Maydell     if (a > b) {
109538b764dSPeter Maydell         return a - b;
110538b764dSPeter Maydell     } else {
111538b764dSPeter Maydell         return 0;
112538b764dSPeter Maydell     }
113538b764dSPeter Maydell }
114538b764dSPeter Maydell 
add8_usat(uint8_t a,uint8_t b)115538b764dSPeter Maydell static inline uint8_t add8_usat(uint8_t a, uint8_t b)
116538b764dSPeter Maydell {
117538b764dSPeter Maydell     uint8_t res;
118538b764dSPeter Maydell     res = a + b;
119538b764dSPeter Maydell     if (res < a) {
120538b764dSPeter Maydell         res = 0xff;
121538b764dSPeter Maydell     }
122538b764dSPeter Maydell     return res;
123538b764dSPeter Maydell }
124538b764dSPeter Maydell 
sub8_usat(uint8_t a,uint8_t b)125538b764dSPeter Maydell static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
126538b764dSPeter Maydell {
127538b764dSPeter Maydell     if (a > b) {
128538b764dSPeter Maydell         return a - b;
129538b764dSPeter Maydell     } else {
130538b764dSPeter Maydell         return 0;
131538b764dSPeter Maydell     }
132538b764dSPeter Maydell }
133538b764dSPeter Maydell 
134538b764dSPeter Maydell #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
135538b764dSPeter Maydell #define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
136538b764dSPeter Maydell #define ADD8(a, b, n)  RESULT(add8_usat(a, b), n, 8);
137538b764dSPeter Maydell #define SUB8(a, b, n)  RESULT(sub8_usat(a, b), n, 8);
138538b764dSPeter Maydell #define PFX uq
139538b764dSPeter Maydell 
140538b764dSPeter Maydell #include "op_addsub.c.inc"
141538b764dSPeter Maydell 
142538b764dSPeter Maydell /* Signed modulo arithmetic.  */
143538b764dSPeter Maydell #define SARITH16(a, b, n, op) do { \
144538b764dSPeter Maydell     int32_t sum; \
145538b764dSPeter Maydell     sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
146538b764dSPeter Maydell     RESULT(sum, n, 16); \
147538b764dSPeter Maydell     if (sum >= 0) \
148538b764dSPeter Maydell         ge |= 3 << (n * 2); \
149538b764dSPeter Maydell     } while (0)
150538b764dSPeter Maydell 
151538b764dSPeter Maydell #define SARITH8(a, b, n, op) do { \
152538b764dSPeter Maydell     int32_t sum; \
153538b764dSPeter Maydell     sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
154538b764dSPeter Maydell     RESULT(sum, n, 8); \
155538b764dSPeter Maydell     if (sum >= 0) \
156538b764dSPeter Maydell         ge |= 1 << n; \
157538b764dSPeter Maydell     } while (0)
158538b764dSPeter Maydell 
159538b764dSPeter Maydell 
160538b764dSPeter Maydell #define ADD16(a, b, n) SARITH16(a, b, n, +)
161538b764dSPeter Maydell #define SUB16(a, b, n) SARITH16(a, b, n, -)
162538b764dSPeter Maydell #define ADD8(a, b, n)  SARITH8(a, b, n, +)
163538b764dSPeter Maydell #define SUB8(a, b, n)  SARITH8(a, b, n, -)
164538b764dSPeter Maydell #define PFX s
165538b764dSPeter Maydell #define ARITH_GE
166538b764dSPeter Maydell 
167538b764dSPeter Maydell #include "op_addsub.c.inc"
168538b764dSPeter Maydell 
169538b764dSPeter Maydell /* Unsigned modulo arithmetic.  */
170538b764dSPeter Maydell #define ADD16(a, b, n) do { \
171538b764dSPeter Maydell     uint32_t sum; \
172538b764dSPeter Maydell     sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
173538b764dSPeter Maydell     RESULT(sum, n, 16); \
174538b764dSPeter Maydell     if ((sum >> 16) == 1) \
175538b764dSPeter Maydell         ge |= 3 << (n * 2); \
176538b764dSPeter Maydell     } while (0)
177538b764dSPeter Maydell 
178538b764dSPeter Maydell #define ADD8(a, b, n) do { \
179538b764dSPeter Maydell     uint32_t sum; \
180538b764dSPeter Maydell     sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
181538b764dSPeter Maydell     RESULT(sum, n, 8); \
182538b764dSPeter Maydell     if ((sum >> 8) == 1) \
183538b764dSPeter Maydell         ge |= 1 << n; \
184538b764dSPeter Maydell     } while (0)
185538b764dSPeter Maydell 
186538b764dSPeter Maydell #define SUB16(a, b, n) do { \
187538b764dSPeter Maydell     uint32_t sum; \
188538b764dSPeter Maydell     sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
189538b764dSPeter Maydell     RESULT(sum, n, 16); \
190538b764dSPeter Maydell     if ((sum >> 16) == 0) \
191538b764dSPeter Maydell         ge |= 3 << (n * 2); \
192538b764dSPeter Maydell     } while (0)
193538b764dSPeter Maydell 
194538b764dSPeter Maydell #define SUB8(a, b, n) do { \
195538b764dSPeter Maydell     uint32_t sum; \
196538b764dSPeter Maydell     sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
197538b764dSPeter Maydell     RESULT(sum, n, 8); \
198538b764dSPeter Maydell     if ((sum >> 8) == 0) \
199538b764dSPeter Maydell         ge |= 1 << n; \
200538b764dSPeter Maydell     } while (0)
201538b764dSPeter Maydell 
202538b764dSPeter Maydell #define PFX u
203538b764dSPeter Maydell #define ARITH_GE
204538b764dSPeter Maydell 
205538b764dSPeter Maydell #include "op_addsub.c.inc"
206538b764dSPeter Maydell 
207538b764dSPeter Maydell /* Halved signed arithmetic.  */
208538b764dSPeter Maydell #define ADD16(a, b, n) \
209538b764dSPeter Maydell   RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
210538b764dSPeter Maydell #define SUB16(a, b, n) \
211538b764dSPeter Maydell   RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
212538b764dSPeter Maydell #define ADD8(a, b, n) \
213538b764dSPeter Maydell   RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
214538b764dSPeter Maydell #define SUB8(a, b, n) \
215538b764dSPeter Maydell   RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
216538b764dSPeter Maydell #define PFX sh
217538b764dSPeter Maydell 
218538b764dSPeter Maydell #include "op_addsub.c.inc"
219538b764dSPeter Maydell 
220538b764dSPeter Maydell /* Halved unsigned arithmetic.  */
221538b764dSPeter Maydell #define ADD16(a, b, n) \
222538b764dSPeter Maydell   RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
223538b764dSPeter Maydell #define SUB16(a, b, n) \
224538b764dSPeter Maydell   RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
225538b764dSPeter Maydell #define ADD8(a, b, n) \
226538b764dSPeter Maydell   RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
227538b764dSPeter Maydell #define SUB8(a, b, n) \
228538b764dSPeter Maydell   RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
229538b764dSPeter Maydell #define PFX uh
230538b764dSPeter Maydell 
231538b764dSPeter Maydell #include "op_addsub.c.inc"
232538b764dSPeter Maydell 
do_usad(uint8_t a,uint8_t b)233538b764dSPeter Maydell static inline uint8_t do_usad(uint8_t a, uint8_t b)
234538b764dSPeter Maydell {
235538b764dSPeter Maydell     if (a > b) {
236538b764dSPeter Maydell         return a - b;
237538b764dSPeter Maydell     } else {
238538b764dSPeter Maydell         return b - a;
239538b764dSPeter Maydell     }
240538b764dSPeter Maydell }
241538b764dSPeter Maydell 
242538b764dSPeter Maydell /* Unsigned sum of absolute byte differences.  */
HELPER(usad8)243538b764dSPeter Maydell uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
244538b764dSPeter Maydell {
245538b764dSPeter Maydell     uint32_t sum;
246538b764dSPeter Maydell     sum = do_usad(a, b);
247538b764dSPeter Maydell     sum += do_usad(a >> 8, b >> 8);
248538b764dSPeter Maydell     sum += do_usad(a >> 16, b >> 16);
249538b764dSPeter Maydell     sum += do_usad(a >> 24, b >> 24);
250538b764dSPeter Maydell     return sum;
251538b764dSPeter Maydell }
252538b764dSPeter Maydell 
253538b764dSPeter Maydell /* For ARMv6 SEL instruction.  */
HELPER(sel_flags)254538b764dSPeter Maydell uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
255538b764dSPeter Maydell {
256538b764dSPeter Maydell     uint32_t mask;
257538b764dSPeter Maydell 
258538b764dSPeter Maydell     mask = 0;
259538b764dSPeter Maydell     if (flags & 1) {
260538b764dSPeter Maydell         mask |= 0xff;
261538b764dSPeter Maydell     }
262538b764dSPeter Maydell     if (flags & 2) {
263538b764dSPeter Maydell         mask |= 0xff00;
264538b764dSPeter Maydell     }
265538b764dSPeter Maydell     if (flags & 4) {
266538b764dSPeter Maydell         mask |= 0xff0000;
267538b764dSPeter Maydell     }
268538b764dSPeter Maydell     if (flags & 8) {
269538b764dSPeter Maydell         mask |= 0xff000000;
270538b764dSPeter Maydell     }
271538b764dSPeter Maydell     return (a & mask) | (b & ~mask);
272538b764dSPeter Maydell }
273538b764dSPeter Maydell 
274538b764dSPeter Maydell /*
275538b764dSPeter Maydell  * CRC helpers.
276538b764dSPeter Maydell  * The upper bytes of val (above the number specified by 'bytes') must have
277538b764dSPeter Maydell  * been zeroed out by the caller.
278538b764dSPeter Maydell  */
HELPER(crc32)279538b764dSPeter Maydell uint32_t HELPER(crc32)(uint32_t acc, uint32_t val, uint32_t bytes)
280538b764dSPeter Maydell {
281538b764dSPeter Maydell     uint8_t buf[4];
282538b764dSPeter Maydell 
283538b764dSPeter Maydell     stl_le_p(buf, val);
284538b764dSPeter Maydell 
285538b764dSPeter Maydell     /* zlib crc32 converts the accumulator and output to one's complement.  */
286538b764dSPeter Maydell     return crc32(acc ^ 0xffffffff, buf, bytes) ^ 0xffffffff;
287538b764dSPeter Maydell }
288538b764dSPeter Maydell 
HELPER(crc32c)289538b764dSPeter Maydell uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
290538b764dSPeter Maydell {
291538b764dSPeter Maydell     uint8_t buf[4];
292538b764dSPeter Maydell 
293538b764dSPeter Maydell     stl_le_p(buf, val);
294538b764dSPeter Maydell 
295538b764dSPeter Maydell     /* Linux crc32c converts the output to one's complement.  */
296538b764dSPeter Maydell     return crc32c(acc, buf, bytes) ^ 0xffffffff;
297538b764dSPeter Maydell }
298