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