1235eb015SJia Liu /* 2235eb015SJia Liu * MIPS ASE DSP Instruction emulation helpers for QEMU. 3235eb015SJia Liu * 4235eb015SJia Liu * Copyright (c) 2012 Jia Liu <proljc@gmail.com> 5235eb015SJia Liu * Dongxue Zhang <elat.era@gmail.com> 6235eb015SJia Liu * This library is free software; you can redistribute it and/or 7235eb015SJia Liu * modify it under the terms of the GNU Lesser General Public 8235eb015SJia Liu * License as published by the Free Software Foundation; either 9235eb015SJia Liu * version 2 of the License, or (at your option) any later version. 10235eb015SJia Liu * 11235eb015SJia Liu * This library is distributed in the hope that it will be useful, 12235eb015SJia Liu * but WITHOUT ANY WARRANTY; without even the implied warranty of 13235eb015SJia Liu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14235eb015SJia Liu * Lesser General Public License for more details. 15235eb015SJia Liu * 16235eb015SJia Liu * You should have received a copy of the GNU Lesser General Public 17235eb015SJia Liu * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18235eb015SJia Liu */ 19235eb015SJia Liu 20235eb015SJia Liu #include "cpu.h" 21235eb015SJia Liu #include "helper.h" 22235eb015SJia Liu 23235eb015SJia Liu /*** MIPS DSP internal functions begin ***/ 24235eb015SJia Liu #define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x) 25235eb015SJia Liu #define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d))) 26235eb015SJia Liu 27235eb015SJia Liu static inline void set_DSPControl_overflow_flag(uint32_t flag, int position, 28235eb015SJia Liu CPUMIPSState *env) 29235eb015SJia Liu { 30235eb015SJia Liu env->active_tc.DSPControl |= (target_ulong)flag << position; 31235eb015SJia Liu } 32235eb015SJia Liu 33235eb015SJia Liu static inline void set_DSPControl_carryflag(uint32_t flag, CPUMIPSState *env) 34235eb015SJia Liu { 35235eb015SJia Liu env->active_tc.DSPControl |= (target_ulong)flag << 13; 36235eb015SJia Liu } 37235eb015SJia Liu 38235eb015SJia Liu static inline uint32_t get_DSPControl_carryflag(CPUMIPSState *env) 39235eb015SJia Liu { 40235eb015SJia Liu return (env->active_tc.DSPControl >> 13) & 0x01; 41235eb015SJia Liu } 42235eb015SJia Liu 43235eb015SJia Liu static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env) 44235eb015SJia Liu { 45235eb015SJia Liu uint32_t filter; 46235eb015SJia Liu 47235eb015SJia Liu filter = ((0x01 << len) - 1) << 24; 48235eb015SJia Liu filter = ~filter; 49235eb015SJia Liu 50235eb015SJia Liu env->active_tc.DSPControl &= filter; 51235eb015SJia Liu env->active_tc.DSPControl |= (target_ulong)flag << 24; 52235eb015SJia Liu } 53235eb015SJia Liu 54235eb015SJia Liu static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env) 55235eb015SJia Liu { 56235eb015SJia Liu uint32_t filter; 57235eb015SJia Liu 58235eb015SJia Liu filter = (0x01 << len) - 1; 59235eb015SJia Liu 60235eb015SJia Liu return (env->active_tc.DSPControl >> 24) & filter; 61235eb015SJia Liu } 62235eb015SJia Liu 63235eb015SJia Liu static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env) 64235eb015SJia Liu { 65235eb015SJia Liu target_ulong dspc; 66235eb015SJia Liu 67235eb015SJia Liu dspc = env->active_tc.DSPControl; 68235eb015SJia Liu #ifndef TARGET_MIPS64 69235eb015SJia Liu dspc = dspc & 0xFFFFFFC0; 70235eb015SJia Liu dspc |= pos; 71235eb015SJia Liu #else 72235eb015SJia Liu dspc = dspc & 0xFFFFFF80; 73235eb015SJia Liu dspc |= pos; 74235eb015SJia Liu #endif 75235eb015SJia Liu env->active_tc.DSPControl = dspc; 76235eb015SJia Liu } 77235eb015SJia Liu 78235eb015SJia Liu static inline uint32_t get_DSPControl_pos(CPUMIPSState *env) 79235eb015SJia Liu { 80235eb015SJia Liu target_ulong dspc; 81235eb015SJia Liu uint32_t pos; 82235eb015SJia Liu 83235eb015SJia Liu dspc = env->active_tc.DSPControl; 84235eb015SJia Liu 85235eb015SJia Liu #ifndef TARGET_MIPS64 86235eb015SJia Liu pos = dspc & 0x3F; 87235eb015SJia Liu #else 88235eb015SJia Liu pos = dspc & 0x7F; 89235eb015SJia Liu #endif 90235eb015SJia Liu 91235eb015SJia Liu return pos; 92235eb015SJia Liu } 93235eb015SJia Liu 94235eb015SJia Liu static inline void set_DSPControl_efi(uint32_t flag, CPUMIPSState *env) 95235eb015SJia Liu { 96235eb015SJia Liu env->active_tc.DSPControl &= 0xFFFFBFFF; 97235eb015SJia Liu env->active_tc.DSPControl |= (target_ulong)flag << 14; 98235eb015SJia Liu } 99235eb015SJia Liu 100235eb015SJia Liu #define DO_MIPS_SAT_ABS(size) \ 101235eb015SJia Liu static inline int##size##_t mipsdsp_sat_abs##size(int##size##_t a, \ 102235eb015SJia Liu CPUMIPSState *env) \ 103235eb015SJia Liu { \ 104235eb015SJia Liu if (a == INT##size##_MIN) { \ 105235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); \ 106235eb015SJia Liu return INT##size##_MAX; \ 107235eb015SJia Liu } else { \ 108235eb015SJia Liu return MIPSDSP_ABS(a); \ 109235eb015SJia Liu } \ 110235eb015SJia Liu } 111235eb015SJia Liu DO_MIPS_SAT_ABS(8) 112235eb015SJia Liu DO_MIPS_SAT_ABS(16) 113235eb015SJia Liu DO_MIPS_SAT_ABS(32) 114235eb015SJia Liu #undef DO_MIPS_SAT_ABS 115235eb015SJia Liu 116235eb015SJia Liu /* get sum value */ 117235eb015SJia Liu static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env) 118235eb015SJia Liu { 119235eb015SJia Liu int16_t tempI; 120235eb015SJia Liu 121235eb015SJia Liu tempI = a + b; 122235eb015SJia Liu 123235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) { 124235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 125235eb015SJia Liu } 126235eb015SJia Liu 127235eb015SJia Liu return tempI; 128235eb015SJia Liu } 129235eb015SJia Liu 130235eb015SJia Liu static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b, 131235eb015SJia Liu CPUMIPSState *env) 132235eb015SJia Liu { 133235eb015SJia Liu int16_t tempS; 134235eb015SJia Liu 135235eb015SJia Liu tempS = a + b; 136235eb015SJia Liu 137235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) { 138235eb015SJia Liu if (a > 0) { 139235eb015SJia Liu tempS = 0x7FFF; 140235eb015SJia Liu } else { 141235eb015SJia Liu tempS = 0x8000; 142235eb015SJia Liu } 143235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 144235eb015SJia Liu } 145235eb015SJia Liu 146235eb015SJia Liu return tempS; 147235eb015SJia Liu } 148235eb015SJia Liu 149235eb015SJia Liu static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b, 150235eb015SJia Liu CPUMIPSState *env) 151235eb015SJia Liu { 152235eb015SJia Liu int32_t tempI; 153235eb015SJia Liu 154235eb015SJia Liu tempI = a + b; 155235eb015SJia Liu 156235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) { 157235eb015SJia Liu if (a > 0) { 158235eb015SJia Liu tempI = 0x7FFFFFFF; 159235eb015SJia Liu } else { 160235eb015SJia Liu tempI = 0x80000000; 161235eb015SJia Liu } 162235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 163235eb015SJia Liu } 164235eb015SJia Liu 165235eb015SJia Liu return tempI; 166235eb015SJia Liu } 167235eb015SJia Liu 168235eb015SJia Liu static inline uint8_t mipsdsp_add_u8(uint8_t a, uint8_t b, CPUMIPSState *env) 169235eb015SJia Liu { 170235eb015SJia Liu uint16_t temp; 171235eb015SJia Liu 172235eb015SJia Liu temp = (uint16_t)a + (uint16_t)b; 173235eb015SJia Liu 174235eb015SJia Liu if (temp & 0x0100) { 175235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 176235eb015SJia Liu } 177235eb015SJia Liu 178235eb015SJia Liu return temp & 0xFF; 179235eb015SJia Liu } 180235eb015SJia Liu 181235eb015SJia Liu static inline uint16_t mipsdsp_add_u16(uint16_t a, uint16_t b, 182235eb015SJia Liu CPUMIPSState *env) 183235eb015SJia Liu { 184235eb015SJia Liu uint32_t temp; 185235eb015SJia Liu 186235eb015SJia Liu temp = (uint32_t)a + (uint32_t)b; 187235eb015SJia Liu 188235eb015SJia Liu if (temp & 0x00010000) { 189235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 190235eb015SJia Liu } 191235eb015SJia Liu 192235eb015SJia Liu return temp & 0xFFFF; 193235eb015SJia Liu } 194235eb015SJia Liu 195235eb015SJia Liu static inline uint8_t mipsdsp_sat_add_u8(uint8_t a, uint8_t b, 196235eb015SJia Liu CPUMIPSState *env) 197235eb015SJia Liu { 198235eb015SJia Liu uint8_t result; 199235eb015SJia Liu uint16_t temp; 200235eb015SJia Liu 201235eb015SJia Liu temp = (uint16_t)a + (uint16_t)b; 202235eb015SJia Liu result = temp & 0xFF; 203235eb015SJia Liu 204235eb015SJia Liu if (0x0100 & temp) { 205235eb015SJia Liu result = 0xFF; 206235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 207235eb015SJia Liu } 208235eb015SJia Liu 209235eb015SJia Liu return result; 210235eb015SJia Liu } 211235eb015SJia Liu 212235eb015SJia Liu static inline uint16_t mipsdsp_sat_add_u16(uint16_t a, uint16_t b, 213235eb015SJia Liu CPUMIPSState *env) 214235eb015SJia Liu { 215235eb015SJia Liu uint16_t result; 216235eb015SJia Liu uint32_t temp; 217235eb015SJia Liu 218235eb015SJia Liu temp = (uint32_t)a + (uint32_t)b; 219235eb015SJia Liu result = temp & 0xFFFF; 220235eb015SJia Liu 221235eb015SJia Liu if (0x00010000 & temp) { 222235eb015SJia Liu result = 0xFFFF; 223235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 224235eb015SJia Liu } 225235eb015SJia Liu 226235eb015SJia Liu return result; 227235eb015SJia Liu } 228235eb015SJia Liu 229235eb015SJia Liu static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a, 230235eb015SJia Liu CPUMIPSState *env) 231235eb015SJia Liu { 232235eb015SJia Liu int64_t temp; 233235eb015SJia Liu int32_t temp32, temp31, result; 234235eb015SJia Liu int64_t temp_sum; 235235eb015SJia Liu 236235eb015SJia Liu #ifndef TARGET_MIPS64 237235eb015SJia Liu temp = ((uint64_t)env->active_tc.HI[acc] << 32) | 238235eb015SJia Liu (uint64_t)env->active_tc.LO[acc]; 239235eb015SJia Liu #else 240235eb015SJia Liu temp = (uint64_t)env->active_tc.LO[acc]; 241235eb015SJia Liu #endif 242235eb015SJia Liu 243235eb015SJia Liu temp_sum = (int64_t)a + temp; 244235eb015SJia Liu 245235eb015SJia Liu temp32 = (temp_sum >> 32) & 0x01; 246235eb015SJia Liu temp31 = (temp_sum >> 31) & 0x01; 247235eb015SJia Liu result = temp_sum & 0xFFFFFFFF; 248235eb015SJia Liu 249235eb015SJia Liu /* FIXME 250235eb015SJia Liu This sat function may wrong, because user manual wrote: 251235eb015SJia Liu temp127..0 ← temp + ( (signA) || a31..0 252235eb015SJia Liu if ( temp32 ≠ temp31 ) then 253235eb015SJia Liu if ( temp32 = 0 ) then 254235eb015SJia Liu temp31..0 ← 0x80000000 255235eb015SJia Liu else 256235eb015SJia Liu temp31..0 ← 0x7FFFFFFF 257235eb015SJia Liu endif 258235eb015SJia Liu DSPControlouflag:16+acc ← 1 259235eb015SJia Liu endif 260235eb015SJia Liu */ 261235eb015SJia Liu if (temp32 != temp31) { 262235eb015SJia Liu if (temp32 == 0) { 263235eb015SJia Liu result = 0x7FFFFFFF; 264235eb015SJia Liu } else { 265235eb015SJia Liu result = 0x80000000; 266235eb015SJia Liu } 267235eb015SJia Liu set_DSPControl_overflow_flag(1, 16 + acc, env); 268235eb015SJia Liu } 269235eb015SJia Liu 270235eb015SJia Liu return result; 271235eb015SJia Liu } 272235eb015SJia Liu 273235eb015SJia Liu /* a[0] is LO, a[1] is HI. */ 274235eb015SJia Liu static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret, 275235eb015SJia Liu int32_t ac, 276235eb015SJia Liu int64_t *a, 277235eb015SJia Liu CPUMIPSState *env) 278235eb015SJia Liu { 279235eb015SJia Liu bool temp64; 280235eb015SJia Liu 281235eb015SJia Liu ret[0] = env->active_tc.LO[ac] + a[0]; 282235eb015SJia Liu ret[1] = env->active_tc.HI[ac] + a[1]; 283235eb015SJia Liu 284235eb015SJia Liu if (((uint64_t)ret[0] < (uint64_t)env->active_tc.LO[ac]) && 285235eb015SJia Liu ((uint64_t)ret[0] < (uint64_t)a[0])) { 286235eb015SJia Liu ret[1] += 1; 287235eb015SJia Liu } 288235eb015SJia Liu temp64 = ret[1] & 1; 289235eb015SJia Liu if (temp64 != ((ret[0] >> 63) & 0x01)) { 290235eb015SJia Liu if (temp64) { 291235eb015SJia Liu ret[0] = (0x01ull << 63); 292235eb015SJia Liu ret[1] = ~0ull; 293235eb015SJia Liu } else { 294235eb015SJia Liu ret[0] = (0x01ull << 63) - 1; 295235eb015SJia Liu ret[1] = 0x00; 296235eb015SJia Liu } 297235eb015SJia Liu set_DSPControl_overflow_flag(1, 16 + ac, env); 298235eb015SJia Liu } 299235eb015SJia Liu } 300235eb015SJia Liu 301235eb015SJia Liu static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret, 302235eb015SJia Liu int32_t ac, 303235eb015SJia Liu int64_t *a, 304235eb015SJia Liu CPUMIPSState *env) 305235eb015SJia Liu { 306235eb015SJia Liu bool temp64; 307235eb015SJia Liu 308235eb015SJia Liu ret[0] = env->active_tc.LO[ac] - a[0]; 309235eb015SJia Liu ret[1] = env->active_tc.HI[ac] - a[1]; 310235eb015SJia Liu 311235eb015SJia Liu if ((uint64_t)ret[0] > (uint64_t)env->active_tc.LO[ac]) { 312235eb015SJia Liu ret[1] -= 1; 313235eb015SJia Liu } 314235eb015SJia Liu temp64 = ret[1] & 1; 315235eb015SJia Liu if (temp64 != ((ret[0] >> 63) & 0x01)) { 316235eb015SJia Liu if (temp64) { 317235eb015SJia Liu ret[0] = (0x01ull << 63); 318235eb015SJia Liu ret[1] = ~0ull; 319235eb015SJia Liu } else { 320235eb015SJia Liu ret[0] = (0x01ull << 63) - 1; 321235eb015SJia Liu ret[1] = 0x00; 322235eb015SJia Liu } 323235eb015SJia Liu set_DSPControl_overflow_flag(1, 16 + ac, env); 324235eb015SJia Liu } 325235eb015SJia Liu } 326235eb015SJia Liu 327235eb015SJia Liu static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b, 328235eb015SJia Liu CPUMIPSState *env) 329235eb015SJia Liu { 330235eb015SJia Liu int32_t temp; 331235eb015SJia Liu 332235eb015SJia Liu temp = (int32_t)a * (int32_t)b; 333235eb015SJia Liu 334235eb015SJia Liu if ((temp > (int)0x7FFF) || (temp < (int)0xFFFF8000)) { 335235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 336235eb015SJia Liu } 337235eb015SJia Liu temp &= 0x0000FFFF; 338235eb015SJia Liu 339235eb015SJia Liu return temp; 340235eb015SJia Liu } 341235eb015SJia Liu 342235eb015SJia Liu static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b) 343235eb015SJia Liu { 344235eb015SJia Liu return a * b; 345235eb015SJia Liu } 346235eb015SJia Liu 347235eb015SJia Liu static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b) 348235eb015SJia Liu { 349235eb015SJia Liu return a * b; 350235eb015SJia Liu } 351235eb015SJia Liu 352235eb015SJia Liu static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b, 353235eb015SJia Liu CPUMIPSState *env) 354235eb015SJia Liu { 355235eb015SJia Liu int32_t temp; 356235eb015SJia Liu 357235eb015SJia Liu temp = (int32_t)a * (int32_t)b; 358235eb015SJia Liu 359235eb015SJia Liu if (temp > (int)0x7FFF) { 360235eb015SJia Liu temp = 0x00007FFF; 361235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 362235eb015SJia Liu } else if (temp < (int)0xffff8000) { 363235eb015SJia Liu temp = 0xFFFF8000; 364235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 365235eb015SJia Liu } 366235eb015SJia Liu temp &= 0x0000FFFF; 367235eb015SJia Liu 368235eb015SJia Liu return temp; 369235eb015SJia Liu } 370235eb015SJia Liu 371235eb015SJia Liu static inline int32_t mipsdsp_mul_q15_q15_overflowflag21(uint16_t a, uint16_t b, 372235eb015SJia Liu CPUMIPSState *env) 373235eb015SJia Liu { 374235eb015SJia Liu int32_t temp; 375235eb015SJia Liu 376235eb015SJia Liu if ((a == 0x8000) && (b == 0x8000)) { 377235eb015SJia Liu temp = 0x7FFFFFFF; 378235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 379235eb015SJia Liu } else { 380235eb015SJia Liu temp = ((int32_t)(int16_t)a * (int32_t)(int16_t)b) << 1; 381235eb015SJia Liu } 382235eb015SJia Liu 383235eb015SJia Liu return temp; 384235eb015SJia Liu } 385235eb015SJia Liu 386235eb015SJia Liu /* right shift */ 387235eb015SJia Liu static inline uint8_t mipsdsp_rshift_u8(uint8_t a, target_ulong mov) 388235eb015SJia Liu { 389235eb015SJia Liu return a >> mov; 390235eb015SJia Liu } 391235eb015SJia Liu 392235eb015SJia Liu static inline uint16_t mipsdsp_rshift_u16(uint16_t a, target_ulong mov) 393235eb015SJia Liu { 394235eb015SJia Liu return a >> mov; 395235eb015SJia Liu } 396235eb015SJia Liu 397235eb015SJia Liu static inline int8_t mipsdsp_rashift8(int8_t a, target_ulong mov) 398235eb015SJia Liu { 399235eb015SJia Liu return a >> mov; 400235eb015SJia Liu } 401235eb015SJia Liu 402235eb015SJia Liu static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov) 403235eb015SJia Liu { 404235eb015SJia Liu return a >> mov; 405235eb015SJia Liu } 406235eb015SJia Liu 407235eb015SJia Liu static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov) 408235eb015SJia Liu { 409235eb015SJia Liu return a >> mov; 410235eb015SJia Liu } 411235eb015SJia Liu 412235eb015SJia Liu static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b) 413235eb015SJia Liu { 414235eb015SJia Liu int32_t temp; 415235eb015SJia Liu 416235eb015SJia Liu temp = (int32_t)a + (int32_t)b; 417235eb015SJia Liu 418235eb015SJia Liu return (temp >> 1) & 0xFFFF; 419235eb015SJia Liu } 420235eb015SJia Liu 421235eb015SJia Liu /* round right shift */ 422235eb015SJia Liu static inline int16_t mipsdsp_rrshift1_add_q16(int16_t a, int16_t b) 423235eb015SJia Liu { 424235eb015SJia Liu int32_t temp; 425235eb015SJia Liu 426235eb015SJia Liu temp = (int32_t)a + (int32_t)b; 427235eb015SJia Liu temp += 1; 428235eb015SJia Liu 429235eb015SJia Liu return (temp >> 1) & 0xFFFF; 430235eb015SJia Liu } 431235eb015SJia Liu 432235eb015SJia Liu static inline int32_t mipsdsp_rshift1_add_q32(int32_t a, int32_t b) 433235eb015SJia Liu { 434235eb015SJia Liu int64_t temp; 435235eb015SJia Liu 436235eb015SJia Liu temp = (int64_t)a + (int64_t)b; 437235eb015SJia Liu 438235eb015SJia Liu return (temp >> 1) & 0xFFFFFFFF; 439235eb015SJia Liu } 440235eb015SJia Liu 441235eb015SJia Liu static inline int32_t mipsdsp_rrshift1_add_q32(int32_t a, int32_t b) 442235eb015SJia Liu { 443235eb015SJia Liu int64_t temp; 444235eb015SJia Liu 445235eb015SJia Liu temp = (int64_t)a + (int64_t)b; 446235eb015SJia Liu temp += 1; 447235eb015SJia Liu 448235eb015SJia Liu return (temp >> 1) & 0xFFFFFFFF; 449235eb015SJia Liu } 450235eb015SJia Liu 451235eb015SJia Liu static inline uint8_t mipsdsp_rshift1_add_u8(uint8_t a, uint8_t b) 452235eb015SJia Liu { 453235eb015SJia Liu uint16_t temp; 454235eb015SJia Liu 455235eb015SJia Liu temp = (uint16_t)a + (uint16_t)b; 456235eb015SJia Liu 457235eb015SJia Liu return (temp >> 1) & 0x00FF; 458235eb015SJia Liu } 459235eb015SJia Liu 460235eb015SJia Liu static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b) 461235eb015SJia Liu { 462235eb015SJia Liu uint16_t temp; 463235eb015SJia Liu 464235eb015SJia Liu temp = (uint16_t)a + (uint16_t)b + 1; 465235eb015SJia Liu 466235eb015SJia Liu return (temp >> 1) & 0x00FF; 467235eb015SJia Liu } 468235eb015SJia Liu 469235eb015SJia Liu static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b) 470235eb015SJia Liu { 471235eb015SJia Liu uint16_t temp; 472235eb015SJia Liu 473235eb015SJia Liu temp = (uint16_t)a - (uint16_t)b; 474235eb015SJia Liu 475235eb015SJia Liu return (temp >> 1) & 0x00FF; 476235eb015SJia Liu } 477235eb015SJia Liu 478235eb015SJia Liu static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b) 479235eb015SJia Liu { 480235eb015SJia Liu uint16_t temp; 481235eb015SJia Liu 482235eb015SJia Liu temp = (uint16_t)a - (uint16_t)b + 1; 483235eb015SJia Liu 484235eb015SJia Liu return (temp >> 1) & 0x00FF; 485235eb015SJia Liu } 486235eb015SJia Liu 487235eb015SJia Liu static inline int64_t mipsdsp_rashift_short_acc(int32_t ac, 488235eb015SJia Liu int32_t shift, 489235eb015SJia Liu CPUMIPSState *env) 490235eb015SJia Liu { 491235eb015SJia Liu int32_t sign, temp31; 492235eb015SJia Liu int64_t temp, acc; 493235eb015SJia Liu 494235eb015SJia Liu sign = (env->active_tc.HI[ac] >> 31) & 0x01; 495235eb015SJia Liu acc = ((int64_t)env->active_tc.HI[ac] << 32) | 496235eb015SJia Liu ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); 497235eb015SJia Liu if (shift == 0) { 498235eb015SJia Liu temp = acc; 499235eb015SJia Liu } else { 500235eb015SJia Liu if (sign == 0) { 501235eb015SJia Liu temp = (((int64_t)0x01 << (32 - shift + 1)) - 1) & (acc >> shift); 502235eb015SJia Liu } else { 503235eb015SJia Liu temp = ((((int64_t)0x01 << (shift + 1)) - 1) << (32 - shift)) | 504235eb015SJia Liu (acc >> shift); 505235eb015SJia Liu } 506235eb015SJia Liu } 507235eb015SJia Liu 508235eb015SJia Liu temp31 = (temp >> 31) & 0x01; 509235eb015SJia Liu if (sign != temp31) { 510235eb015SJia Liu set_DSPControl_overflow_flag(1, 23, env); 511235eb015SJia Liu } 512235eb015SJia Liu 513235eb015SJia Liu return temp; 514235eb015SJia Liu } 515235eb015SJia Liu 516235eb015SJia Liu /* 128 bits long. p[0] is LO, p[1] is HI. */ 517235eb015SJia Liu static inline void mipsdsp_rndrashift_short_acc(int64_t *p, 518235eb015SJia Liu int32_t ac, 519235eb015SJia Liu int32_t shift, 520235eb015SJia Liu CPUMIPSState *env) 521235eb015SJia Liu { 522235eb015SJia Liu int64_t acc; 523235eb015SJia Liu 524235eb015SJia Liu acc = ((int64_t)env->active_tc.HI[ac] << 32) | 525235eb015SJia Liu ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); 526235eb015SJia Liu if (shift == 0) { 527235eb015SJia Liu p[0] = acc << 1; 528235eb015SJia Liu p[1] = (acc >> 63) & 0x01; 529235eb015SJia Liu } else { 530235eb015SJia Liu p[0] = acc >> (shift - 1); 531235eb015SJia Liu p[1] = 0; 532235eb015SJia Liu } 533235eb015SJia Liu } 534235eb015SJia Liu 535235eb015SJia Liu /* 128 bits long. p[0] is LO, p[1] is HI */ 536235eb015SJia Liu static inline void mipsdsp_rashift_acc(uint64_t *p, 537235eb015SJia Liu uint32_t ac, 538235eb015SJia Liu uint32_t shift, 539235eb015SJia Liu CPUMIPSState *env) 540235eb015SJia Liu { 541235eb015SJia Liu uint64_t tempB, tempA; 542235eb015SJia Liu 543235eb015SJia Liu tempB = env->active_tc.HI[ac]; 544235eb015SJia Liu tempA = env->active_tc.LO[ac]; 545235eb015SJia Liu shift = shift & 0x1F; 546235eb015SJia Liu 547235eb015SJia Liu if (shift == 0) { 548235eb015SJia Liu p[1] = tempB; 549235eb015SJia Liu p[0] = tempA; 550235eb015SJia Liu } else { 551235eb015SJia Liu p[0] = (tempB << (64 - shift)) | (tempA >> shift); 552235eb015SJia Liu p[1] = (int64_t)tempB >> shift; 553235eb015SJia Liu } 554235eb015SJia Liu } 555235eb015SJia Liu 556235eb015SJia Liu /* 128 bits long. p[0] is LO, p[1] is HI , p[2] is sign of HI.*/ 557235eb015SJia Liu static inline void mipsdsp_rndrashift_acc(uint64_t *p, 558235eb015SJia Liu uint32_t ac, 559235eb015SJia Liu uint32_t shift, 560235eb015SJia Liu CPUMIPSState *env) 561235eb015SJia Liu { 562235eb015SJia Liu int64_t tempB, tempA; 563235eb015SJia Liu 564235eb015SJia Liu tempB = env->active_tc.HI[ac]; 565235eb015SJia Liu tempA = env->active_tc.LO[ac]; 566235eb015SJia Liu shift = shift & 0x3F; 567235eb015SJia Liu 568235eb015SJia Liu if (shift == 0) { 569235eb015SJia Liu p[2] = tempB >> 63; 570235eb015SJia Liu p[1] = (tempB << 1) | (tempA >> 63); 571235eb015SJia Liu p[0] = tempA << 1; 572235eb015SJia Liu } else { 573235eb015SJia Liu p[0] = (tempB << (65 - shift)) | (tempA >> (shift - 1)); 574235eb015SJia Liu p[1] = (int64_t)tempB >> (shift - 1); 575235eb015SJia Liu if (tempB >= 0) { 576235eb015SJia Liu p[2] = 0x0; 577235eb015SJia Liu } else { 578235eb015SJia Liu p[2] = ~0ull; 579235eb015SJia Liu } 580235eb015SJia Liu } 581235eb015SJia Liu } 582235eb015SJia Liu 583235eb015SJia Liu static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b, 584235eb015SJia Liu CPUMIPSState *env) 585235eb015SJia Liu { 586235eb015SJia Liu int32_t temp; 587235eb015SJia Liu 588235eb015SJia Liu if ((a == 0x8000) && (b == 0x8000)) { 589235eb015SJia Liu temp = 0x7FFFFFFF; 590235eb015SJia Liu set_DSPControl_overflow_flag(1, 16 + ac, env); 591235eb015SJia Liu } else { 592235eb015SJia Liu temp = ((uint32_t)a * (uint32_t)b) << 1; 593235eb015SJia Liu } 594235eb015SJia Liu 595235eb015SJia Liu return temp; 596235eb015SJia Liu } 597235eb015SJia Liu 598235eb015SJia Liu static inline int64_t mipsdsp_mul_q31_q31(int32_t ac, uint32_t a, uint32_t b, 599235eb015SJia Liu CPUMIPSState *env) 600235eb015SJia Liu { 601235eb015SJia Liu uint64_t temp; 602235eb015SJia Liu 603235eb015SJia Liu if ((a == 0x80000000) && (b == 0x80000000)) { 604235eb015SJia Liu temp = (0x01ull << 63) - 1; 605235eb015SJia Liu set_DSPControl_overflow_flag(1, 16 + ac, env); 606235eb015SJia Liu } else { 607235eb015SJia Liu temp = ((uint64_t)a * (uint64_t)b) << 1; 608235eb015SJia Liu } 609235eb015SJia Liu 610235eb015SJia Liu return temp; 611235eb015SJia Liu } 612235eb015SJia Liu 613235eb015SJia Liu static inline uint16_t mipsdsp_mul_u8_u8(uint8_t a, uint8_t b) 614235eb015SJia Liu { 615235eb015SJia Liu return (uint16_t)a * (uint16_t)b; 616235eb015SJia Liu } 617235eb015SJia Liu 618235eb015SJia Liu static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b, 619235eb015SJia Liu CPUMIPSState *env) 620235eb015SJia Liu { 621235eb015SJia Liu uint32_t tempI; 622235eb015SJia Liu 623235eb015SJia Liu tempI = (uint32_t)a * (uint32_t)b; 624235eb015SJia Liu if (tempI > 0x0000FFFF) { 625235eb015SJia Liu tempI = 0x0000FFFF; 626235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 627235eb015SJia Liu } 628235eb015SJia Liu 629235eb015SJia Liu return tempI & 0x0000FFFF; 630235eb015SJia Liu } 631235eb015SJia Liu 632235eb015SJia Liu static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b) 633235eb015SJia Liu { 634235eb015SJia Liu return (uint64_t)a * (uint64_t)b; 635235eb015SJia Liu } 636235eb015SJia Liu 637235eb015SJia Liu static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b, 638235eb015SJia Liu CPUMIPSState *env) 639235eb015SJia Liu { 640235eb015SJia Liu uint32_t temp; 641235eb015SJia Liu 642235eb015SJia Liu if ((a == 0x8000) && (b == 0x8000)) { 643235eb015SJia Liu temp = 0x7FFF0000; 644235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 645235eb015SJia Liu } else { 646235eb015SJia Liu temp = (a * b) << 1; 647235eb015SJia Liu temp = temp + 0x00008000; 648235eb015SJia Liu } 649235eb015SJia Liu 650235eb015SJia Liu return (temp & 0xFFFF0000) >> 16; 651235eb015SJia Liu } 652235eb015SJia Liu 653235eb015SJia Liu static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b, 654235eb015SJia Liu CPUMIPSState *env) 655235eb015SJia Liu { 656235eb015SJia Liu int32_t temp; 657235eb015SJia Liu 658235eb015SJia Liu if ((a == 0x8000) && (b == 0x8000)) { 659235eb015SJia Liu temp = 0x7FFF0000; 660235eb015SJia Liu set_DSPControl_overflow_flag(1, 21, env); 661235eb015SJia Liu } else { 662235eb015SJia Liu temp = ((uint32_t)a * (uint32_t)b); 663235eb015SJia Liu temp = temp << 1; 664235eb015SJia Liu } 665235eb015SJia Liu 666235eb015SJia Liu return (temp >> 16) & 0x0000FFFF; 667235eb015SJia Liu } 668235eb015SJia Liu 669235eb015SJia Liu static inline uint16_t mipsdsp_trunc16_sat16_round(int32_t a, 670235eb015SJia Liu CPUMIPSState *env) 671235eb015SJia Liu { 672235eb015SJia Liu int64_t temp; 673235eb015SJia Liu 674235eb015SJia Liu temp = (int32_t)a + 0x00008000; 675235eb015SJia Liu 676235eb015SJia Liu if (a > (int)0x7fff8000) { 677235eb015SJia Liu temp = 0x7FFFFFFF; 678235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 679235eb015SJia Liu } 680235eb015SJia Liu 681235eb015SJia Liu return (temp >> 16) & 0xFFFF; 682235eb015SJia Liu } 683235eb015SJia Liu 684235eb015SJia Liu static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a, 685235eb015SJia Liu CPUMIPSState *env) 686235eb015SJia Liu { 687235eb015SJia Liu uint16_t mag; 688235eb015SJia Liu uint32_t sign; 689235eb015SJia Liu 690235eb015SJia Liu sign = (a >> 15) & 0x01; 691235eb015SJia Liu mag = a & 0x7FFF; 692235eb015SJia Liu 693235eb015SJia Liu if (sign == 0) { 694235eb015SJia Liu if (mag > 0x7F80) { 695235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 696235eb015SJia Liu return 0xFF; 697235eb015SJia Liu } else { 698235eb015SJia Liu return (mag >> 7) & 0xFFFF; 699235eb015SJia Liu } 700235eb015SJia Liu } else { 701235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 702235eb015SJia Liu return 0x00; 703235eb015SJia Liu } 704235eb015SJia Liu } 705235eb015SJia Liu 706235eb015SJia Liu static inline uint8_t mipsdsp_lshift8(uint8_t a, uint8_t s, CPUMIPSState *env) 707235eb015SJia Liu { 708235eb015SJia Liu uint8_t sign; 709235eb015SJia Liu uint8_t discard; 710235eb015SJia Liu 711235eb015SJia Liu if (s == 0) { 712235eb015SJia Liu return a; 713235eb015SJia Liu } else { 714235eb015SJia Liu sign = (a >> 7) & 0x01; 715235eb015SJia Liu if (sign != 0) { 716235eb015SJia Liu discard = (((0x01 << (8 - s)) - 1) << s) | 717235eb015SJia Liu ((a >> (6 - (s - 1))) & ((0x01 << s) - 1)); 718235eb015SJia Liu } else { 719235eb015SJia Liu discard = a >> (6 - (s - 1)); 720235eb015SJia Liu } 721235eb015SJia Liu 722235eb015SJia Liu if (discard != 0x00) { 723235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 724235eb015SJia Liu } 725235eb015SJia Liu return a << s; 726235eb015SJia Liu } 727235eb015SJia Liu } 728235eb015SJia Liu 729235eb015SJia Liu static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s, 730235eb015SJia Liu CPUMIPSState *env) 731235eb015SJia Liu { 732235eb015SJia Liu uint8_t sign; 733235eb015SJia Liu uint16_t discard; 734235eb015SJia Liu 735235eb015SJia Liu if (s == 0) { 736235eb015SJia Liu return a; 737235eb015SJia Liu } else { 738235eb015SJia Liu sign = (a >> 15) & 0x01; 739235eb015SJia Liu if (sign != 0) { 740235eb015SJia Liu discard = (((0x01 << (16 - s)) - 1) << s) | 741235eb015SJia Liu ((a >> (14 - (s - 1))) & ((0x01 << s) - 1)); 742235eb015SJia Liu } else { 743235eb015SJia Liu discard = a >> (14 - (s - 1)); 744235eb015SJia Liu } 745235eb015SJia Liu 746235eb015SJia Liu if ((discard != 0x0000) && (discard != 0xFFFF)) { 747235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 748235eb015SJia Liu } 749235eb015SJia Liu return a << s; 750235eb015SJia Liu } 751235eb015SJia Liu } 752235eb015SJia Liu 753235eb015SJia Liu 754235eb015SJia Liu static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s, 755235eb015SJia Liu CPUMIPSState *env) 756235eb015SJia Liu { 757235eb015SJia Liu uint32_t discard; 758235eb015SJia Liu 759235eb015SJia Liu if (s == 0) { 760235eb015SJia Liu return a; 761235eb015SJia Liu } else { 762235eb015SJia Liu discard = (int32_t)a >> (31 - (s - 1)); 763235eb015SJia Liu 764235eb015SJia Liu if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) { 765235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 766235eb015SJia Liu } 767235eb015SJia Liu return a << s; 768235eb015SJia Liu } 769235eb015SJia Liu } 770235eb015SJia Liu 771235eb015SJia Liu static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s, 772235eb015SJia Liu CPUMIPSState *env) 773235eb015SJia Liu { 774235eb015SJia Liu uint8_t sign; 775235eb015SJia Liu uint16_t discard; 776235eb015SJia Liu 777235eb015SJia Liu if (s == 0) { 778235eb015SJia Liu return a; 779235eb015SJia Liu } else { 780235eb015SJia Liu sign = (a >> 15) & 0x01; 781235eb015SJia Liu if (sign != 0) { 782235eb015SJia Liu discard = (((0x01 << (16 - s)) - 1) << s) | 783235eb015SJia Liu ((a >> (14 - (s - 1))) & ((0x01 << s) - 1)); 784235eb015SJia Liu } else { 785235eb015SJia Liu discard = a >> (14 - (s - 1)); 786235eb015SJia Liu } 787235eb015SJia Liu 788235eb015SJia Liu if ((discard != 0x0000) && (discard != 0xFFFF)) { 789235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 790235eb015SJia Liu return (sign == 0) ? 0x7FFF : 0x8000; 791235eb015SJia Liu } else { 792235eb015SJia Liu return a << s; 793235eb015SJia Liu } 794235eb015SJia Liu } 795235eb015SJia Liu } 796235eb015SJia Liu 797235eb015SJia Liu static inline uint32_t mipsdsp_sat32_lshift(uint32_t a, uint8_t s, 798235eb015SJia Liu CPUMIPSState *env) 799235eb015SJia Liu { 800235eb015SJia Liu uint8_t sign; 801235eb015SJia Liu uint32_t discard; 802235eb015SJia Liu 803235eb015SJia Liu if (s == 0) { 804235eb015SJia Liu return a; 805235eb015SJia Liu } else { 806235eb015SJia Liu sign = (a >> 31) & 0x01; 807235eb015SJia Liu if (sign != 0) { 808235eb015SJia Liu discard = (((0x01 << (32 - s)) - 1) << s) | 809235eb015SJia Liu ((a >> (30 - (s - 1))) & ((0x01 << s) - 1)); 810235eb015SJia Liu } else { 811235eb015SJia Liu discard = a >> (30 - (s - 1)); 812235eb015SJia Liu } 813235eb015SJia Liu 814235eb015SJia Liu if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) { 815235eb015SJia Liu set_DSPControl_overflow_flag(1, 22, env); 816235eb015SJia Liu return (sign == 0) ? 0x7FFFFFFF : 0x80000000; 817235eb015SJia Liu } else { 818235eb015SJia Liu return a << s; 819235eb015SJia Liu } 820235eb015SJia Liu } 821235eb015SJia Liu } 822235eb015SJia Liu 823235eb015SJia Liu static inline uint8_t mipsdsp_rnd8_rashift(uint8_t a, uint8_t s) 824235eb015SJia Liu { 825235eb015SJia Liu uint32_t temp; 826235eb015SJia Liu 827235eb015SJia Liu if (s == 0) { 828235eb015SJia Liu temp = (uint32_t)a << 1; 829235eb015SJia Liu } else { 830235eb015SJia Liu temp = (int32_t)(int8_t)a >> (s - 1); 831235eb015SJia Liu } 832235eb015SJia Liu 833235eb015SJia Liu return (temp + 1) >> 1; 834235eb015SJia Liu } 835235eb015SJia Liu 836235eb015SJia Liu static inline uint16_t mipsdsp_rnd16_rashift(uint16_t a, uint8_t s) 837235eb015SJia Liu { 838235eb015SJia Liu uint32_t temp; 839235eb015SJia Liu 840235eb015SJia Liu if (s == 0) { 841235eb015SJia Liu temp = (uint32_t)a << 1; 842235eb015SJia Liu } else { 843235eb015SJia Liu temp = (int32_t)(int16_t)a >> (s - 1); 844235eb015SJia Liu } 845235eb015SJia Liu 846235eb015SJia Liu return (temp + 1) >> 1; 847235eb015SJia Liu } 848235eb015SJia Liu 849235eb015SJia Liu static inline uint32_t mipsdsp_rnd32_rashift(uint32_t a, uint8_t s) 850235eb015SJia Liu { 851235eb015SJia Liu int64_t temp; 852235eb015SJia Liu 853235eb015SJia Liu if (s == 0) { 854235eb015SJia Liu temp = (uint64_t)a << 1; 855235eb015SJia Liu } else { 856235eb015SJia Liu temp = (int64_t)(int32_t)a >> (s - 1); 857235eb015SJia Liu } 858235eb015SJia Liu temp += 1; 859235eb015SJia Liu 860235eb015SJia Liu return (temp >> 1) & 0xFFFFFFFFull; 861235eb015SJia Liu } 862235eb015SJia Liu 863235eb015SJia Liu static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env) 864235eb015SJia Liu { 865235eb015SJia Liu int16_t temp; 866235eb015SJia Liu 867235eb015SJia Liu temp = a - b; 868235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) { 869235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 870235eb015SJia Liu } 871235eb015SJia Liu 872235eb015SJia Liu return temp; 873235eb015SJia Liu } 874235eb015SJia Liu 875235eb015SJia Liu static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b, 876235eb015SJia Liu CPUMIPSState *env) 877235eb015SJia Liu { 878235eb015SJia Liu int16_t temp; 879235eb015SJia Liu 880235eb015SJia Liu temp = a - b; 881235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) { 882235eb015SJia Liu if (a > 0) { 883235eb015SJia Liu temp = 0x7FFF; 884235eb015SJia Liu } else { 885235eb015SJia Liu temp = 0x8000; 886235eb015SJia Liu } 887235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 888235eb015SJia Liu } 889235eb015SJia Liu 890235eb015SJia Liu return temp; 891235eb015SJia Liu } 892235eb015SJia Liu 893235eb015SJia Liu static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b, 894235eb015SJia Liu CPUMIPSState *env) 895235eb015SJia Liu { 896235eb015SJia Liu int32_t temp; 897235eb015SJia Liu 898235eb015SJia Liu temp = a - b; 899235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) { 900235eb015SJia Liu if (a > 0) { 901235eb015SJia Liu temp = 0x7FFFFFFF; 902235eb015SJia Liu } else { 903235eb015SJia Liu temp = 0x80000000; 904235eb015SJia Liu } 905235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 906235eb015SJia Liu } 907235eb015SJia Liu 908235eb015SJia Liu return temp & 0xFFFFFFFFull; 909235eb015SJia Liu } 910235eb015SJia Liu 911235eb015SJia Liu static inline uint16_t mipsdsp_rshift1_sub_q16(int16_t a, int16_t b) 912235eb015SJia Liu { 913235eb015SJia Liu int32_t temp; 914235eb015SJia Liu 915235eb015SJia Liu temp = (int32_t)a - (int32_t)b; 916235eb015SJia Liu 917235eb015SJia Liu return (temp >> 1) & 0x0000FFFF; 918235eb015SJia Liu } 919235eb015SJia Liu 920235eb015SJia Liu static inline uint16_t mipsdsp_rrshift1_sub_q16(int16_t a, int16_t b) 921235eb015SJia Liu { 922235eb015SJia Liu int32_t temp; 923235eb015SJia Liu 924235eb015SJia Liu temp = (int32_t)a - (int32_t)b; 925235eb015SJia Liu temp += 1; 926235eb015SJia Liu 927235eb015SJia Liu return (temp >> 1) & 0x0000FFFF; 928235eb015SJia Liu } 929235eb015SJia Liu 930235eb015SJia Liu static inline uint32_t mipsdsp_rshift1_sub_q32(int32_t a, int32_t b) 931235eb015SJia Liu { 932235eb015SJia Liu int64_t temp; 933235eb015SJia Liu 934235eb015SJia Liu temp = (int64_t)a - (int64_t)b; 935235eb015SJia Liu 936235eb015SJia Liu return (temp >> 1) & 0xFFFFFFFFull; 937235eb015SJia Liu } 938235eb015SJia Liu 939235eb015SJia Liu static inline uint32_t mipsdsp_rrshift1_sub_q32(int32_t a, int32_t b) 940235eb015SJia Liu { 941235eb015SJia Liu int64_t temp; 942235eb015SJia Liu 943235eb015SJia Liu temp = (int64_t)a - (int64_t)b; 944235eb015SJia Liu temp += 1; 945235eb015SJia Liu 946235eb015SJia Liu return (temp >> 1) & 0xFFFFFFFFull; 947235eb015SJia Liu } 948235eb015SJia Liu 949235eb015SJia Liu static inline uint16_t mipsdsp_sub_u16_u16(uint16_t a, uint16_t b, 950235eb015SJia Liu CPUMIPSState *env) 951235eb015SJia Liu { 952235eb015SJia Liu uint8_t temp16; 953235eb015SJia Liu uint32_t temp; 954235eb015SJia Liu 955235eb015SJia Liu temp = (uint32_t)a - (uint32_t)b; 956235eb015SJia Liu temp16 = (temp >> 16) & 0x01; 957235eb015SJia Liu if (temp16 == 1) { 958235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 959235eb015SJia Liu } 960235eb015SJia Liu return temp & 0x0000FFFF; 961235eb015SJia Liu } 962235eb015SJia Liu 963235eb015SJia Liu static inline uint16_t mipsdsp_satu16_sub_u16_u16(uint16_t a, uint16_t b, 964235eb015SJia Liu CPUMIPSState *env) 965235eb015SJia Liu { 966235eb015SJia Liu uint8_t temp16; 967235eb015SJia Liu uint32_t temp; 968235eb015SJia Liu 969235eb015SJia Liu temp = (uint32_t)a - (uint32_t)b; 970235eb015SJia Liu temp16 = (temp >> 16) & 0x01; 971235eb015SJia Liu 972235eb015SJia Liu if (temp16 == 1) { 973235eb015SJia Liu temp = 0x0000; 974235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 975235eb015SJia Liu } 976235eb015SJia Liu 977235eb015SJia Liu return temp & 0x0000FFFF; 978235eb015SJia Liu } 979235eb015SJia Liu 980235eb015SJia Liu static inline uint8_t mipsdsp_sub_u8(uint8_t a, uint8_t b, CPUMIPSState *env) 981235eb015SJia Liu { 982235eb015SJia Liu uint8_t temp8; 983235eb015SJia Liu uint16_t temp; 984235eb015SJia Liu 985235eb015SJia Liu temp = (uint16_t)a - (uint16_t)b; 986235eb015SJia Liu temp8 = (temp >> 8) & 0x01; 987235eb015SJia Liu if (temp8 == 1) { 988235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 989235eb015SJia Liu } 990235eb015SJia Liu 991235eb015SJia Liu return temp & 0x00FF; 992235eb015SJia Liu } 993235eb015SJia Liu 994235eb015SJia Liu static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env) 995235eb015SJia Liu { 996235eb015SJia Liu uint8_t temp8; 997235eb015SJia Liu uint16_t temp; 998235eb015SJia Liu 999235eb015SJia Liu temp = (uint16_t)a - (uint16_t)b; 1000235eb015SJia Liu temp8 = (temp >> 8) & 0x01; 1001235eb015SJia Liu if (temp8 == 1) { 1002235eb015SJia Liu temp = 0x00; 1003235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 1004235eb015SJia Liu } 1005235eb015SJia Liu 1006235eb015SJia Liu return temp & 0x00FF; 1007235eb015SJia Liu } 1008235eb015SJia Liu 1009235eb015SJia Liu static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env) 1010235eb015SJia Liu { 1011235eb015SJia Liu int32_t temp; 1012235eb015SJia Liu 1013235eb015SJia Liu temp = a - b; 1014235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) { 1015235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 1016235eb015SJia Liu } 1017235eb015SJia Liu 1018235eb015SJia Liu return temp; 1019235eb015SJia Liu } 1020235eb015SJia Liu 1021235eb015SJia Liu static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env) 1022235eb015SJia Liu { 1023235eb015SJia Liu int32_t temp; 1024235eb015SJia Liu 1025235eb015SJia Liu temp = a + b; 1026235eb015SJia Liu 1027235eb015SJia Liu if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) { 1028235eb015SJia Liu set_DSPControl_overflow_flag(1, 20, env); 1029235eb015SJia Liu } 1030235eb015SJia Liu 1031235eb015SJia Liu return temp; 1032235eb015SJia Liu } 1033235eb015SJia Liu 1034235eb015SJia Liu static inline int32_t mipsdsp_cmp_eq(int32_t a, int32_t b) 1035235eb015SJia Liu { 1036235eb015SJia Liu return a == b; 1037235eb015SJia Liu } 1038235eb015SJia Liu 1039235eb015SJia Liu static inline int32_t mipsdsp_cmp_le(int32_t a, int32_t b) 1040235eb015SJia Liu { 1041235eb015SJia Liu return a <= b; 1042235eb015SJia Liu } 1043235eb015SJia Liu 1044235eb015SJia Liu static inline int32_t mipsdsp_cmp_lt(int32_t a, int32_t b) 1045235eb015SJia Liu { 1046235eb015SJia Liu return a < b; 1047235eb015SJia Liu } 1048235eb015SJia Liu 1049235eb015SJia Liu static inline int32_t mipsdsp_cmpu_eq(uint32_t a, uint32_t b) 1050235eb015SJia Liu { 1051235eb015SJia Liu return a == b; 1052235eb015SJia Liu } 1053235eb015SJia Liu 1054235eb015SJia Liu static inline int32_t mipsdsp_cmpu_le(uint32_t a, uint32_t b) 1055235eb015SJia Liu { 1056235eb015SJia Liu return a <= b; 1057235eb015SJia Liu } 1058235eb015SJia Liu 1059235eb015SJia Liu static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b) 1060235eb015SJia Liu { 1061235eb015SJia Liu return a < b; 1062235eb015SJia Liu } 1063235eb015SJia Liu /*** MIPS DSP internal functions end ***/ 1064