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. */ 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. */ 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. */ 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. */ 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. */ 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 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 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 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 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. */ 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. */ 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 */ 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 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