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