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