qemu/target-mips/dsp_helper.c
<<
>>
Prefs
   1/*
   2 * MIPS ASE DSP Instruction emulation helpers for QEMU.
   3 *
   4 * Copyright (c) 2012  Jia Liu <proljc@gmail.com>
   5 *                     Dongxue Zhang <elta.era@gmail.com>
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "cpu.h"
  21#include "helper.h"
  22#include "qemu/bitops.h"
  23
  24/* As the byte ordering doesn't matter, i.e. all columns are treated
  25   identically, these unions can be used directly.  */
  26typedef union {
  27    uint8_t  ub[4];
  28    int8_t   sb[4];
  29    uint16_t uh[2];
  30    int16_t  sh[2];
  31    uint32_t uw[1];
  32    int32_t  sw[1];
  33} DSP32Value;
  34
  35typedef union {
  36    uint8_t  ub[8];
  37    int8_t   sb[8];
  38    uint16_t uh[4];
  39    int16_t  sh[4];
  40    uint32_t uw[2];
  41    int32_t  sw[2];
  42    uint64_t ul[1];
  43    int64_t  sl[1];
  44} DSP64Value;
  45
  46/*** MIPS DSP internal functions begin ***/
  47#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
  48#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~(a ^ b) & (a ^ c) & d)
  49#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) ((a ^ b) & (a ^ c) & d)
  50
  51static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
  52                                                CPUMIPSState *env)
  53{
  54    env->active_tc.DSPControl |= (target_ulong)flag << position;
  55}
  56
  57static inline void set_DSPControl_carryflag(bool flag, CPUMIPSState *env)
  58{
  59    env->active_tc.DSPControl &= ~(1 << 13);
  60    env->active_tc.DSPControl |= flag << 13;
  61}
  62
  63static inline uint32_t get_DSPControl_carryflag(CPUMIPSState *env)
  64{
  65    return (env->active_tc.DSPControl >> 13) & 0x01;
  66}
  67
  68static inline void set_DSPControl_24(uint32_t flag, int len, CPUMIPSState *env)
  69{
  70  uint32_t filter;
  71
  72  filter = ((0x01 << len) - 1) << 24;
  73  filter = ~filter;
  74
  75  env->active_tc.DSPControl &= filter;
  76  env->active_tc.DSPControl |= (target_ulong)flag << 24;
  77}
  78
  79static inline uint32_t get_DSPControl_24(int len, CPUMIPSState *env)
  80{
  81  uint32_t filter;
  82
  83  filter = (0x01 << len) - 1;
  84
  85  return (env->active_tc.DSPControl >> 24) & filter;
  86}
  87
  88static inline void set_DSPControl_pos(uint32_t pos, CPUMIPSState *env)
  89{
  90    target_ulong dspc;
  91
  92    dspc = env->active_tc.DSPControl;
  93#ifndef TARGET_MIPS64
  94    dspc = dspc & 0xFFFFFFC0;
  95    dspc |= (pos & 0x3F);
  96#else
  97    dspc = dspc & 0xFFFFFF80;
  98    dspc |= (pos & 0x7F);
  99#endif
 100    env->active_tc.DSPControl = dspc;
 101}
 102
 103static inline uint32_t get_DSPControl_pos(CPUMIPSState *env)
 104{
 105    target_ulong dspc;
 106    uint32_t pos;
 107
 108    dspc = env->active_tc.DSPControl;
 109
 110#ifndef TARGET_MIPS64
 111    pos = dspc & 0x3F;
 112#else
 113    pos = dspc & 0x7F;
 114#endif
 115
 116    return pos;
 117}
 118
 119static inline void set_DSPControl_efi(uint32_t flag, CPUMIPSState *env)
 120{
 121    env->active_tc.DSPControl &= 0xFFFFBFFF;
 122    env->active_tc.DSPControl |= (target_ulong)flag << 14;
 123}
 124
 125#define DO_MIPS_SAT_ABS(size)                                          \
 126static inline int##size##_t mipsdsp_sat_abs##size(int##size##_t a,         \
 127                                                  CPUMIPSState *env)   \
 128{                                                                      \
 129    if (a == INT##size##_MIN) {                                        \
 130        set_DSPControl_overflow_flag(1, 20, env);                      \
 131        return INT##size##_MAX;                                        \
 132    } else {                                                           \
 133        return MIPSDSP_ABS(a);                                         \
 134    }                                                                  \
 135}
 136DO_MIPS_SAT_ABS(8)
 137DO_MIPS_SAT_ABS(16)
 138DO_MIPS_SAT_ABS(32)
 139#undef DO_MIPS_SAT_ABS
 140
 141/* get sum value */
 142static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env)
 143{
 144    int16_t tempI;
 145
 146    tempI = a + b;
 147
 148    if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x8000)) {
 149        set_DSPControl_overflow_flag(1, 20, env);
 150    }
 151
 152    return tempI;
 153}
 154
 155static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b,
 156                                          CPUMIPSState *env)
 157{
 158    int16_t tempS;
 159
 160    tempS = a + b;
 161
 162    if (MIPSDSP_OVERFLOW_ADD(a, b, tempS, 0x8000)) {
 163        if (a > 0) {
 164            tempS = 0x7FFF;
 165        } else {
 166            tempS = 0x8000;
 167        }
 168        set_DSPControl_overflow_flag(1, 20, env);
 169    }
 170
 171    return tempS;
 172}
 173
 174static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b,
 175                                          CPUMIPSState *env)
 176{
 177    int32_t tempI;
 178
 179    tempI = a + b;
 180
 181    if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x80000000)) {
 182        if (a > 0) {
 183            tempI = 0x7FFFFFFF;
 184        } else {
 185            tempI = 0x80000000;
 186        }
 187        set_DSPControl_overflow_flag(1, 20, env);
 188    }
 189
 190    return tempI;
 191}
 192
 193static inline uint8_t mipsdsp_add_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
 194{
 195    uint16_t temp;
 196
 197    temp = (uint16_t)a + (uint16_t)b;
 198
 199    if (temp & 0x0100) {
 200        set_DSPControl_overflow_flag(1, 20, env);
 201    }
 202
 203    return temp & 0xFF;
 204}
 205
 206static inline uint16_t mipsdsp_add_u16(uint16_t a, uint16_t b,
 207                                       CPUMIPSState *env)
 208{
 209    uint32_t temp;
 210
 211    temp = (uint32_t)a + (uint32_t)b;
 212
 213    if (temp & 0x00010000) {
 214        set_DSPControl_overflow_flag(1, 20, env);
 215    }
 216
 217    return temp & 0xFFFF;
 218}
 219
 220static inline uint8_t mipsdsp_sat_add_u8(uint8_t a, uint8_t b,
 221                                         CPUMIPSState *env)
 222{
 223    uint8_t  result;
 224    uint16_t temp;
 225
 226    temp = (uint16_t)a + (uint16_t)b;
 227    result = temp & 0xFF;
 228
 229    if (0x0100 & temp) {
 230        result = 0xFF;
 231        set_DSPControl_overflow_flag(1, 20, env);
 232    }
 233
 234    return result;
 235}
 236
 237static inline uint16_t mipsdsp_sat_add_u16(uint16_t a, uint16_t b,
 238                                           CPUMIPSState *env)
 239{
 240    uint16_t result;
 241    uint32_t temp;
 242
 243    temp = (uint32_t)a + (uint32_t)b;
 244    result = temp & 0xFFFF;
 245
 246    if (0x00010000 & temp) {
 247        result = 0xFFFF;
 248        set_DSPControl_overflow_flag(1, 20, env);
 249    }
 250
 251    return result;
 252}
 253
 254static inline int32_t mipsdsp_sat32_acc_q31(int32_t acc, int32_t a,
 255                                            CPUMIPSState *env)
 256{
 257    int64_t temp;
 258    int32_t temp32, temp31, result;
 259    int64_t temp_sum;
 260
 261#ifndef TARGET_MIPS64
 262    temp = ((uint64_t)env->active_tc.HI[acc] << 32) |
 263           (uint64_t)env->active_tc.LO[acc];
 264#else
 265    temp = (uint64_t)env->active_tc.LO[acc];
 266#endif
 267
 268    temp_sum = (int64_t)a + temp;
 269
 270    temp32 = (temp_sum >> 32) & 0x01;
 271    temp31 = (temp_sum >> 31) & 0x01;
 272    result = temp_sum & 0xFFFFFFFF;
 273
 274    if (temp32 != temp31) {
 275        if (temp32 == 0) {
 276            result = 0x7FFFFFFF;
 277        } else {
 278            result = 0x80000000;
 279        }
 280        set_DSPControl_overflow_flag(1, 16 + acc, env);
 281    }
 282
 283    return result;
 284}
 285
 286/* a[0] is LO, a[1] is HI. */
 287static inline void mipsdsp_sat64_acc_add_q63(int64_t *ret,
 288                                             int32_t ac,
 289                                             int64_t *a,
 290                                             CPUMIPSState *env)
 291{
 292    bool temp64;
 293
 294    ret[0] = env->active_tc.LO[ac] + a[0];
 295    ret[1] = env->active_tc.HI[ac] + a[1];
 296
 297    if (((uint64_t)ret[0] < (uint64_t)env->active_tc.LO[ac]) &&
 298        ((uint64_t)ret[0] < (uint64_t)a[0])) {
 299        ret[1] += 1;
 300    }
 301    temp64 = ret[1] & 1;
 302    if (temp64 != ((ret[0] >> 63) & 0x01)) {
 303        if (temp64) {
 304            ret[0] = (0x01ull << 63);
 305            ret[1] = ~0ull;
 306        } else {
 307            ret[0] = (0x01ull << 63) - 1;
 308            ret[1] = 0x00;
 309        }
 310        set_DSPControl_overflow_flag(1, 16 + ac, env);
 311    }
 312}
 313
 314static inline void mipsdsp_sat64_acc_sub_q63(int64_t *ret,
 315                                             int32_t ac,
 316                                             int64_t *a,
 317                                             CPUMIPSState *env)
 318{
 319    bool temp64;
 320
 321    ret[0] = env->active_tc.LO[ac] - a[0];
 322    ret[1] = env->active_tc.HI[ac] - a[1];
 323
 324    if ((uint64_t)ret[0] > (uint64_t)env->active_tc.LO[ac]) {
 325        ret[1] -= 1;
 326    }
 327    temp64 = ret[1] & 1;
 328    if (temp64 != ((ret[0] >> 63) & 0x01)) {
 329        if (temp64) {
 330            ret[0] = (0x01ull << 63);
 331            ret[1] = ~0ull;
 332        } else {
 333            ret[0] = (0x01ull << 63) - 1;
 334            ret[1] = 0x00;
 335        }
 336        set_DSPControl_overflow_flag(1, 16 + ac, env);
 337    }
 338}
 339
 340static inline int32_t mipsdsp_mul_i16_i16(int16_t a, int16_t b,
 341                                          CPUMIPSState *env)
 342{
 343    int32_t temp;
 344
 345    temp = (int32_t)a * (int32_t)b;
 346
 347    if ((temp > (int)0x7FFF) || (temp < (int)0xFFFF8000)) {
 348        set_DSPControl_overflow_flag(1, 21, env);
 349    }
 350    temp &= 0x0000FFFF;
 351
 352    return temp;
 353}
 354
 355static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b)
 356{
 357    return a * b;
 358}
 359
 360static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b)
 361{
 362    return a * b;
 363}
 364
 365static inline int32_t mipsdsp_sat16_mul_i16_i16(int16_t a, int16_t b,
 366                                                CPUMIPSState *env)
 367{
 368    int32_t temp;
 369
 370    temp = (int32_t)a * (int32_t)b;
 371
 372    if (temp > (int)0x7FFF) {
 373        temp = 0x00007FFF;
 374        set_DSPControl_overflow_flag(1, 21, env);
 375    } else if (temp < (int)0xffff8000) {
 376        temp = 0xFFFF8000;
 377        set_DSPControl_overflow_flag(1, 21, env);
 378    }
 379    temp &= 0x0000FFFF;
 380
 381    return temp;
 382}
 383
 384static inline int32_t mipsdsp_mul_q15_q15_overflowflag21(uint16_t a, uint16_t b,
 385                                                         CPUMIPSState *env)
 386{
 387    int32_t temp;
 388
 389    if ((a == 0x8000) && (b == 0x8000)) {
 390        temp = 0x7FFFFFFF;
 391        set_DSPControl_overflow_flag(1, 21, env);
 392    } else {
 393        temp = ((int32_t)(int16_t)a * (int32_t)(int16_t)b) << 1;
 394    }
 395
 396    return temp;
 397}
 398
 399/* right shift */
 400static inline uint8_t mipsdsp_rshift_u8(uint8_t a, target_ulong mov)
 401{
 402    return a >> mov;
 403}
 404
 405static inline uint16_t mipsdsp_rshift_u16(uint16_t a, target_ulong mov)
 406{
 407    return a >> mov;
 408}
 409
 410static inline int8_t mipsdsp_rashift8(int8_t a, target_ulong mov)
 411{
 412    return a >> mov;
 413}
 414
 415static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov)
 416{
 417    return a >> mov;
 418}
 419
 420static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov)
 421{
 422    return a >> mov;
 423}
 424
 425static inline int16_t mipsdsp_rshift1_add_q16(int16_t a, int16_t b)
 426{
 427    int32_t temp;
 428
 429    temp = (int32_t)a + (int32_t)b;
 430
 431    return (temp >> 1) & 0xFFFF;
 432}
 433
 434/* round right shift */
 435static inline int16_t mipsdsp_rrshift1_add_q16(int16_t a, int16_t b)
 436{
 437    int32_t temp;
 438
 439    temp = (int32_t)a + (int32_t)b;
 440    temp += 1;
 441
 442    return (temp >> 1) & 0xFFFF;
 443}
 444
 445static inline int32_t mipsdsp_rshift1_add_q32(int32_t a, int32_t b)
 446{
 447    int64_t temp;
 448
 449    temp = (int64_t)a + (int64_t)b;
 450
 451    return (temp >> 1) & 0xFFFFFFFF;
 452}
 453
 454static inline int32_t mipsdsp_rrshift1_add_q32(int32_t a, int32_t b)
 455{
 456    int64_t temp;
 457
 458    temp = (int64_t)a + (int64_t)b;
 459    temp += 1;
 460
 461    return (temp >> 1) & 0xFFFFFFFF;
 462}
 463
 464static inline uint8_t mipsdsp_rshift1_add_u8(uint8_t a, uint8_t b)
 465{
 466    uint16_t temp;
 467
 468    temp = (uint16_t)a + (uint16_t)b;
 469
 470    return (temp >> 1) & 0x00FF;
 471}
 472
 473static inline uint8_t mipsdsp_rrshift1_add_u8(uint8_t a, uint8_t b)
 474{
 475    uint16_t temp;
 476
 477    temp = (uint16_t)a + (uint16_t)b + 1;
 478
 479    return (temp >> 1) & 0x00FF;
 480}
 481
 482static inline uint8_t mipsdsp_rshift1_sub_u8(uint8_t a, uint8_t b)
 483{
 484    uint16_t temp;
 485
 486    temp = (uint16_t)a - (uint16_t)b;
 487
 488    return (temp >> 1) & 0x00FF;
 489}
 490
 491static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b)
 492{
 493    uint16_t temp;
 494
 495    temp = (uint16_t)a - (uint16_t)b + 1;
 496
 497    return (temp >> 1) & 0x00FF;
 498}
 499
 500/*  128 bits long. p[0] is LO, p[1] is HI. */
 501static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
 502                                                int32_t ac,
 503                                                int32_t shift,
 504                                                CPUMIPSState *env)
 505{
 506    int64_t acc;
 507
 508    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
 509          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
 510    p[0] = (shift == 0) ? (acc << 1) : (acc >> (shift - 1));
 511    p[1] = (acc >> 63) & 0x01;
 512}
 513
 514/* 128 bits long. p[0] is LO, p[1] is HI */
 515static inline void mipsdsp_rashift_acc(uint64_t *p,
 516                                       uint32_t ac,
 517                                       uint32_t shift,
 518                                       CPUMIPSState *env)
 519{
 520    uint64_t tempB, tempA;
 521
 522    tempB = env->active_tc.HI[ac];
 523    tempA = env->active_tc.LO[ac];
 524    shift = shift & 0x1F;
 525
 526    if (shift == 0) {
 527        p[1] = tempB;
 528        p[0] = tempA;
 529    } else {
 530        p[0] = (tempB << (64 - shift)) | (tempA >> shift);
 531        p[1] = (int64_t)tempB >> shift;
 532    }
 533}
 534
 535/* 128 bits long. p[0] is LO, p[1] is HI , p[2] is sign of HI.*/
 536static inline void mipsdsp_rndrashift_acc(uint64_t *p,
 537                                          uint32_t ac,
 538                                          uint32_t shift,
 539                                          CPUMIPSState *env)
 540{
 541    int64_t tempB, tempA;
 542
 543    tempB = env->active_tc.HI[ac];
 544    tempA = env->active_tc.LO[ac];
 545    shift = shift & 0x3F;
 546
 547    if (shift == 0) {
 548        p[2] = tempB >> 63;
 549        p[1] = (tempB << 1) | (tempA >> 63);
 550        p[0] = tempA << 1;
 551    } else {
 552        p[0] = (tempB << (65 - shift)) | (tempA >> (shift - 1));
 553        p[1] = (int64_t)tempB >> (shift - 1);
 554        if (tempB >= 0) {
 555            p[2] = 0x0;
 556        } else {
 557            p[2] = ~0ull;
 558        }
 559    }
 560}
 561
 562static inline int32_t mipsdsp_mul_q15_q15(int32_t ac, uint16_t a, uint16_t b,
 563                                          CPUMIPSState *env)
 564{
 565    int32_t temp;
 566
 567    if ((a == 0x8000) && (b == 0x8000)) {
 568        temp = 0x7FFFFFFF;
 569        set_DSPControl_overflow_flag(1, 16 + ac, env);
 570    } else {
 571        temp = ((int16_t)a * (int16_t)b) << 1;
 572    }
 573
 574    return temp;
 575}
 576
 577static inline int64_t mipsdsp_mul_q31_q31(int32_t ac, uint32_t a, uint32_t b,
 578                                          CPUMIPSState *env)
 579{
 580    uint64_t temp;
 581
 582    if ((a == 0x80000000) && (b == 0x80000000)) {
 583        temp = (0x01ull << 63) - 1;
 584        set_DSPControl_overflow_flag(1, 16 + ac, env);
 585    } else {
 586        temp = ((uint64_t)a * (uint64_t)b) << 1;
 587    }
 588
 589    return temp;
 590}
 591
 592static inline uint16_t mipsdsp_mul_u8_u8(uint8_t a, uint8_t b)
 593{
 594    return (uint16_t)a * (uint16_t)b;
 595}
 596
 597static inline uint16_t mipsdsp_mul_u8_u16(uint8_t a, uint16_t b,
 598                                          CPUMIPSState *env)
 599{
 600    uint32_t tempI;
 601
 602    tempI = (uint32_t)a * (uint32_t)b;
 603    if (tempI > 0x0000FFFF) {
 604        tempI = 0x0000FFFF;
 605        set_DSPControl_overflow_flag(1, 21, env);
 606    }
 607
 608    return tempI & 0x0000FFFF;
 609}
 610
 611static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b)
 612{
 613    return (uint64_t)a * (uint64_t)b;
 614}
 615
 616static inline int16_t mipsdsp_rndq15_mul_q15_q15(uint16_t a, uint16_t b,
 617                                                 CPUMIPSState *env)
 618{
 619    uint32_t temp;
 620
 621    if ((a == 0x8000) && (b == 0x8000)) {
 622        temp = 0x7FFF0000;
 623        set_DSPControl_overflow_flag(1, 21, env);
 624    } else {
 625        temp = (a * b) << 1;
 626        temp = temp + 0x00008000;
 627    }
 628
 629    return (temp & 0xFFFF0000) >> 16;
 630}
 631
 632static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b,
 633                                                CPUMIPSState *env)
 634{
 635    int32_t temp;
 636
 637    if ((a == 0x8000) && (b == 0x8000)) {
 638        temp = 0x7FFF0000;
 639        set_DSPControl_overflow_flag(1, 21, env);
 640    } else {
 641        temp = (int16_t)a * (int16_t)b;
 642        temp = temp << 1;
 643    }
 644
 645    return (temp >> 16) & 0x0000FFFF;
 646}
 647
 648static inline uint16_t mipsdsp_trunc16_sat16_round(int32_t a,
 649                                                   CPUMIPSState *env)
 650{
 651    int64_t temp;
 652
 653    temp = (int32_t)a + 0x00008000;
 654
 655    if (a > (int)0x7fff8000) {
 656        temp = 0x7FFFFFFF;
 657        set_DSPControl_overflow_flag(1, 22, env);
 658    }
 659
 660    return (temp >> 16) & 0xFFFF;
 661}
 662
 663static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a,
 664                                                    CPUMIPSState *env)
 665{
 666    uint16_t mag;
 667    uint32_t sign;
 668
 669    sign = (a >> 15) & 0x01;
 670    mag = a & 0x7FFF;
 671
 672    if (sign == 0) {
 673        if (mag > 0x7F80) {
 674            set_DSPControl_overflow_flag(1, 22, env);
 675            return 0xFF;
 676        } else {
 677            return (mag >> 7) & 0xFFFF;
 678        }
 679    } else {
 680        set_DSPControl_overflow_flag(1, 22, env);
 681        return 0x00;
 682    }
 683}
 684
 685static inline uint8_t mipsdsp_lshift8(uint8_t a, uint8_t s, CPUMIPSState *env)
 686{
 687    uint8_t discard;
 688
 689    if (s != 0) {
 690        discard = a >> (8 - s);
 691
 692        if (discard != 0x00) {
 693            set_DSPControl_overflow_flag(1, 22, env);
 694        }
 695    }
 696    return a << s;
 697}
 698
 699static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s,
 700                                        CPUMIPSState *env)
 701{
 702    uint16_t discard;
 703
 704    if (s != 0) {
 705        discard = (int16_t)a >> (15 - s);
 706
 707        if ((discard != 0x0000) && (discard != 0xFFFF)) {
 708            set_DSPControl_overflow_flag(1, 22, env);
 709        }
 710    }
 711    return a << s;
 712}
 713
 714
 715static inline uint32_t mipsdsp_lshift32(uint32_t a, uint8_t s,
 716                                        CPUMIPSState *env)
 717{
 718    uint32_t discard;
 719
 720    if (s == 0) {
 721        return a;
 722    } else {
 723        discard = (int32_t)a >> (31 - (s - 1));
 724
 725        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
 726            set_DSPControl_overflow_flag(1, 22, env);
 727        }
 728        return a << s;
 729    }
 730}
 731
 732static inline uint16_t mipsdsp_sat16_lshift(uint16_t a, uint8_t s,
 733                                            CPUMIPSState *env)
 734{
 735    uint8_t  sign;
 736    uint16_t discard;
 737
 738    if (s == 0) {
 739        return a;
 740    } else {
 741        sign = (a >> 15) & 0x01;
 742        if (sign != 0) {
 743            discard = (((0x01 << (16 - s)) - 1) << s) |
 744                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
 745        } else {
 746            discard = a >> (14 - (s - 1));
 747        }
 748
 749        if ((discard != 0x0000) && (discard != 0xFFFF)) {
 750            set_DSPControl_overflow_flag(1, 22, env);
 751            return (sign == 0) ? 0x7FFF : 0x8000;
 752        } else {
 753            return a << s;
 754        }
 755    }
 756}
 757
 758static inline uint32_t mipsdsp_sat32_lshift(uint32_t a, uint8_t s,
 759                                            CPUMIPSState *env)
 760{
 761    uint8_t  sign;
 762    uint32_t discard;
 763
 764    if (s == 0) {
 765        return a;
 766    } else {
 767        sign = (a >> 31) & 0x01;
 768        if (sign != 0) {
 769            discard = (((0x01 << (32 - s)) - 1) << s) |
 770                      ((a >> (30 - (s - 1))) & ((0x01 << s) - 1));
 771        } else {
 772            discard = a >> (30 - (s - 1));
 773        }
 774
 775        if ((discard != 0x00000000) && (discard != 0xFFFFFFFF)) {
 776            set_DSPControl_overflow_flag(1, 22, env);
 777            return (sign == 0) ? 0x7FFFFFFF : 0x80000000;
 778        } else {
 779            return a << s;
 780        }
 781    }
 782}
 783
 784static inline uint8_t mipsdsp_rnd8_rashift(uint8_t a, uint8_t s)
 785{
 786    uint32_t temp;
 787
 788    if (s == 0) {
 789        temp = (uint32_t)a << 1;
 790    } else {
 791        temp = (int32_t)(int8_t)a >> (s - 1);
 792    }
 793
 794    return (temp + 1) >> 1;
 795}
 796
 797static inline uint16_t mipsdsp_rnd16_rashift(uint16_t a, uint8_t s)
 798{
 799    uint32_t temp;
 800
 801    if (s == 0) {
 802        temp = (uint32_t)a << 1;
 803    } else {
 804        temp = (int32_t)(int16_t)a >> (s - 1);
 805    }
 806
 807    return (temp + 1) >> 1;
 808}
 809
 810static inline uint32_t mipsdsp_rnd32_rashift(uint32_t a, uint8_t s)
 811{
 812    int64_t temp;
 813
 814    if (s == 0) {
 815        temp = (uint64_t)a << 1;
 816    } else {
 817        temp = (int64_t)(int32_t)a >> (s - 1);
 818    }
 819    temp += 1;
 820
 821    return (temp >> 1) & 0xFFFFFFFFull;
 822}
 823
 824static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env)
 825{
 826    int16_t  temp;
 827
 828    temp = a - b;
 829    if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) {
 830        set_DSPControl_overflow_flag(1, 20, env);
 831    }
 832
 833    return temp;
 834}
 835
 836static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b,
 837                                         CPUMIPSState *env)
 838{
 839    int16_t  temp;
 840
 841    temp = a - b;
 842    if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) {
 843        if (a >= 0) {
 844            temp = 0x7FFF;
 845        } else {
 846            temp = 0x8000;
 847        }
 848        set_DSPControl_overflow_flag(1, 20, env);
 849    }
 850
 851    return temp;
 852}
 853
 854static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b,
 855                                         CPUMIPSState *env)
 856{
 857    int32_t  temp;
 858
 859    temp = a - b;
 860    if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) {
 861        if (a >= 0) {
 862            temp = 0x7FFFFFFF;
 863        } else {
 864            temp = 0x80000000;
 865        }
 866        set_DSPControl_overflow_flag(1, 20, env);
 867    }
 868
 869    return temp & 0xFFFFFFFFull;
 870}
 871
 872static inline uint16_t mipsdsp_rshift1_sub_q16(int16_t a, int16_t b)
 873{
 874    int32_t  temp;
 875
 876    temp = (int32_t)a - (int32_t)b;
 877
 878    return (temp >> 1) & 0x0000FFFF;
 879}
 880
 881static inline uint16_t mipsdsp_rrshift1_sub_q16(int16_t a, int16_t b)
 882{
 883    int32_t  temp;
 884
 885    temp = (int32_t)a - (int32_t)b;
 886    temp += 1;
 887
 888    return (temp >> 1) & 0x0000FFFF;
 889}
 890
 891static inline uint32_t mipsdsp_rshift1_sub_q32(int32_t a, int32_t b)
 892{
 893    int64_t  temp;
 894
 895    temp = (int64_t)a - (int64_t)b;
 896
 897    return (temp >> 1) & 0xFFFFFFFFull;
 898}
 899
 900static inline uint32_t mipsdsp_rrshift1_sub_q32(int32_t a, int32_t b)
 901{
 902    int64_t  temp;
 903
 904    temp = (int64_t)a - (int64_t)b;
 905    temp += 1;
 906
 907    return (temp >> 1) & 0xFFFFFFFFull;
 908}
 909
 910static inline uint16_t mipsdsp_sub_u16_u16(uint16_t a, uint16_t b,
 911                                           CPUMIPSState *env)
 912{
 913    uint8_t  temp16;
 914    uint32_t temp;
 915
 916    temp = (uint32_t)a - (uint32_t)b;
 917    temp16 = (temp >> 16) & 0x01;
 918    if (temp16 == 1) {
 919        set_DSPControl_overflow_flag(1, 20, env);
 920    }
 921    return temp & 0x0000FFFF;
 922}
 923
 924static inline uint16_t mipsdsp_satu16_sub_u16_u16(uint16_t a, uint16_t b,
 925                                                  CPUMIPSState *env)
 926{
 927    uint8_t  temp16;
 928    uint32_t temp;
 929
 930    temp   = (uint32_t)a - (uint32_t)b;
 931    temp16 = (temp >> 16) & 0x01;
 932
 933    if (temp16 == 1) {
 934        temp = 0x0000;
 935        set_DSPControl_overflow_flag(1, 20, env);
 936    }
 937
 938    return temp & 0x0000FFFF;
 939}
 940
 941static inline uint8_t mipsdsp_sub_u8(uint8_t a, uint8_t b, CPUMIPSState *env)
 942{
 943    uint8_t  temp8;
 944    uint16_t temp;
 945
 946    temp = (uint16_t)a - (uint16_t)b;
 947    temp8 = (temp >> 8) & 0x01;
 948    if (temp8 == 1) {
 949        set_DSPControl_overflow_flag(1, 20, env);
 950    }
 951
 952    return temp & 0x00FF;
 953}
 954
 955static inline uint8_t mipsdsp_satu8_sub(uint8_t a, uint8_t b, CPUMIPSState *env)
 956{
 957    uint8_t  temp8;
 958    uint16_t temp;
 959
 960    temp = (uint16_t)a - (uint16_t)b;
 961    temp8 = (temp >> 8) & 0x01;
 962    if (temp8 == 1) {
 963        temp = 0x00;
 964        set_DSPControl_overflow_flag(1, 20, env);
 965    }
 966
 967    return temp & 0x00FF;
 968}
 969
 970static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
 971{
 972    int32_t temp;
 973
 974    temp = a - b;
 975    if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) {
 976        set_DSPControl_overflow_flag(1, 20, env);
 977    }
 978
 979    return temp;
 980}
 981
 982static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
 983{
 984    int32_t temp;
 985
 986    temp = a + b;
 987
 988    if (MIPSDSP_OVERFLOW_ADD(a, b, temp, 0x80000000)) {
 989        set_DSPControl_overflow_flag(1, 20, env);
 990    }
 991
 992    return temp;
 993}
 994
 995static inline int32_t mipsdsp_cmp_eq(int32_t a, int32_t b)
 996{
 997    return a == b;
 998}
 999
1000static inline int32_t mipsdsp_cmp_le(int32_t a, int32_t b)
1001{
1002    return a <= b;
1003}
1004
1005static inline int32_t mipsdsp_cmp_lt(int32_t a, int32_t b)
1006{
1007    return a < b;
1008}
1009
1010static inline int32_t mipsdsp_cmpu_eq(uint32_t a, uint32_t b)
1011{
1012    return a == b;
1013}
1014
1015static inline int32_t mipsdsp_cmpu_le(uint32_t a, uint32_t b)
1016{
1017    return a <= b;
1018}
1019
1020static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b)
1021{
1022    return a < b;
1023}
1024/*** MIPS DSP internal functions end ***/
1025
1026#define MIPSDSP_LHI 0xFFFFFFFF00000000ull
1027#define MIPSDSP_LLO 0x00000000FFFFFFFFull
1028#define MIPSDSP_HI  0xFFFF0000
1029#define MIPSDSP_LO  0x0000FFFF
1030#define MIPSDSP_Q3  0xFF000000
1031#define MIPSDSP_Q2  0x00FF0000
1032#define MIPSDSP_Q1  0x0000FF00
1033#define MIPSDSP_Q0  0x000000FF
1034
1035#define MIPSDSP_SPLIT32_8(num, a, b, c, d)  \
1036    do {                                    \
1037        a = (num >> 24) & MIPSDSP_Q0;       \
1038        b = (num >> 16) & MIPSDSP_Q0;       \
1039        c = (num >> 8) & MIPSDSP_Q0;        \
1040        d = num & MIPSDSP_Q0;               \
1041    } while (0)
1042
1043#define MIPSDSP_SPLIT32_16(num, a, b)       \
1044    do {                                    \
1045        a = (num >> 16) & MIPSDSP_LO;       \
1046        b = num & MIPSDSP_LO;               \
1047    } while (0)
1048
1049#define MIPSDSP_RETURN32_8(a, b, c, d)  ((target_long)(int32_t) \
1050                                         (((uint32_t)a << 24) | \
1051                                         (((uint32_t)b << 16) | \
1052                                         (((uint32_t)c << 8) |  \
1053                                          ((uint32_t)d & 0xFF)))))
1054#define MIPSDSP_RETURN32_16(a, b)       ((target_long)(int32_t) \
1055                                         (((uint32_t)a << 16) | \
1056                                          ((uint32_t)b & 0xFFFF)))
1057
1058#ifdef TARGET_MIPS64
1059#define MIPSDSP_SPLIT64_16(num, a, b, c, d)  \
1060    do {                                     \
1061        a = (num >> 48) & MIPSDSP_LO;        \
1062        b = (num >> 32) & MIPSDSP_LO;        \
1063        c = (num >> 16) & MIPSDSP_LO;        \
1064        d = num & MIPSDSP_LO;                \
1065    } while (0)
1066
1067#define MIPSDSP_SPLIT64_32(num, a, b)       \
1068    do {                                    \
1069        a = (num >> 32) & MIPSDSP_LLO;      \
1070        b = num & MIPSDSP_LLO;              \
1071    } while (0)
1072
1073#define MIPSDSP_RETURN64_16(a, b, c, d) (((uint64_t)a << 48) | \
1074                                         ((uint64_t)b << 32) | \
1075                                         ((uint64_t)c << 16) | \
1076                                         (uint64_t)d)
1077#define MIPSDSP_RETURN64_32(a, b)       (((uint64_t)a << 32) | (uint64_t)b)
1078#endif
1079
1080/** DSP Arithmetic Sub-class insns **/
1081#define MIPSDSP32_UNOP_ENV(name, func, element)                            \
1082target_ulong helper_##name(target_ulong rt, CPUMIPSState *env)             \
1083{                                                                          \
1084    DSP32Value dt;                                                         \
1085    unsigned int i, n;                                                     \
1086                                                                           \
1087    n = sizeof(DSP32Value) / sizeof(dt.element[0]);                        \
1088    dt.sw[0] = rt;                                                         \
1089                                                                           \
1090    for (i = 0; i < n; i++) {                                              \
1091        dt.element[i] = mipsdsp_##func(dt.element[i], env);                \
1092    }                                                                      \
1093                                                                           \
1094    return (target_long)dt.sw[0];                                          \
1095}
1096MIPSDSP32_UNOP_ENV(absq_s_ph, sat_abs16, sh)
1097MIPSDSP32_UNOP_ENV(absq_s_qb, sat_abs8, sb)
1098MIPSDSP32_UNOP_ENV(absq_s_w, sat_abs32, sw)
1099#undef MIPSDSP32_UNOP_ENV
1100
1101#if defined(TARGET_MIPS64)
1102#define MIPSDSP64_UNOP_ENV(name, func, element)                            \
1103target_ulong helper_##name(target_ulong rt, CPUMIPSState *env)             \
1104{                                                                          \
1105    DSP64Value dt;                                                         \
1106    unsigned int i, n;                                                     \
1107                                                                           \
1108    n = sizeof(DSP64Value) / sizeof(dt.element[0]);                        \
1109    dt.sl[0] = rt;                                                         \
1110                                                                           \
1111    for (i = 0; i < n; i++) {                                              \
1112        dt.element[i] = mipsdsp_##func(dt.element[i], env);                \
1113    }                                                                      \
1114                                                                           \
1115    return dt.sl[0];                                                       \
1116}
1117MIPSDSP64_UNOP_ENV(absq_s_ob, sat_abs8, sb)
1118MIPSDSP64_UNOP_ENV(absq_s_qh, sat_abs16, sh)
1119MIPSDSP64_UNOP_ENV(absq_s_pw, sat_abs32, sw)
1120#undef MIPSDSP64_UNOP_ENV
1121#endif
1122
1123#define MIPSDSP32_BINOP(name, func, element)                               \
1124target_ulong helper_##name(target_ulong rs, target_ulong rt)               \
1125{                                                                          \
1126    DSP32Value ds, dt;                                                     \
1127    unsigned int i, n;                                                     \
1128                                                                           \
1129    n = sizeof(DSP32Value) / sizeof(ds.element[0]);                        \
1130    ds.sw[0] = rs;                                                         \
1131    dt.sw[0] = rt;                                                         \
1132                                                                           \
1133    for (i = 0; i < n; i++) {                                              \
1134        ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i]);      \
1135    }                                                                      \
1136                                                                           \
1137    return (target_long)ds.sw[0];                                          \
1138}
1139MIPSDSP32_BINOP(addqh_ph, rshift1_add_q16, sh);
1140MIPSDSP32_BINOP(addqh_r_ph, rrshift1_add_q16, sh);
1141MIPSDSP32_BINOP(addqh_r_w, rrshift1_add_q32, sw);
1142MIPSDSP32_BINOP(addqh_w, rshift1_add_q32, sw);
1143MIPSDSP32_BINOP(adduh_qb, rshift1_add_u8, ub);
1144MIPSDSP32_BINOP(adduh_r_qb, rrshift1_add_u8, ub);
1145MIPSDSP32_BINOP(subqh_ph, rshift1_sub_q16, sh);
1146MIPSDSP32_BINOP(subqh_r_ph, rrshift1_sub_q16, sh);
1147MIPSDSP32_BINOP(subqh_r_w, rrshift1_sub_q32, sw);
1148MIPSDSP32_BINOP(subqh_w, rshift1_sub_q32, sw);
1149#undef MIPSDSP32_BINOP
1150
1151#define MIPSDSP32_BINOP_ENV(name, func, element)                           \
1152target_ulong helper_##name(target_ulong rs, target_ulong rt,               \
1153                           CPUMIPSState *env)                              \
1154{                                                                          \
1155    DSP32Value ds, dt;                                                     \
1156    unsigned int i, n;                                                     \
1157                                                                           \
1158    n = sizeof(DSP32Value) / sizeof(ds.element[0]);                        \
1159    ds.sw[0] = rs;                                                         \
1160    dt.sw[0] = rt;                                                         \
1161                                                                           \
1162    for (i = 0 ; i < n ; i++) {                                            \
1163        ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i], env); \
1164    }                                                                      \
1165                                                                           \
1166    return (target_long)ds.sw[0];                                          \
1167}
1168MIPSDSP32_BINOP_ENV(addq_ph, add_i16, sh)
1169MIPSDSP32_BINOP_ENV(addq_s_ph, sat_add_i16, sh)
1170MIPSDSP32_BINOP_ENV(addq_s_w, sat_add_i32, sw);
1171MIPSDSP32_BINOP_ENV(addu_ph, add_u16, sh)
1172MIPSDSP32_BINOP_ENV(addu_qb, add_u8, ub);
1173MIPSDSP32_BINOP_ENV(addu_s_ph, sat_add_u16, sh)
1174MIPSDSP32_BINOP_ENV(addu_s_qb, sat_add_u8, ub);
1175MIPSDSP32_BINOP_ENV(subq_ph, sub_i16, sh);
1176MIPSDSP32_BINOP_ENV(subq_s_ph, sat16_sub, sh);
1177MIPSDSP32_BINOP_ENV(subq_s_w, sat32_sub, sw);
1178MIPSDSP32_BINOP_ENV(subu_ph, sub_u16_u16, sh);
1179MIPSDSP32_BINOP_ENV(subu_qb, sub_u8, ub);
1180MIPSDSP32_BINOP_ENV(subu_s_ph, satu16_sub_u16_u16, sh);
1181MIPSDSP32_BINOP_ENV(subu_s_qb, satu8_sub, ub);
1182#undef MIPSDSP32_BINOP_ENV
1183
1184#ifdef TARGET_MIPS64
1185#define MIPSDSP64_BINOP(name, func, element)                               \
1186target_ulong helper_##name(target_ulong rs, target_ulong rt)               \
1187{                                                                          \
1188    DSP64Value ds, dt;                                                     \
1189    unsigned int i, n;                                                     \
1190                                                                           \
1191    n = sizeof(DSP64Value) / sizeof(ds.element[0]);                        \
1192    ds.sl[0] = rs;                                                         \
1193    dt.sl[0] = rt;                                                         \
1194                                                                           \
1195    for (i = 0 ; i < n ; i++) {                                            \
1196        ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i]);      \
1197    }                                                                      \
1198                                                                           \
1199    return ds.sl[0];                                                       \
1200}
1201MIPSDSP64_BINOP(adduh_ob, rshift1_add_u8, ub);
1202MIPSDSP64_BINOP(adduh_r_ob, rrshift1_add_u8, ub);
1203MIPSDSP64_BINOP(subuh_ob, rshift1_sub_u8, ub);
1204MIPSDSP64_BINOP(subuh_r_ob, rrshift1_sub_u8, ub);
1205#undef MIPSDSP64_BINOP
1206
1207#define MIPSDSP64_BINOP_ENV(name, func, element)                           \
1208target_ulong helper_##name(target_ulong rs, target_ulong rt,               \
1209                           CPUMIPSState *env)                              \
1210{                                                                          \
1211    DSP64Value ds, dt;                                                     \
1212    unsigned int i, n;                                                     \
1213                                                                           \
1214    n = sizeof(DSP64Value) / sizeof(ds.element[0]);                        \
1215    ds.sl[0] = rs;                                                         \
1216    dt.sl[0] = rt;                                                         \
1217                                                                           \
1218    for (i = 0 ; i < n ; i++) {                                            \
1219        ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i], env); \
1220    }                                                                      \
1221                                                                           \
1222    return ds.sl[0];                                                       \
1223}
1224MIPSDSP64_BINOP_ENV(addq_pw, add_i32, sw);
1225MIPSDSP64_BINOP_ENV(addq_qh, add_i16, sh);
1226MIPSDSP64_BINOP_ENV(addq_s_pw, sat_add_i32, sw);
1227MIPSDSP64_BINOP_ENV(addq_s_qh, sat_add_i16, sh);
1228MIPSDSP64_BINOP_ENV(addu_ob, add_u8, uh);
1229MIPSDSP64_BINOP_ENV(addu_qh, add_u16, uh);
1230MIPSDSP64_BINOP_ENV(addu_s_ob, sat_add_u8, uh);
1231MIPSDSP64_BINOP_ENV(addu_s_qh, sat_add_u16, uh);
1232MIPSDSP64_BINOP_ENV(subq_pw, sub32, sw);
1233MIPSDSP64_BINOP_ENV(subq_qh, sub_i16, sh);
1234MIPSDSP64_BINOP_ENV(subq_s_pw, sat32_sub, sw);
1235MIPSDSP64_BINOP_ENV(subq_s_qh, sat16_sub, sh);
1236MIPSDSP64_BINOP_ENV(subu_ob, sub_u8, uh);
1237MIPSDSP64_BINOP_ENV(subu_qh, sub_u16_u16, uh);
1238MIPSDSP64_BINOP_ENV(subu_s_ob, satu8_sub, uh);
1239MIPSDSP64_BINOP_ENV(subu_s_qh, satu16_sub_u16_u16, uh);
1240#undef MIPSDSP64_BINOP_ENV
1241
1242#endif
1243
1244#define SUBUH_QB(name, var) \
1245target_ulong helper_##name##_qb(target_ulong rs, target_ulong rt) \
1246{                                                                 \
1247    uint8_t rs3, rs2, rs1, rs0;                                   \
1248    uint8_t rt3, rt2, rt1, rt0;                                   \
1249    uint8_t tempD, tempC, tempB, tempA;                           \
1250                                                                  \
1251    MIPSDSP_SPLIT32_8(rs, rs3, rs2, rs1, rs0);                    \
1252    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                    \
1253                                                                  \
1254    tempD = ((uint16_t)rs3 - (uint16_t)rt3 + var) >> 1;           \
1255    tempC = ((uint16_t)rs2 - (uint16_t)rt2 + var) >> 1;           \
1256    tempB = ((uint16_t)rs1 - (uint16_t)rt1 + var) >> 1;           \
1257    tempA = ((uint16_t)rs0 - (uint16_t)rt0 + var) >> 1;           \
1258                                                                  \
1259    return ((uint32_t)tempD << 24) | ((uint32_t)tempC << 16) |    \
1260        ((uint32_t)tempB << 8) | ((uint32_t)tempA);               \
1261}
1262
1263SUBUH_QB(subuh, 0);
1264SUBUH_QB(subuh_r, 1);
1265
1266#undef SUBUH_QB
1267
1268target_ulong helper_addsc(target_ulong rs, target_ulong rt, CPUMIPSState *env)
1269{
1270    uint64_t temp, tempRs, tempRt;
1271    bool flag;
1272
1273    tempRs = (uint64_t)rs & MIPSDSP_LLO;
1274    tempRt = (uint64_t)rt & MIPSDSP_LLO;
1275
1276    temp = tempRs + tempRt;
1277    flag = (temp & 0x0100000000ull) >> 32;
1278    set_DSPControl_carryflag(flag, env);
1279
1280    return (target_long)(int32_t)(temp & MIPSDSP_LLO);
1281}
1282
1283target_ulong helper_addwc(target_ulong rs, target_ulong rt, CPUMIPSState *env)
1284{
1285    uint32_t rd;
1286    int32_t temp32, temp31;
1287    int64_t tempL;
1288
1289    tempL = (int64_t)(int32_t)rs + (int64_t)(int32_t)rt +
1290        get_DSPControl_carryflag(env);
1291    temp31 = (tempL >> 31) & 0x01;
1292    temp32 = (tempL >> 32) & 0x01;
1293
1294    if (temp31 != temp32) {
1295        set_DSPControl_overflow_flag(1, 20, env);
1296    }
1297
1298    rd = tempL & MIPSDSP_LLO;
1299
1300    return (target_long)(int32_t)rd;
1301}
1302
1303target_ulong helper_modsub(target_ulong rs, target_ulong rt)
1304{
1305    int32_t decr;
1306    uint16_t lastindex;
1307    target_ulong rd;
1308
1309    decr = rt & MIPSDSP_Q0;
1310    lastindex = (rt >> 8) & MIPSDSP_LO;
1311
1312    if ((rs & MIPSDSP_LLO) == 0x00000000) {
1313        rd = (target_ulong)lastindex;
1314    } else {
1315        rd = rs - decr;
1316    }
1317
1318    return rd;
1319}
1320
1321target_ulong helper_raddu_w_qb(target_ulong rs)
1322{
1323    target_ulong ret = 0;
1324    DSP32Value ds;
1325    unsigned int i;
1326
1327    ds.uw[0] = rs;
1328    for (i = 0; i < 4; i++) {
1329        ret += ds.ub[i];
1330    }
1331    return ret;
1332}
1333
1334#if defined(TARGET_MIPS64)
1335target_ulong helper_raddu_l_ob(target_ulong rs)
1336{
1337    target_ulong ret = 0;
1338    DSP64Value ds;
1339    unsigned int i;
1340
1341    ds.ul[0] = rs;
1342    for (i = 0; i < 8; i++) {
1343        ret += ds.ub[i];
1344    }
1345    return ret;
1346}
1347#endif
1348
1349#define PRECR_QB_PH(name, a, b)\
1350target_ulong helper_##name##_qb_ph(target_ulong rs, target_ulong rt) \
1351{                                                                    \
1352    uint8_t tempD, tempC, tempB, tempA;                              \
1353                                                                     \
1354    tempD = (rs >> a) & MIPSDSP_Q0;                                  \
1355    tempC = (rs >> b) & MIPSDSP_Q0;                                  \
1356    tempB = (rt >> a) & MIPSDSP_Q0;                                  \
1357    tempA = (rt >> b) & MIPSDSP_Q0;                                  \
1358                                                                     \
1359    return MIPSDSP_RETURN32_8(tempD, tempC, tempB, tempA);           \
1360}
1361
1362PRECR_QB_PH(precr, 16, 0);
1363PRECR_QB_PH(precrq, 24, 8);
1364
1365#undef PRECR_QB_OH
1366
1367target_ulong helper_precr_sra_ph_w(uint32_t sa, target_ulong rs,
1368                                   target_ulong rt)
1369{
1370    uint16_t tempB, tempA;
1371
1372    tempB = ((int32_t)rt >> sa) & MIPSDSP_LO;
1373    tempA = ((int32_t)rs >> sa) & MIPSDSP_LO;
1374
1375    return MIPSDSP_RETURN32_16(tempB, tempA);
1376}
1377
1378target_ulong helper_precr_sra_r_ph_w(uint32_t sa,
1379                                     target_ulong rs, target_ulong rt)
1380{
1381    uint64_t tempB, tempA;
1382
1383    /* If sa = 0, then (sa - 1) = -1 will case shift error, so we need else. */
1384    if (sa == 0) {
1385        tempB = (rt & MIPSDSP_LO) << 1;
1386        tempA = (rs & MIPSDSP_LO) << 1;
1387    } else {
1388        tempB = ((int32_t)rt >> (sa - 1)) + 1;
1389        tempA = ((int32_t)rs >> (sa - 1)) + 1;
1390    }
1391    rt = (((tempB >> 1) & MIPSDSP_LO) << 16) | ((tempA >> 1) & MIPSDSP_LO);
1392
1393    return (target_long)(int32_t)rt;
1394}
1395
1396target_ulong helper_precrq_ph_w(target_ulong rs, target_ulong rt)
1397{
1398    uint16_t tempB, tempA;
1399
1400    tempB = (rs & MIPSDSP_HI) >> 16;
1401    tempA = (rt & MIPSDSP_HI) >> 16;
1402
1403    return MIPSDSP_RETURN32_16(tempB, tempA);
1404}
1405
1406target_ulong helper_precrq_rs_ph_w(target_ulong rs, target_ulong rt,
1407                                   CPUMIPSState *env)
1408{
1409    uint16_t tempB, tempA;
1410
1411    tempB = mipsdsp_trunc16_sat16_round(rs, env);
1412    tempA = mipsdsp_trunc16_sat16_round(rt, env);
1413
1414    return MIPSDSP_RETURN32_16(tempB, tempA);
1415}
1416
1417#if defined(TARGET_MIPS64)
1418target_ulong helper_precr_ob_qh(target_ulong rs, target_ulong rt)
1419{
1420    uint8_t rs6, rs4, rs2, rs0;
1421    uint8_t rt6, rt4, rt2, rt0;
1422    uint64_t temp;
1423
1424    rs6 = (rs >> 48) & MIPSDSP_Q0;
1425    rs4 = (rs >> 32) & MIPSDSP_Q0;
1426    rs2 = (rs >> 16) & MIPSDSP_Q0;
1427    rs0 = rs & MIPSDSP_Q0;
1428    rt6 = (rt >> 48) & MIPSDSP_Q0;
1429    rt4 = (rt >> 32) & MIPSDSP_Q0;
1430    rt2 = (rt >> 16) & MIPSDSP_Q0;
1431    rt0 = rt & MIPSDSP_Q0;
1432
1433    temp = ((uint64_t)rs6 << 56) | ((uint64_t)rs4 << 48) |
1434           ((uint64_t)rs2 << 40) | ((uint64_t)rs0 << 32) |
1435           ((uint64_t)rt6 << 24) | ((uint64_t)rt4 << 16) |
1436           ((uint64_t)rt2 << 8) | (uint64_t)rt0;
1437
1438    return temp;
1439}
1440
1441#define PRECR_QH_PW(name, var) \
1442target_ulong helper_precr_##name##_qh_pw(target_ulong rs, target_ulong rt, \
1443                                    uint32_t sa)                      \
1444{                                                                     \
1445    uint16_t rs3, rs2, rs1, rs0;                                      \
1446    uint16_t rt3, rt2, rt1, rt0;                                      \
1447    uint16_t tempD, tempC, tempB, tempA;                              \
1448                                                                      \
1449    MIPSDSP_SPLIT64_16(rs, rs3, rs2, rs1, rs0);                       \
1450    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                       \
1451                                                                      \
1452    /* When sa = 0, we use rt2, rt0, rs2, rs0;                        \
1453     * when sa != 0, we use rt3, rt1, rs3, rs1. */                    \
1454    if (sa == 0) {                                                    \
1455        tempD = rt2 << var;                                           \
1456        tempC = rt0 << var;                                           \
1457        tempB = rs2 << var;                                           \
1458        tempA = rs0 << var;                                           \
1459    } else {                                                          \
1460        tempD = (((int16_t)rt3 >> sa) + var) >> var;                  \
1461        tempC = (((int16_t)rt1 >> sa) + var) >> var;                  \
1462        tempB = (((int16_t)rs3 >> sa) + var) >> var;                  \
1463        tempA = (((int16_t)rs1 >> sa) + var) >> var;                  \
1464    }                                                                 \
1465                                                                      \
1466    return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA);           \
1467}
1468
1469PRECR_QH_PW(sra, 0);
1470PRECR_QH_PW(sra_r, 1);
1471
1472#undef PRECR_QH_PW
1473
1474target_ulong helper_precrq_ob_qh(target_ulong rs, target_ulong rt)
1475{
1476    uint8_t rs6, rs4, rs2, rs0;
1477    uint8_t rt6, rt4, rt2, rt0;
1478    uint64_t temp;
1479
1480    rs6 = (rs >> 56) & MIPSDSP_Q0;
1481    rs4 = (rs >> 40) & MIPSDSP_Q0;
1482    rs2 = (rs >> 24) & MIPSDSP_Q0;
1483    rs0 = (rs >> 8) & MIPSDSP_Q0;
1484    rt6 = (rt >> 56) & MIPSDSP_Q0;
1485    rt4 = (rt >> 40) & MIPSDSP_Q0;
1486    rt2 = (rt >> 24) & MIPSDSP_Q0;
1487    rt0 = (rt >> 8) & MIPSDSP_Q0;
1488
1489    temp = ((uint64_t)rs6 << 56) | ((uint64_t)rs4 << 48) |
1490           ((uint64_t)rs2 << 40) | ((uint64_t)rs0 << 32) |
1491           ((uint64_t)rt6 << 24) | ((uint64_t)rt4 << 16) |
1492           ((uint64_t)rt2 << 8) | (uint64_t)rt0;
1493
1494    return temp;
1495}
1496
1497target_ulong helper_precrq_qh_pw(target_ulong rs, target_ulong rt)
1498{
1499    uint16_t tempD, tempC, tempB, tempA;
1500
1501    tempD = (rs >> 48) & MIPSDSP_LO;
1502    tempC = (rs >> 16) & MIPSDSP_LO;
1503    tempB = (rt >> 48) & MIPSDSP_LO;
1504    tempA = (rt >> 16) & MIPSDSP_LO;
1505
1506    return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA);
1507}
1508
1509target_ulong helper_precrq_rs_qh_pw(target_ulong rs, target_ulong rt,
1510                                    CPUMIPSState *env)
1511{
1512    uint32_t rs2, rs0;
1513    uint32_t rt2, rt0;
1514    uint16_t tempD, tempC, tempB, tempA;
1515
1516    rs2 = (rs >> 32) & MIPSDSP_LLO;
1517    rs0 = rs & MIPSDSP_LLO;
1518    rt2 = (rt >> 32) & MIPSDSP_LLO;
1519    rt0 = rt & MIPSDSP_LLO;
1520
1521    tempD = mipsdsp_trunc16_sat16_round(rs2, env);
1522    tempC = mipsdsp_trunc16_sat16_round(rs0, env);
1523    tempB = mipsdsp_trunc16_sat16_round(rt2, env);
1524    tempA = mipsdsp_trunc16_sat16_round(rt0, env);
1525
1526    return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA);
1527}
1528
1529target_ulong helper_precrq_pw_l(target_ulong rs, target_ulong rt)
1530{
1531    uint32_t tempB, tempA;
1532
1533    tempB = (rs >> 32) & MIPSDSP_LLO;
1534    tempA = (rt >> 32) & MIPSDSP_LLO;
1535
1536    return MIPSDSP_RETURN64_32(tempB, tempA);
1537}
1538#endif
1539
1540target_ulong helper_precrqu_s_qb_ph(target_ulong rs, target_ulong rt,
1541                                    CPUMIPSState *env)
1542{
1543    uint8_t  tempD, tempC, tempB, tempA;
1544    uint16_t rsh, rsl, rth, rtl;
1545
1546    rsh = (rs & MIPSDSP_HI) >> 16;
1547    rsl =  rs & MIPSDSP_LO;
1548    rth = (rt & MIPSDSP_HI) >> 16;
1549    rtl =  rt & MIPSDSP_LO;
1550
1551    tempD = mipsdsp_sat8_reduce_precision(rsh, env);
1552    tempC = mipsdsp_sat8_reduce_precision(rsl, env);
1553    tempB = mipsdsp_sat8_reduce_precision(rth, env);
1554    tempA = mipsdsp_sat8_reduce_precision(rtl, env);
1555
1556    return MIPSDSP_RETURN32_8(tempD, tempC, tempB, tempA);
1557}
1558
1559#if defined(TARGET_MIPS64)
1560target_ulong helper_precrqu_s_ob_qh(target_ulong rs, target_ulong rt,
1561                                    CPUMIPSState *env)
1562{
1563    int i;
1564    uint16_t rs3, rs2, rs1, rs0;
1565    uint16_t rt3, rt2, rt1, rt0;
1566    uint8_t temp[8];
1567    uint64_t result;
1568
1569    result = 0;
1570
1571    MIPSDSP_SPLIT64_16(rs, rs3, rs2, rs1, rs0);
1572    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);
1573
1574    temp[7] = mipsdsp_sat8_reduce_precision(rs3, env);
1575    temp[6] = mipsdsp_sat8_reduce_precision(rs2, env);
1576    temp[5] = mipsdsp_sat8_reduce_precision(rs1, env);
1577    temp[4] = mipsdsp_sat8_reduce_precision(rs0, env);
1578    temp[3] = mipsdsp_sat8_reduce_precision(rt3, env);
1579    temp[2] = mipsdsp_sat8_reduce_precision(rt2, env);
1580    temp[1] = mipsdsp_sat8_reduce_precision(rt1, env);
1581    temp[0] = mipsdsp_sat8_reduce_precision(rt0, env);
1582
1583    for (i = 0; i < 8; i++) {
1584        result |= (uint64_t)temp[i] << (8 * i);
1585    }
1586
1587    return result;
1588}
1589
1590#define PRECEQ_PW(name, a, b) \
1591target_ulong helper_preceq_pw_##name(target_ulong rt) \
1592{                                                       \
1593    uint16_t tempB, tempA;                              \
1594    uint32_t tempBI, tempAI;                            \
1595                                                        \
1596    tempB = (rt >> a) & MIPSDSP_LO;                     \
1597    tempA = (rt >> b) & MIPSDSP_LO;                     \
1598                                                        \
1599    tempBI = (uint32_t)tempB << 16;                     \
1600    tempAI = (uint32_t)tempA << 16;                     \
1601                                                        \
1602    return MIPSDSP_RETURN64_32(tempBI, tempAI);         \
1603}
1604
1605PRECEQ_PW(qhl, 48, 32);
1606PRECEQ_PW(qhr, 16, 0);
1607PRECEQ_PW(qhla, 48, 16);
1608PRECEQ_PW(qhra, 32, 0);
1609
1610#undef PRECEQ_PW
1611
1612#endif
1613
1614#define PRECEQU_PH(name, a, b) \
1615target_ulong helper_precequ_ph_##name(target_ulong rt) \
1616{                                                        \
1617    uint16_t tempB, tempA;                               \
1618                                                         \
1619    tempB = (rt >> a) & MIPSDSP_Q0;                      \
1620    tempA = (rt >> b) & MIPSDSP_Q0;                      \
1621                                                         \
1622    tempB = tempB << 7;                                  \
1623    tempA = tempA << 7;                                  \
1624                                                         \
1625    return MIPSDSP_RETURN32_16(tempB, tempA);            \
1626}
1627
1628PRECEQU_PH(qbl, 24, 16);
1629PRECEQU_PH(qbr, 8, 0);
1630PRECEQU_PH(qbla, 24, 8);
1631PRECEQU_PH(qbra, 16, 0);
1632
1633#undef PRECEQU_PH
1634
1635#if defined(TARGET_MIPS64)
1636#define PRECEQU_QH(name, a, b, c, d) \
1637target_ulong helper_precequ_qh_##name(target_ulong rt)       \
1638{                                                            \
1639    uint16_t tempD, tempC, tempB, tempA;                     \
1640                                                             \
1641    tempD = (rt >> a) & MIPSDSP_Q0;                          \
1642    tempC = (rt >> b) & MIPSDSP_Q0;                          \
1643    tempB = (rt >> c) & MIPSDSP_Q0;                          \
1644    tempA = (rt >> d) & MIPSDSP_Q0;                          \
1645                                                             \
1646    tempD = tempD << 7;                                      \
1647    tempC = tempC << 7;                                      \
1648    tempB = tempB << 7;                                      \
1649    tempA = tempA << 7;                                      \
1650                                                             \
1651    return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA);  \
1652}
1653
1654PRECEQU_QH(obl, 56, 48, 40, 32);
1655PRECEQU_QH(obr, 24, 16, 8, 0);
1656PRECEQU_QH(obla, 56, 40, 24, 8);
1657PRECEQU_QH(obra, 48, 32, 16, 0);
1658
1659#undef PRECEQU_QH
1660
1661#endif
1662
1663#define PRECEU_PH(name, a, b) \
1664target_ulong helper_preceu_ph_##name(target_ulong rt) \
1665{                                                     \
1666    uint16_t tempB, tempA;                            \
1667                                                      \
1668    tempB = (rt >> a) & MIPSDSP_Q0;                   \
1669    tempA = (rt >> b) & MIPSDSP_Q0;                   \
1670                                                      \
1671    return MIPSDSP_RETURN32_16(tempB, tempA);         \
1672}
1673
1674PRECEU_PH(qbl, 24, 16);
1675PRECEU_PH(qbr, 8, 0);
1676PRECEU_PH(qbla, 24, 8);
1677PRECEU_PH(qbra, 16, 0);
1678
1679#undef PRECEU_PH
1680
1681#if defined(TARGET_MIPS64)
1682#define PRECEU_QH(name, a, b, c, d) \
1683target_ulong helper_preceu_qh_##name(target_ulong rt)        \
1684{                                                            \
1685    uint16_t tempD, tempC, tempB, tempA;                     \
1686                                                             \
1687    tempD = (rt >> a) & MIPSDSP_Q0;                          \
1688    tempC = (rt >> b) & MIPSDSP_Q0;                          \
1689    tempB = (rt >> c) & MIPSDSP_Q0;                          \
1690    tempA = (rt >> d) & MIPSDSP_Q0;                          \
1691                                                             \
1692    return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA);  \
1693}
1694
1695PRECEU_QH(obl, 56, 48, 40, 32);
1696PRECEU_QH(obr, 24, 16, 8, 0);
1697PRECEU_QH(obla, 56, 40, 24, 8);
1698PRECEU_QH(obra, 48, 32, 16, 0);
1699
1700#undef PRECEU_QH
1701
1702#endif
1703
1704/** DSP GPR-Based Shift Sub-class insns **/
1705#define SHIFT_QB(name, func) \
1706target_ulong helper_##name##_qb(target_ulong sa, target_ulong rt) \
1707{                                                                    \
1708    uint8_t rt3, rt2, rt1, rt0;                                      \
1709                                                                     \
1710    sa = sa & 0x07;                                                  \
1711                                                                     \
1712    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                       \
1713                                                                     \
1714    rt3 = mipsdsp_##func(rt3, sa);                                   \
1715    rt2 = mipsdsp_##func(rt2, sa);                                   \
1716    rt1 = mipsdsp_##func(rt1, sa);                                   \
1717    rt0 = mipsdsp_##func(rt0, sa);                                   \
1718                                                                     \
1719    return MIPSDSP_RETURN32_8(rt3, rt2, rt1, rt0);                   \
1720}
1721
1722#define SHIFT_QB_ENV(name, func) \
1723target_ulong helper_##name##_qb(target_ulong sa, target_ulong rt,\
1724                                CPUMIPSState *env) \
1725{                                                                    \
1726    uint8_t rt3, rt2, rt1, rt0;                                      \
1727                                                                     \
1728    sa = sa & 0x07;                                                  \
1729                                                                     \
1730    MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0);                       \
1731                                                                     \
1732    rt3 = mipsdsp_##func(rt3, sa, env);                              \
1733    rt2 = mipsdsp_##func(rt2, sa, env);                              \
1734    rt1 = mipsdsp_##func(rt1, sa, env);                              \
1735    rt0 = mipsdsp_##func(rt0, sa, env);                              \
1736                                                                     \
1737    return MIPSDSP_RETURN32_8(rt3, rt2, rt1, rt0);                   \
1738}
1739
1740SHIFT_QB_ENV(shll, lshift8);
1741SHIFT_QB(shrl, rshift_u8);
1742
1743SHIFT_QB(shra, rashift8);
1744SHIFT_QB(shra_r, rnd8_rashift);
1745
1746#undef SHIFT_QB
1747#undef SHIFT_QB_ENV
1748
1749#if defined(TARGET_MIPS64)
1750#define SHIFT_OB(name, func) \
1751target_ulong helper_##name##_ob(target_ulong rt, target_ulong sa) \
1752{                                                                        \
1753    int i;                                                               \
1754    uint8_t rt_t[8];                                                     \
1755    uint64_t temp;                                                       \
1756                                                                         \
1757    sa = sa & 0x07;                                                      \
1758    temp = 0;                                                            \
1759                                                                         \
1760    for (i = 0; i < 8; i++) {                                            \
1761        rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0;                          \
1762        rt_t[i] = mipsdsp_##func(rt_t[i], sa);                           \
1763        temp |= (uint64_t)rt_t[i] << (8 * i);                            \
1764    }                                                                    \
1765                                                                         \
1766    return temp;                                                         \
1767}
1768
1769#define SHIFT_OB_ENV(name, func) \
1770target_ulong helper_##name##_ob(target_ulong rt, target_ulong sa, \
1771                                CPUMIPSState *env)                       \
1772{                                                                        \
1773    int i;                                                               \
1774    uint8_t rt_t[8];                                                     \
1775    uint64_t temp;                                                       \
1776                                                                         \
1777    sa = sa & 0x07;                                                      \
1778    temp = 0;                                                            \
1779                                                                         \
1780    for (i = 0; i < 8; i++) {                                            \
1781        rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0;                          \
1782        rt_t[i] = mipsdsp_##func(rt_t[i], sa, env);                      \
1783        temp |= (uint64_t)rt_t[i] << (8 * i);                            \
1784    }                                                                    \
1785                                                                         \
1786    return temp;                                                         \
1787}
1788
1789SHIFT_OB_ENV(shll, lshift8);
1790SHIFT_OB(shrl, rshift_u8);
1791
1792SHIFT_OB(shra, rashift8);
1793SHIFT_OB(shra_r, rnd8_rashift);
1794
1795#undef SHIFT_OB
1796#undef SHIFT_OB_ENV
1797
1798#endif
1799
1800#define SHIFT_PH(name, func) \
1801target_ulong helper_##name##_ph(target_ulong sa, target_ulong rt, \
1802                                CPUMIPSState *env)                \
1803{                                                                 \
1804    uint16_t rth, rtl;                                            \
1805                                                                  \
1806    sa = sa & 0x0F;                                               \
1807                                                                  \
1808    MIPSDSP_SPLIT32_16(rt, rth, rtl);                             \
1809                                                                  \
1810    rth = mipsdsp_##func(rth, sa, env);                           \
1811    rtl = mipsdsp_##func(rtl, sa, env);                           \
1812                                                                  \
1813    return MIPSDSP_RETURN32_16(rth, rtl);                         \
1814}
1815
1816SHIFT_PH(shll, lshift16);
1817SHIFT_PH(shll_s, sat16_lshift);
1818
1819#undef SHIFT_PH
1820
1821#if defined(TARGET_MIPS64)
1822#define SHIFT_QH(name, func) \
1823target_ulong helper_##name##_qh(target_ulong rt, target_ulong sa) \
1824{                                                                 \
1825    uint16_t rt3, rt2, rt1, rt0;                                  \
1826                                                                  \
1827    sa = sa & 0x0F;                                               \
1828                                                                  \
1829    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                   \
1830                                                                  \
1831    rt3 = mipsdsp_##func(rt3, sa);                                \
1832    rt2 = mipsdsp_##func(rt2, sa);                                \
1833    rt1 = mipsdsp_##func(rt1, sa);                                \
1834    rt0 = mipsdsp_##func(rt0, sa);                                \
1835                                                                  \
1836    return MIPSDSP_RETURN64_16(rt3, rt2, rt1, rt0);               \
1837}
1838
1839#define SHIFT_QH_ENV(name, func) \
1840target_ulong helper_##name##_qh(target_ulong rt, target_ulong sa, \
1841                                CPUMIPSState *env)                \
1842{                                                                 \
1843    uint16_t rt3, rt2, rt1, rt0;                                  \
1844                                                                  \
1845    sa = sa & 0x0F;                                               \
1846                                                                  \
1847    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                   \
1848                                                                  \
1849    rt3 = mipsdsp_##func(rt3, sa, env);                           \
1850    rt2 = mipsdsp_##func(rt2, sa, env);                           \
1851    rt1 = mipsdsp_##func(rt1, sa, env);                           \
1852    rt0 = mipsdsp_##func(rt0, sa, env);                           \
1853                                                                  \
1854    return MIPSDSP_RETURN64_16(rt3, rt2, rt1, rt0);               \
1855}
1856
1857SHIFT_QH_ENV(shll, lshift16);
1858SHIFT_QH_ENV(shll_s, sat16_lshift);
1859
1860SHIFT_QH(shrl, rshift_u16);
1861SHIFT_QH(shra, rashift16);
1862SHIFT_QH(shra_r, rnd16_rashift);
1863
1864#undef SHIFT_QH
1865#undef SHIFT_QH_ENV
1866
1867#endif
1868
1869#define SHIFT_W(name, func) \
1870target_ulong helper_##name##_w(target_ulong sa, target_ulong rt) \
1871{                                                                       \
1872    uint32_t temp;                                                      \
1873                                                                        \
1874    sa = sa & 0x1F;                                                     \
1875    temp = mipsdsp_##func(rt, sa);                                      \
1876                                                                        \
1877    return (target_long)(int32_t)temp;                                  \
1878}
1879
1880#define SHIFT_W_ENV(name, func) \
1881target_ulong helper_##name##_w(target_ulong sa, target_ulong rt, \
1882                               CPUMIPSState *env) \
1883{                                                                       \
1884    uint32_t temp;                                                      \
1885                                                                        \
1886    sa = sa & 0x1F;                                                     \
1887    temp = mipsdsp_##func(rt, sa, env);                                 \
1888                                                                        \
1889    return (target_long)(int32_t)temp;                                  \
1890}
1891
1892SHIFT_W_ENV(shll_s, sat32_lshift);
1893SHIFT_W(shra_r, rnd32_rashift);
1894
1895#undef SHIFT_W
1896#undef SHIFT_W_ENV
1897
1898#if defined(TARGET_MIPS64)
1899#define SHIFT_PW(name, func) \
1900target_ulong helper_##name##_pw(target_ulong rt, target_ulong sa) \
1901{                                                                 \
1902    uint32_t rt1, rt0;                                            \
1903                                                                  \
1904    sa = sa & 0x1F;                                               \
1905    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
1906                                                                  \
1907    rt1 = mipsdsp_##func(rt1, sa);                                \
1908    rt0 = mipsdsp_##func(rt0, sa);                                \
1909                                                                  \
1910    return MIPSDSP_RETURN64_32(rt1, rt0);                         \
1911}
1912
1913#define SHIFT_PW_ENV(name, func) \
1914target_ulong helper_##name##_pw(target_ulong rt, target_ulong sa, \
1915                                CPUMIPSState *env)                \
1916{                                                                 \
1917    uint32_t rt1, rt0;                                            \
1918                                                                  \
1919    sa = sa & 0x1F;                                               \
1920    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
1921                                                                  \
1922    rt1 = mipsdsp_##func(rt1, sa, env);                           \
1923    rt0 = mipsdsp_##func(rt0, sa, env);                           \
1924                                                                  \
1925    return MIPSDSP_RETURN64_32(rt1, rt0);                         \
1926}
1927
1928SHIFT_PW_ENV(shll, lshift32);
1929SHIFT_PW_ENV(shll_s, sat32_lshift);
1930
1931SHIFT_PW(shra, rashift32);
1932SHIFT_PW(shra_r, rnd32_rashift);
1933
1934#undef SHIFT_PW
1935#undef SHIFT_PW_ENV
1936
1937#endif
1938
1939#define SHIFT_PH(name, func) \
1940target_ulong helper_##name##_ph(target_ulong sa, target_ulong rt) \
1941{                                                                    \
1942    uint16_t rth, rtl;                                               \
1943                                                                     \
1944    sa = sa & 0x0F;                                                  \
1945                                                                     \
1946    MIPSDSP_SPLIT32_16(rt, rth, rtl);                                \
1947                                                                     \
1948    rth = mipsdsp_##func(rth, sa);                                   \
1949    rtl = mipsdsp_##func(rtl, sa);                                   \
1950                                                                     \
1951    return MIPSDSP_RETURN32_16(rth, rtl);                            \
1952}
1953
1954SHIFT_PH(shrl, rshift_u16);
1955SHIFT_PH(shra, rashift16);
1956SHIFT_PH(shra_r, rnd16_rashift);
1957
1958#undef SHIFT_PH
1959
1960/** DSP Multiply Sub-class insns **/
1961/* Return value made up by two 16bits value.
1962 * FIXME give the macro a better name.
1963 */
1964#define MUL_RETURN32_16_PH(name, func, \
1965                           rsmov1, rsmov2, rsfilter, \
1966                           rtmov1, rtmov2, rtfilter) \
1967target_ulong helper_##name(target_ulong rs, target_ulong rt, \
1968                           CPUMIPSState *env)                \
1969{                                                            \
1970    uint16_t rsB, rsA, rtB, rtA;                             \
1971                                                             \
1972    rsB = (rs >> rsmov1) & rsfilter;                         \
1973    rsA = (rs >> rsmov2) & rsfilter;                         \
1974    rtB = (rt >> rtmov1) & rtfilter;                         \
1975    rtA = (rt >> rtmov2) & rtfilter;                         \
1976                                                             \
1977    rsB = mipsdsp_##func(rsB, rtB, env);                     \
1978    rsA = mipsdsp_##func(rsA, rtA, env);                     \
1979                                                             \
1980    return MIPSDSP_RETURN32_16(rsB, rsA);                    \
1981}
1982
1983MUL_RETURN32_16_PH(muleu_s_ph_qbl, mul_u8_u16, \
1984                      24, 16, MIPSDSP_Q0, \
1985                      16, 0, MIPSDSP_LO);
1986MUL_RETURN32_16_PH(muleu_s_ph_qbr, mul_u8_u16, \
1987                      8, 0, MIPSDSP_Q0, \
1988                      16, 0, MIPSDSP_LO);
1989MUL_RETURN32_16_PH(mulq_rs_ph, rndq15_mul_q15_q15, \
1990                      16, 0, MIPSDSP_LO, \
1991                      16, 0, MIPSDSP_LO);
1992MUL_RETURN32_16_PH(mul_ph, mul_i16_i16, \
1993                      16, 0, MIPSDSP_LO, \
1994                      16, 0, MIPSDSP_LO);
1995MUL_RETURN32_16_PH(mul_s_ph, sat16_mul_i16_i16, \
1996                      16, 0, MIPSDSP_LO, \
1997                      16, 0, MIPSDSP_LO);
1998MUL_RETURN32_16_PH(mulq_s_ph, sat16_mul_q15_q15, \
1999                      16, 0, MIPSDSP_LO, \
2000                      16, 0, MIPSDSP_LO);
2001
2002#undef MUL_RETURN32_16_PH
2003
2004#define MUL_RETURN32_32_ph(name, func, movbits) \
2005target_ulong helper_##name(target_ulong rs, target_ulong rt, \
2006                                  CPUMIPSState *env)         \
2007{                                                            \
2008    int16_t rsh, rth;                                        \
2009    int32_t temp;                                            \
2010                                                             \
2011    rsh = (rs >> movbits) & MIPSDSP_LO;                      \
2012    rth = (rt >> movbits) & MIPSDSP_LO;                      \
2013    temp = mipsdsp_##func(rsh, rth, env);                    \
2014                                                             \
2015    return (target_long)(int32_t)temp;                       \
2016}
2017
2018MUL_RETURN32_32_ph(muleq_s_w_phl, mul_q15_q15_overflowflag21, 16);
2019MUL_RETURN32_32_ph(muleq_s_w_phr, mul_q15_q15_overflowflag21, 0);
2020
2021#undef MUL_RETURN32_32_ph
2022
2023#define MUL_VOID_PH(name, use_ac_env) \
2024void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt,        \
2025                          CPUMIPSState *env)                             \
2026{                                                                        \
2027    int16_t rsh, rsl, rth, rtl;                                          \
2028    int32_t tempB, tempA;                                                \
2029    int64_t acc, dotp;                                                   \
2030                                                                         \
2031    MIPSDSP_SPLIT32_16(rs, rsh, rsl);                                    \
2032    MIPSDSP_SPLIT32_16(rt, rth, rtl);                                    \
2033                                                                         \
2034    if (use_ac_env == 1) {                                               \
2035        tempB = mipsdsp_mul_q15_q15(ac, rsh, rth, env);                  \
2036        tempA = mipsdsp_mul_q15_q15(ac, rsl, rtl, env);                  \
2037    } else {                                                             \
2038        tempB = mipsdsp_mul_u16_u16(rsh, rth);                           \
2039        tempA = mipsdsp_mul_u16_u16(rsl, rtl);                           \
2040    }                                                                    \
2041                                                                         \
2042    dotp = (int64_t)tempB - (int64_t)tempA;                              \
2043    acc = ((uint64_t)env->active_tc.HI[ac] << 32) |                      \
2044          ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);               \
2045    dotp = dotp + acc;                                                   \
2046    env->active_tc.HI[ac] = (target_long)(int32_t)                       \
2047                            ((dotp & MIPSDSP_LHI) >> 32);                \
2048    env->active_tc.LO[ac] = (target_long)(int32_t)(dotp & MIPSDSP_LLO);  \
2049}
2050
2051MUL_VOID_PH(mulsaq_s_w_ph, 1);
2052MUL_VOID_PH(mulsa_w_ph, 0);
2053
2054#undef MUL_VOID_PH
2055
2056#if defined(TARGET_MIPS64)
2057#define MUL_RETURN64_16_QH(name, func, \
2058                           rsmov1, rsmov2, rsmov3, rsmov4, rsfilter, \
2059                           rtmov1, rtmov2, rtmov3, rtmov4, rtfilter) \
2060target_ulong helper_##name(target_ulong rs, target_ulong rt,         \
2061                           CPUMIPSState *env)                        \
2062{                                                                    \
2063    uint16_t rs3, rs2, rs1, rs0;                                     \
2064    uint16_t rt3, rt2, rt1, rt0;                                     \
2065    uint16_t tempD, tempC, tempB, tempA;                             \
2066                                                                     \
2067    rs3 = (rs >> rsmov1) & rsfilter;                                 \
2068    rs2 = (rs >> rsmov2) & rsfilter;                                 \
2069    rs1 = (rs >> rsmov3) & rsfilter;                                 \
2070    rs0 = (rs >> rsmov4) & rsfilter;                                 \
2071    rt3 = (rt >> rtmov1) & rtfilter;                                 \
2072    rt2 = (rt >> rtmov2) & rtfilter;                                 \
2073    rt1 = (rt >> rtmov3) & rtfilter;                                 \
2074    rt0 = (rt >> rtmov4) & rtfilter;                                 \
2075                                                                     \
2076    tempD = mipsdsp_##func(rs3, rt3, env);                           \
2077    tempC = mipsdsp_##func(rs2, rt2, env);                           \
2078    tempB = mipsdsp_##func(rs1, rt1, env);                           \
2079    tempA = mipsdsp_##func(rs0, rt0, env);                           \
2080                                                                     \
2081    return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA);          \
2082}
2083
2084MUL_RETURN64_16_QH(muleu_s_qh_obl, mul_u8_u16, \
2085                   56, 48, 40, 32, MIPSDSP_Q0, \
2086                   48, 32, 16, 0, MIPSDSP_LO);
2087MUL_RETURN64_16_QH(muleu_s_qh_obr, mul_u8_u16, \
2088                   24, 16, 8, 0, MIPSDSP_Q0, \
2089                   48, 32, 16, 0, MIPSDSP_LO);
2090MUL_RETURN64_16_QH(mulq_rs_qh, rndq15_mul_q15_q15, \
2091                   48, 32, 16, 0, MIPSDSP_LO, \
2092                   48, 32, 16, 0, MIPSDSP_LO);
2093
2094#undef MUL_RETURN64_16_QH
2095
2096#define MUL_RETURN64_32_QH(name, \
2097                           rsmov1, rsmov2, \
2098                           rtmov1, rtmov2) \
2099target_ulong helper_##name(target_ulong rs, target_ulong rt, \
2100                           CPUMIPSState *env)                \
2101{                                                            \
2102    uint16_t rsB, rsA;                                       \
2103    uint16_t rtB, rtA;                                       \
2104    uint32_t tempB, tempA;                                   \
2105                                                             \
2106    rsB = (rs >> rsmov1) & MIPSDSP_LO;                       \
2107    rsA = (rs >> rsmov2) & MIPSDSP_LO;                       \
2108    rtB = (rt >> rtmov1) & MIPSDSP_LO;                       \
2109    rtA = (rt >> rtmov2) & MIPSDSP_LO;                       \
2110                                                             \
2111    tempB = mipsdsp_mul_q15_q15(5, rsB, rtB, env);           \
2112    tempA = mipsdsp_mul_q15_q15(5, rsA, rtA, env);           \
2113                                                             \
2114    return ((uint64_t)tempB << 32) | (uint64_t)tempA;        \
2115}
2116
2117MUL_RETURN64_32_QH(muleq_s_pw_qhl, 48, 32, 48, 32);
2118MUL_RETURN64_32_QH(muleq_s_pw_qhr, 16, 0, 16, 0);
2119
2120#undef MUL_RETURN64_32_QH
2121
2122void helper_mulsaq_s_w_qh(target_ulong rs, target_ulong rt, uint32_t ac,
2123                          CPUMIPSState *env)
2124{
2125    int16_t rs3, rs2, rs1, rs0;
2126    int16_t rt3, rt2, rt1, rt0;
2127    int32_t tempD, tempC, tempB, tempA;
2128    int64_t acc[2];
2129    int64_t temp[2];
2130    int64_t temp_sum;
2131
2132    MIPSDSP_SPLIT64_16(rs, rs3, rs2, rs1, rs0);
2133    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);
2134
2135    tempD = mipsdsp_mul_q15_q15(ac, rs3, rt3, env);
2136    tempC = mipsdsp_mul_q15_q15(ac, rs2, rt2, env);
2137    tempB = mipsdsp_mul_q15_q15(ac, rs1, rt1, env);
2138    tempA = mipsdsp_mul_q15_q15(ac, rs0, rt0, env);
2139
2140    temp[0] = ((int32_t)tempD - (int32_t)tempC) +
2141              ((int32_t)tempB - (int32_t)tempA);
2142    temp[0] = (int64_t)(temp[0] << 30) >> 30;
2143    if (((temp[0] >> 33) & 0x01) == 0) {
2144        temp[1] = 0x00;
2145    } else {
2146        temp[1] = ~0ull;
2147    }
2148
2149    acc[0] = env->active_tc.LO[ac];
2150    acc[1] = env->active_tc.HI[ac];
2151
2152    temp_sum = acc[0] + temp[0];
2153    if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&
2154       ((uint64_t)temp_sum < (uint64_t)temp[0])) {
2155        acc[1] += 1;
2156    }
2157    acc[0] = temp_sum;
2158    acc[1] += temp[1];
2159
2160    env->active_tc.HI[ac] = acc[1];
2161    env->active_tc.LO[ac] = acc[0];
2162}
2163#endif
2164
2165#define DP_QB(name, func, is_add, rsmov1, rsmov2, rtmov1, rtmov2) \
2166void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt,        \
2167                   CPUMIPSState *env)                                    \
2168{                                                                        \
2169    uint8_t rs3, rs2;                                                    \
2170    uint8_t rt3, rt2;                                                    \
2171    uint16_t tempB, tempA;                                               \
2172    uint64_t tempC, dotp;                                                \
2173                                                                         \
2174    rs3 = (rs >> rsmov1) & MIPSDSP_Q0;                                   \
2175    rs2 = (rs >> rsmov2) & MIPSDSP_Q0;                                   \
2176    rt3 = (rt >> rtmov1) & MIPSDSP_Q0;                                   \
2177    rt2 = (rt >> rtmov2) & MIPSDSP_Q0;                                   \
2178    tempB = mipsdsp_##func(rs3, rt3);                                    \
2179    tempA = mipsdsp_##func(rs2, rt2);                                    \
2180    dotp = (int64_t)tempB + (int64_t)tempA;                              \
2181    if (is_add) {                                                        \
2182        tempC = (((uint64_t)env->active_tc.HI[ac] << 32) |               \
2183                 ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO))        \
2184            + dotp;                                                      \
2185    } else {                                                             \
2186        tempC = (((uint64_t)env->active_tc.HI[ac] << 32) |               \
2187                 ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO))        \
2188            - dotp;                                                      \
2189    }                                                                    \
2190                                                                         \
2191    env->active_tc.HI[ac] = (target_long)(int32_t)                       \
2192                            ((tempC & MIPSDSP_LHI) >> 32);               \
2193    env->active_tc.LO[ac] = (target_long)(int32_t)(tempC & MIPSDSP_LLO); \
2194}
2195
2196DP_QB(dpau_h_qbl, mul_u8_u8, 1, 24, 16, 24, 16);
2197DP_QB(dpau_h_qbr, mul_u8_u8, 1, 8, 0, 8, 0);
2198DP_QB(dpsu_h_qbl, mul_u8_u8, 0, 24, 16, 24, 16);
2199DP_QB(dpsu_h_qbr, mul_u8_u8, 0, 8, 0, 8, 0);
2200
2201#undef DP_QB
2202
2203#if defined(TARGET_MIPS64)
2204#define DP_OB(name, add_sub, \
2205              rsmov1, rsmov2, rsmov3, rsmov4, \
2206              rtmov1, rtmov2, rtmov3, rtmov4) \
2207void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac,       \
2208                       CPUMIPSState *env)                               \
2209{                                                                       \
2210    uint8_t rsD, rsC, rsB, rsA;                                         \
2211    uint8_t rtD, rtC, rtB, rtA;                                         \
2212    uint16_t tempD, tempC, tempB, tempA;                                \
2213    uint64_t temp[2];                                                   \
2214    uint64_t acc[2];                                                    \
2215    uint64_t temp_sum;                                                  \
2216                                                                        \
2217    temp[0] = 0;                                                        \
2218    temp[1] = 0;                                                        \
2219                                                                        \
2220    rsD = (rs >> rsmov1) & MIPSDSP_Q0;                                  \
2221    rsC = (rs >> rsmov2) & MIPSDSP_Q0;                                  \
2222    rsB = (rs >> rsmov3) & MIPSDSP_Q0;                                  \
2223    rsA = (rs >> rsmov4) & MIPSDSP_Q0;                                  \
2224    rtD = (rt >> rtmov1) & MIPSDSP_Q0;                                  \
2225    rtC = (rt >> rtmov2) & MIPSDSP_Q0;                                  \
2226    rtB = (rt >> rtmov3) & MIPSDSP_Q0;                                  \
2227    rtA = (rt >> rtmov4) & MIPSDSP_Q0;                                  \
2228                                                                        \
2229    tempD = mipsdsp_mul_u8_u8(rsD, rtD);                                \
2230    tempC = mipsdsp_mul_u8_u8(rsC, rtC);                                \
2231    tempB = mipsdsp_mul_u8_u8(rsB, rtB);                                \
2232    tempA = mipsdsp_mul_u8_u8(rsA, rtA);                                \
2233                                                                        \
2234    temp[0] = (uint64_t)tempD + (uint64_t)tempC +                       \
2235      (uint64_t)tempB + (uint64_t)tempA;                                \
2236                                                                        \
2237    acc[0] = env->active_tc.LO[ac];                                     \
2238    acc[1] = env->active_tc.HI[ac];                                     \
2239                                                                        \
2240    if (add_sub) {                                                      \
2241        temp_sum = acc[0] + temp[0];                                    \
2242        if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&                  \
2243            ((uint64_t)temp_sum < (uint64_t)temp[0])) {                 \
2244            acc[1] += 1;                                                \
2245        }                                                               \
2246        temp[0] = temp_sum;                                             \
2247        temp[1] = acc[1] + temp[1];                                     \
2248    } else {                                                            \
2249        temp_sum = acc[0] - temp[0];                                    \
2250        if ((uint64_t)temp_sum > (uint64_t)acc[0]) {                    \
2251            acc[1] -= 1;                                                \
2252        }                                                               \
2253        temp[0] = temp_sum;                                             \
2254        temp[1] = acc[1] - temp[1];                                     \
2255    }                                                                   \
2256                                                                        \
2257    env->active_tc.HI[ac] = temp[1];                                    \
2258    env->active_tc.LO[ac] = temp[0];                                    \
2259}
2260
2261DP_OB(dpau_h_obl, 1, 56, 48, 40, 32, 56, 48, 40, 32);
2262DP_OB(dpau_h_obr, 1, 24, 16, 8, 0, 24, 16, 8, 0);
2263DP_OB(dpsu_h_obl, 0, 56, 48, 40, 32, 56, 48, 40, 32);
2264DP_OB(dpsu_h_obr, 0, 24, 16, 8, 0, 24, 16, 8, 0);
2265
2266#undef DP_OB
2267#endif
2268
2269#define DP_NOFUNC_PH(name, is_add, rsmov1, rsmov2, rtmov1, rtmov2)             \
2270void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt,              \
2271                   CPUMIPSState *env)                                          \
2272{                                                                              \
2273    int16_t rsB, rsA, rtB, rtA;                                                \
2274    int32_t  tempA, tempB;                                                     \
2275    int64_t  acc;                                                              \
2276                                                                               \
2277    rsB = (rs >> rsmov1) & MIPSDSP_LO;                                         \
2278    rsA = (rs >> rsmov2) & MIPSDSP_LO;                                         \
2279    rtB = (rt >> rtmov1) & MIPSDSP_LO;                                         \
2280    rtA = (rt >> rtmov2) & MIPSDSP_LO;                                         \
2281                                                                               \
2282    tempB = (int32_t)rsB * (int32_t)rtB;                                       \
2283    tempA = (int32_t)rsA * (int32_t)rtA;                                       \
2284                                                                               \
2285    acc = ((uint64_t)env->active_tc.HI[ac] << 32) |                            \
2286          ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);                     \
2287                                                                               \
2288    if (is_add) {                                                              \
2289        acc = acc + ((int64_t)tempB + (int64_t)tempA);                         \
2290    } else {                                                                   \
2291        acc = acc - ((int64_t)tempB + (int64_t)tempA);                         \
2292    }                                                                          \
2293                                                                               \
2294    env->active_tc.HI[ac] = (target_long)(int32_t)((acc & MIPSDSP_LHI) >> 32); \
2295    env->active_tc.LO[ac] = (target_long)(int32_t)(acc & MIPSDSP_LLO);         \
2296}
2297
2298DP_NOFUNC_PH(dpa_w_ph, 1, 16, 0, 16, 0);
2299DP_NOFUNC_PH(dpax_w_ph, 1, 16, 0, 0, 16);
2300DP_NOFUNC_PH(dps_w_ph, 0, 16, 0, 16, 0);
2301DP_NOFUNC_PH(dpsx_w_ph, 0, 16, 0, 0, 16);
2302#undef DP_NOFUNC_PH
2303
2304#define DP_HASFUNC_PH(name, is_add, rsmov1, rsmov2, rtmov1, rtmov2) \
2305void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt,   \
2306                   CPUMIPSState *env)                      \
2307{                                                          \
2308    int16_t rsB, rsA, rtB, rtA;                            \
2309    int32_t tempB, tempA;                                  \
2310    int64_t acc, dotp;                                     \
2311                                                           \
2312    rsB = (rs >> rsmov1) & MIPSDSP_LO;                     \
2313    rsA = (rs >> rsmov2) & MIPSDSP_LO;                     \
2314    rtB = (rt >> rtmov1) & MIPSDSP_LO;                     \
2315    rtA = (rt >> rtmov2) & MIPSDSP_LO;                     \
2316                                                           \
2317    tempB = mipsdsp_mul_q15_q15(ac, rsB, rtB, env);        \
2318    tempA = mipsdsp_mul_q15_q15(ac, rsA, rtA, env);        \
2319                                                           \
2320    dotp = (int64_t)tempB + (int64_t)tempA;                \
2321    acc = ((uint64_t)env->active_tc.HI[ac] << 32) |        \
2322          ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \
2323                                                           \
2324    if (is_add) {                                          \
2325        acc = acc + dotp;                                  \
2326    } else {                                               \
2327        acc = acc - dotp;                                  \
2328    }                                                      \
2329                                                           \
2330    env->active_tc.HI[ac] = (target_long)(int32_t)         \
2331        ((acc & MIPSDSP_LHI) >> 32);                       \
2332    env->active_tc.LO[ac] = (target_long)(int32_t)         \
2333        (acc & MIPSDSP_LLO);                               \
2334}
2335
2336DP_HASFUNC_PH(dpaq_s_w_ph, 1, 16, 0, 16, 0);
2337DP_HASFUNC_PH(dpaqx_s_w_ph, 1, 16, 0, 0, 16);
2338DP_HASFUNC_PH(dpsq_s_w_ph, 0, 16, 0, 16, 0);
2339DP_HASFUNC_PH(dpsqx_s_w_ph, 0, 16, 0, 0, 16);
2340
2341#undef DP_HASFUNC_PH
2342
2343#define DP_128OPERATION_PH(name, is_add) \
2344void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \
2345                          CPUMIPSState *env)                             \
2346{                                                                        \
2347    int16_t rsh, rsl, rth, rtl;                                          \
2348    int32_t tempB, tempA, tempC62_31, tempC63;                           \
2349    int64_t acc, dotp, tempC;                                            \
2350                                                                         \
2351    MIPSDSP_SPLIT32_16(rs, rsh, rsl);                                    \
2352    MIPSDSP_SPLIT32_16(rt, rth, rtl);                                    \
2353                                                                         \
2354    tempB = mipsdsp_mul_q15_q15(ac, rsh, rtl, env);                      \
2355    tempA = mipsdsp_mul_q15_q15(ac, rsl, rth, env);                      \
2356                                                                         \
2357    dotp = (int64_t)tempB + (int64_t)tempA;                              \
2358    acc = ((uint64_t)env->active_tc.HI[ac] << 32) |                      \
2359          ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);               \
2360    if (is_add) {                                                        \
2361        tempC = acc + dotp;                                              \
2362    } else {                                                             \
2363        tempC = acc - dotp;                                              \
2364    }                                                                    \
2365    tempC63 = (tempC >> 63) & 0x01;                                      \
2366    tempC62_31 = (tempC >> 31) & 0xFFFFFFFF;                             \
2367                                                                         \
2368    if ((tempC63 == 0) && (tempC62_31 != 0x00000000)) {                  \
2369        tempC = 0x7FFFFFFF;                                              \
2370        set_DSPControl_overflow_flag(1, 16 + ac, env);                   \
2371    }                                                                    \
2372                                                                         \
2373    if ((tempC63 == 1) && (tempC62_31 != 0xFFFFFFFF)) {                  \
2374        tempC = (int64_t)(int32_t)0x80000000;                            \
2375        set_DSPControl_overflow_flag(1, 16 + ac, env);                   \
2376    }                                                                    \
2377                                                                         \
2378    env->active_tc.HI[ac] = (target_long)(int32_t)                       \
2379        ((tempC & MIPSDSP_LHI) >> 32);                                   \
2380    env->active_tc.LO[ac] = (target_long)(int32_t)                       \
2381        (tempC & MIPSDSP_LLO);                                           \
2382}
2383
2384DP_128OPERATION_PH(dpaqx_sa_w_ph, 1);
2385DP_128OPERATION_PH(dpsqx_sa_w_ph, 0);
2386
2387#undef DP_128OPERATION_HP
2388
2389#if defined(TARGET_MIPS64)
2390#define DP_QH(name, is_add, use_ac_env) \
2391void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac,    \
2392                   CPUMIPSState *env)                                \
2393{                                                                    \
2394    int32_t rs3, rs2, rs1, rs0;                                      \
2395    int32_t rt3, rt2, rt1, rt0;                                      \
2396    int32_t tempD, tempC, tempB, tempA;                              \
2397    int64_t acc[2];                                                  \
2398    int64_t temp[2];                                                 \
2399    int64_t temp_sum;                                                \
2400                                                                     \
2401    MIPSDSP_SPLIT64_16(rs, rs3, rs2, rs1, rs0);                      \
2402    MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0);                      \
2403                                                                     \
2404    if (use_ac_env) {                                                \
2405        tempD = mipsdsp_mul_q15_q15(ac, rs3, rt3, env);              \
2406        tempC = mipsdsp_mul_q15_q15(ac, rs2, rt2, env);              \
2407        tempB = mipsdsp_mul_q15_q15(ac, rs1, rt1, env);              \
2408        tempA = mipsdsp_mul_q15_q15(ac, rs0, rt0, env);              \
2409    } else {                                                         \
2410        tempD = mipsdsp_mul_u16_u16(rs3, rt3);                       \
2411        tempC = mipsdsp_mul_u16_u16(rs2, rt2);                       \
2412        tempB = mipsdsp_mul_u16_u16(rs1, rt1);                       \
2413        tempA = mipsdsp_mul_u16_u16(rs0, rt0);                       \
2414    }                                                                \
2415                                                                     \
2416    temp[0] = (int64_t)tempD + (int64_t)tempC +                      \
2417              (int64_t)tempB + (int64_t)tempA;                       \
2418                                                                     \
2419    if (temp[0] >= 0) {                                              \
2420        temp[1] = 0;                                                 \
2421    } else {                                                         \
2422        temp[1] = ~0ull;                                             \
2423    }                                                                \
2424                                                                     \
2425    acc[1] = env->active_tc.HI[ac];                                  \
2426    acc[0] = env->active_tc.LO[ac];                                  \
2427                                                                     \
2428    if (is_add) {                                                    \
2429        temp_sum = acc[0] + temp[0];                                 \
2430        if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&               \
2431            ((uint64_t)temp_sum < (uint64_t)temp[0])) {              \
2432            acc[1] = acc[1] + 1;                                     \
2433        }                                                            \
2434        temp[0] = temp_sum;                                          \
2435        temp[1] = acc[1] + temp[1];                                  \
2436    } else {                                                         \
2437        temp_sum = acc[0] - temp[0];                                 \
2438        if ((uint64_t)temp_sum > (uint64_t)acc[0]) {                 \
2439            acc[1] = acc[1] - 1;                                     \
2440        }                                                            \
2441        temp[0] = temp_sum;                                          \
2442        temp[1] = acc[1] - temp[1];                                  \
2443    }                                                                \
2444                                                                     \
2445    env->active_tc.HI[ac] = temp[1];                                 \
2446    env->active_tc.LO[ac] = temp[0];                                 \
2447}
2448
2449DP_QH(dpa_w_qh, 1, 0);
2450DP_QH(dpaq_s_w_qh, 1, 1);
2451DP_QH(dps_w_qh, 0, 0);
2452DP_QH(dpsq_s_w_qh, 0, 1);
2453
2454#undef DP_QH
2455
2456#endif
2457
2458#define DP_L_W(name, is_add) \
2459void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt,      \
2460                   CPUMIPSState *env)                                  \
2461{                                                                      \
2462    int32_t temp63;                                                    \
2463    int64_t dotp, acc;                                                 \
2464    uint64_t temp;                                                     \
2465    bool overflow;                                                     \
2466                                                                       \
2467    dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env);                       \
2468    acc = ((uint64_t)env->active_tc.HI[ac] << 32) |                    \
2469          ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);             \
2470    if (is_add) {                                                      \
2471        temp = acc + dotp;                                             \
2472        overflow = MIPSDSP_OVERFLOW_ADD((uint64_t)acc, (uint64_t)dotp, \
2473                                        temp, (0x01ull << 63));        \
2474    } else {                                                           \
2475        temp = acc - dotp;                                             \
2476        overflow = MIPSDSP_OVERFLOW_SUB((uint64_t)acc, (uint64_t)dotp, \
2477                                        temp, (0x01ull << 63));        \
2478    }                                                                  \
2479                                                                       \
2480    if (overflow) {                                                    \
2481        temp63 = (temp >> 63) & 0x01;                                  \
2482        if (temp63 == 1) {                                             \
2483            temp = (0x01ull << 63) - 1;                                \
2484        } else {                                                       \
2485            temp = 0x01ull << 63;                                      \
2486        }                                                              \
2487                                                                       \
2488        set_DSPControl_overflow_flag(1, 16 + ac, env);                 \
2489    }                                                                  \
2490                                                                       \
2491    env->active_tc.HI[ac] = (target_long)(int32_t)                     \
2492        ((temp & MIPSDSP_LHI) >> 32);                                  \
2493    env->active_tc.LO[ac] = (target_long)(int32_t)                     \
2494        (temp & MIPSDSP_LLO);                                          \
2495}
2496
2497DP_L_W(dpaq_sa_l_w, 1);
2498DP_L_W(dpsq_sa_l_w, 0);
2499
2500#undef DP_L_W
2501
2502#if defined(TARGET_MIPS64)
2503#define DP_L_PW(name, func) \
2504void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac, \
2505                   CPUMIPSState *env)                             \
2506{                                                                 \
2507    int32_t rs1, rs0;                                             \
2508    int32_t rt1, rt0;                                             \
2509    int64_t tempB[2], tempA[2];                                   \
2510    int64_t temp[2];                                              \
2511    int64_t acc[2];                                               \
2512    int64_t temp_sum;                                             \
2513                                                                  \
2514    temp[0] = 0;                                                  \
2515    temp[1] = 0;                                                  \
2516                                                                  \
2517    MIPSDSP_SPLIT64_32(rs, rs1, rs0);                             \
2518    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                             \
2519                                                                  \
2520    tempB[0] = mipsdsp_mul_q31_q31(ac, rs1, rt1, env);            \
2521    tempA[0] = mipsdsp_mul_q31_q31(ac, rs0, rt0, env);            \
2522                                                                  \
2523    if (tempB[0] >= 0) {                                          \
2524        tempB[1] = 0x00;                                          \
2525    } else {                                                      \
2526        tempB[1] = ~0ull;                                         \
2527    }                                                             \
2528                                                                  \
2529    if (tempA[0] >= 0) {                                          \
2530        tempA[1] = 0x00;                                          \
2531    } else {                                                      \
2532        tempA[1] = ~0ull;                                         \
2533    }                                                             \
2534                                                                  \
2535    temp_sum = tempB[0] + tempA[0];                               \
2536    if (((uint64_t)temp_sum < (uint64_t)tempB[0]) &&              \
2537        ((uint64_t)temp_sum < (uint64_t)tempA[0])) {              \
2538        temp[1] += 1;                                             \
2539    }                                                             \
2540    temp[0] = temp_sum;                                           \
2541    temp[1] += tempB[1] + tempA[1];                               \
2542                                                                  \
2543    mipsdsp_##func(acc, ac, temp, env);                           \
2544                                                                  \
2545    env->active_tc.HI[ac] = acc[1];                               \
2546    env->active_tc.LO[ac] = acc[0];                               \
2547}
2548
2549DP_L_PW(dpaq_sa_l_pw, sat64_acc_add_q63);
2550DP_L_PW(dpsq_sa_l_pw, sat64_acc_sub_q63);
2551
2552#undef DP_L_PW
2553
2554void helper_mulsaq_s_l_pw(target_ulong rs, target_ulong rt, uint32_t ac,
2555                          CPUMIPSState *env)
2556{
2557    int32_t rs1, rs0;
2558    int32_t rt1, rt0;
2559    int64_t tempB[2], tempA[2];
2560    int64_t temp[2];
2561    int64_t acc[2];
2562    int64_t temp_sum;
2563
2564    rs1 = (rs >> 32) & MIPSDSP_LLO;
2565    rs0 = rs & MIPSDSP_LLO;
2566    rt1 = (rt >> 32) & MIPSDSP_LLO;
2567    rt0 = rt & MIPSDSP_LLO;
2568
2569    tempB[0] = mipsdsp_mul_q31_q31(ac, rs1, rt1, env);
2570    tempA[0] = mipsdsp_mul_q31_q31(ac, rs0, rt0, env);
2571
2572    if (tempB[0] >= 0) {
2573        tempB[1] = 0x00;
2574    } else {
2575        tempB[1] = ~0ull;
2576    }
2577
2578    if (tempA[0] >= 0) {
2579        tempA[1] = 0x00;
2580    } else {
2581        tempA[1] = ~0ull;
2582    }
2583
2584    acc[0] = env->active_tc.LO[ac];
2585    acc[1] = env->active_tc.HI[ac];
2586
2587    temp_sum = tempB[0] - tempA[0];
2588    if ((uint64_t)temp_sum > (uint64_t)tempB[0]) {
2589        tempB[1] -= 1;
2590    }
2591    temp[0] = temp_sum;
2592    temp[1] = tempB[1] - tempA[1];
2593
2594    if ((temp[1] & 0x01) == 0) {
2595        temp[1] = 0x00;
2596    } else {
2597        temp[1] = ~0ull;
2598    }
2599
2600    temp_sum = acc[0] + temp[0];
2601    if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&
2602       ((uint64_t)temp_sum < (uint64_t)temp[0])) {
2603        acc[1] += 1;
2604    }
2605    acc[0] = temp_sum;
2606    acc[1] += temp[1];
2607
2608    env->active_tc.HI[ac] = acc[1];
2609    env->active_tc.LO[ac] = acc[0];
2610}
2611#endif
2612
2613#define MAQ_S_W(name, mov) \
2614void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \
2615                   CPUMIPSState *env)                             \
2616{                                                                 \
2617    int16_t rsh, rth;                                             \
2618    int32_t tempA;                                                \
2619    int64_t tempL, acc;                                           \
2620                                                                  \
2621    rsh = (rs >> mov) & MIPSDSP_LO;                               \
2622    rth = (rt >> mov) & MIPSDSP_LO;                               \
2623    tempA  = mipsdsp_mul_q15_q15(ac, rsh, rth, env);              \
2624    acc = ((uint64_t)env->active_tc.HI[ac] << 32) |               \
2625          ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);        \
2626    tempL  = (int64_t)tempA + acc;                                \
2627    env->active_tc.HI[ac] = (target_long)(int32_t)                \
2628        ((tempL & MIPSDSP_LHI) >> 32);                            \
2629    env->active_tc.LO[ac] = (target_long)(int32_t)                \
2630        (tempL & MIPSDSP_LLO);                                    \
2631}
2632
2633MAQ_S_W(maq_s_w_phl, 16);
2634MAQ_S_W(maq_s_w_phr, 0);
2635
2636#undef MAQ_S_W
2637
2638#define MAQ_SA_W(name, mov) \
2639void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt,        \
2640                   CPUMIPSState *env)                                    \
2641{                                                                        \
2642    int16_t rsh, rth;                                                    \
2643    int32_t tempA;                                                       \
2644                                                                         \
2645    rsh = (rs >> mov) & MIPSDSP_LO;                                      \
2646    rth = (rt >> mov) & MIPSDSP_LO;                                      \
2647    tempA = mipsdsp_mul_q15_q15(ac, rsh, rth, env);                      \
2648    tempA = mipsdsp_sat32_acc_q31(ac, tempA, env);                       \
2649                                                                         \
2650    env->active_tc.HI[ac] = (target_long)(int32_t)(((int64_t)tempA &     \
2651                                                    MIPSDSP_LHI) >> 32); \
2652    env->active_tc.LO[ac] = (target_long)(int32_t)((int64_t)tempA &      \
2653                                                   MIPSDSP_LLO);         \
2654}
2655
2656MAQ_SA_W(maq_sa_w_phl, 16);
2657MAQ_SA_W(maq_sa_w_phr, 0);
2658
2659#undef MAQ_SA_W
2660
2661#define MULQ_W(name, addvar) \
2662target_ulong helper_##name(target_ulong rs, target_ulong rt,   \
2663                           CPUMIPSState *env)                  \
2664{                                                              \
2665    int32_t rs_t, rt_t;                                        \
2666    int32_t tempI;                                             \
2667    int64_t tempL;                                             \
2668                                                               \
2669    rs_t = rs & MIPSDSP_LLO;                                   \
2670    rt_t = rt & MIPSDSP_LLO;                                   \
2671                                                               \
2672    if ((rs_t == 0x80000000) && (rt_t == 0x80000000)) {        \
2673        tempL = 0x7FFFFFFF00000000ull;                         \
2674        set_DSPControl_overflow_flag(1, 21, env);              \
2675    } else {                                                   \
2676        tempL  = ((int64_t)rs_t * (int64_t)rt_t) << 1;         \
2677        tempL += addvar;                                       \
2678    }                                                          \
2679    tempI = (tempL & MIPSDSP_LHI) >> 32;                       \
2680                                                               \
2681    return (target_long)(int32_t)tempI;                        \
2682}
2683
2684MULQ_W(mulq_s_w, 0);
2685MULQ_W(mulq_rs_w, 0x80000000ull);
2686
2687#undef MULQ_W
2688
2689#if defined(TARGET_MIPS64)
2690
2691#define MAQ_S_W_QH(name, mov) \
2692void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac, \
2693                   CPUMIPSState *env)                             \
2694{                                                                 \
2695    int16_t rs_t, rt_t;                                           \
2696    int32_t temp_mul;                                             \
2697    int64_t temp[2];                                              \
2698    int64_t acc[2];                                               \
2699    int64_t temp_sum;                                             \
2700                                                                  \
2701    temp[0] = 0;                                                  \
2702    temp[1] = 0;                                                  \
2703                                                                  \
2704    rs_t = (rs >> mov) & MIPSDSP_LO;                              \
2705    rt_t = (rt >> mov) & MIPSDSP_LO;                              \
2706    temp_mul = mipsdsp_mul_q15_q15(ac, rs_t, rt_t, env);          \
2707                                                                  \
2708    temp[0] = (int64_t)temp_mul;                                  \
2709    if (temp[0] >= 0) {                                           \
2710        temp[1] = 0x00;                                           \
2711    } else {                                                      \
2712        temp[1] = ~0ull;                                          \
2713    }                                                             \
2714                                                                  \
2715    acc[0] = env->active_tc.LO[ac];                               \
2716    acc[1] = env->active_tc.HI[ac];                               \
2717                                                                  \
2718    temp_sum = acc[0] + temp[0];                                  \
2719    if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&                \
2720        ((uint64_t)temp_sum < (uint64_t)temp[0])) {               \
2721        acc[1] += 1;                                              \
2722    }                                                             \
2723    acc[0] = temp_sum;                                            \
2724    acc[1] += temp[1];                                            \
2725                                                                  \
2726    env->active_tc.HI[ac] = acc[1];                               \
2727    env->active_tc.LO[ac] = acc[0];                               \
2728}
2729
2730MAQ_S_W_QH(maq_s_w_qhll, 48);
2731MAQ_S_W_QH(maq_s_w_qhlr, 32);
2732MAQ_S_W_QH(maq_s_w_qhrl, 16);
2733MAQ_S_W_QH(maq_s_w_qhrr, 0);
2734
2735#undef MAQ_S_W_QH
2736
2737#define MAQ_SA_W(name, mov) \
2738void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac, \
2739                   CPUMIPSState *env)                             \
2740{                                                                 \
2741    int16_t rs_t, rt_t;                                           \
2742    int32_t temp;                                                 \
2743    int64_t acc[2];                                               \
2744                                                                  \
2745    rs_t = (rs >> mov) & MIPSDSP_LO;                              \
2746    rt_t = (rt >> mov) & MIPSDSP_LO;                              \
2747    temp = mipsdsp_mul_q15_q15(ac, rs_t, rt_t, env);              \
2748    temp = mipsdsp_sat32_acc_q31(ac, temp, env);                  \
2749                                                                  \
2750    acc[0] = (int64_t)(int32_t)temp;                              \
2751    if (acc[0] >= 0) {                                            \
2752        acc[1] = 0x00;                                            \
2753    } else {                                                      \
2754        acc[1] = ~0ull;                                           \
2755    }                                                             \
2756                                                                  \
2757    env->active_tc.HI[ac] = acc[1];                               \
2758    env->active_tc.LO[ac] = acc[0];                               \
2759}
2760
2761MAQ_SA_W(maq_sa_w_qhll, 48);
2762MAQ_SA_W(maq_sa_w_qhlr, 32);
2763MAQ_SA_W(maq_sa_w_qhrl, 16);
2764MAQ_SA_W(maq_sa_w_qhrr, 0);
2765
2766#undef MAQ_SA_W
2767
2768#define MAQ_S_L_PW(name, mov) \
2769void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac, \
2770                   CPUMIPSState *env)                             \
2771{                                                                 \
2772    int32_t rs_t, rt_t;                                           \
2773    int64_t temp[2];                                              \
2774    int64_t acc[2];                                               \
2775    int64_t temp_sum;                                             \
2776                                                                  \
2777    temp[0] = 0;                                                  \
2778    temp[1] = 0;                                                  \
2779                                                                  \
2780    rs_t = (rs >> mov) & MIPSDSP_LLO;                             \
2781    rt_t = (rt >> mov) & MIPSDSP_LLO;                             \
2782                                                                  \
2783    temp[0] = mipsdsp_mul_q31_q31(ac, rs_t, rt_t, env);           \
2784    if (temp[0] >= 0) {                                           \
2785        temp[1] = 0x00;                                           \
2786    } else {                                                      \
2787        temp[1] = ~0ull;                                          \
2788    }                                                             \
2789                                                                  \
2790    acc[0] = env->active_tc.LO[ac];                               \
2791    acc[1] = env->active_tc.HI[ac];                               \
2792                                                                  \
2793    temp_sum = acc[0] + temp[0];                                  \
2794    if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&                \
2795        ((uint64_t)temp_sum < (uint64_t)temp[0])) {               \
2796        acc[1] += 1;                                              \
2797    }                                                             \
2798    acc[0] = temp_sum;                                            \
2799    acc[1] += temp[1];                                            \
2800                                                                  \
2801    env->active_tc.HI[ac] = acc[1];                               \
2802    env->active_tc.LO[ac] = acc[0];                               \
2803}
2804
2805MAQ_S_L_PW(maq_s_l_pwl, 32);
2806MAQ_S_L_PW(maq_s_l_pwr, 0);
2807
2808#undef MAQ_S_L_PW
2809
2810#define DM_OPERATE(name, func, is_add, sigext) \
2811void helper_##name(target_ulong rs, target_ulong rt, uint32_t ac,    \
2812                  CPUMIPSState *env)                                 \
2813{                                                                    \
2814    int32_t rs1, rs0;                                                \
2815    int32_t rt1, rt0;                                                \
2816    int64_t tempBL[2], tempAL[2];                                    \
2817    int64_t acc[2];                                                  \
2818    int64_t temp[2];                                                 \
2819    int64_t temp_sum;                                                \
2820                                                                     \
2821    temp[0] = 0x00;                                                  \
2822    temp[1] = 0x00;                                                  \
2823                                                                     \
2824    MIPSDSP_SPLIT64_32(rs, rs1, rs0);                                \
2825    MIPSDSP_SPLIT64_32(rt, rt1, rt0);                                \
2826                                                                     \
2827    if (sigext) {                                                    \
2828        tempBL[0] = (int64_t)mipsdsp_##func(rs1, rt1);               \
2829        tempAL[0] = (int64_t)mipsdsp_##func(rs0, rt0);               \
2830                                                                     \
2831        if (tempBL[0] >= 0) {                                        \
2832            tempBL[1] = 0x0;                                         \
2833        } else {                                                     \
2834            tempBL[1] = ~0ull;                                       \
2835        }                                                            \
2836                                                                     \
2837        if (tempAL[0] >= 0) {                                        \
2838            tempAL[1] = 0x0;                                         \
2839        } else {                                                     \
2840            tempAL[1] = ~0ull;                                       \
2841        }                                                            \
2842    } else {                                                         \
2843        tempBL[0] = mipsdsp_##func(rs1, rt1);                        \
2844        tempAL[0] = mipsdsp_##func(rs0, rt0);                        \
2845        tempBL[1] = 0;                                               \
2846        tempAL[1] = 0;                                               \
2847    }                                                                \
2848                                                                     \
2849    acc[1] = env->active_tc.HI[ac];                                  \
2850    acc[0] = env->active_tc.LO[ac];                                  \
2851                                                                     \
2852    temp_sum = tempBL[0] + tempAL[0];                                \
2853    if (((uint64_t)temp_sum < (uint64_t)tempBL[0]) &&                \
2854        ((uint64_t)temp_sum < (uint64_t)tempAL[0])) {                \
2855        temp[1] += 1;                                                \
2856    }                                                                \
2857    temp[0] = temp_sum;                                              \
2858    temp[1] += tempBL[1] + tempAL[1];                                \
2859                                                                     \
2860    if (is_add) {                                                    \
2861        temp_sum = acc[0] + temp[0];                                 \
2862        if (((uint64_t)temp_sum < (uint64_t)acc[0]) &&               \
2863            ((uint64_t)temp_sum < (uint64_t)temp[0])) {              \
2864            acc[1] += 1;                                             \
2865        }                                                            \
2866        temp[0] = temp_sum;                                          \
2867        temp[1] = acc[1] + temp[1];                                  \
2868    } else {                                                         \
2869        temp_sum = acc[0] - temp[0];                                 \
2870        if ((uint64_t)temp_sum > (uint64_t)acc[0]) {                 \
2871            acc[1] -= 1;                                             \
2872        }                                                            \
2873        temp[0] = temp_sum;                                          \
2874        temp[1] = acc[1] - temp[1];                                  \
2875    }                                                                \
2876                                                                     \
2877    env->active_tc.HI[ac] = temp[1];                                 \
2878    env->active_tc.LO[ac] = temp[0];                                 \
2879}
2880
2881DM_OPERATE(dmadd, mul_i32_i32, 1, 1);
2882DM_OPERATE(dmaddu, mul_u32_u32, 1, 0);
2883DM_OPERATE(dmsub, mul_i32_i32, 0, 1);
2884DM_OPERATE(dmsubu, mul_u32_u32, 0, 0);
2885#undef DM_OPERATE
2886#endif
2887
2888/** DSP Bit/Manipulation Sub-class insns **/
2889target_ulong helper_bitrev(target_ulong rt)
2890{
2891    int32_t temp;
2892    uint32_t rd;
2893    int i;
2894
2895    temp = rt & MIPSDSP_LO;
2896    rd = 0;
2897    for (i = 0; i < 16; i++) {
2898        rd = (rd << 1) | (temp & 1);
2899        temp = temp >> 1;
2900    }
2901
2902    return (target_ulong)rd;
2903}
2904
2905#define BIT_INSV(name, posfilter, sizefilter, ret_type)         \
2906target_ulong helper_##name(CPUMIPSState *env, target_ulong rs,  \
2907                           target_ulong rt)                     \
2908{                                                               \
2909    uint32_t pos, size, msb, lsb;                               \
2910    target_ulong filter;                                        \
2911    target_ulong temp, temprs, temprt;                          \
2912    target_ulong dspc;                                          \
2913                                                                \
2914    dspc = env->active_tc.DSPControl;                           \
2915                                                                \
2916    pos  = dspc & posfilter;                                    \
2917    size = (dspc >> 7) & sizefilter;                            \
2918                                                                \
2919    msb  = pos + size - 1;                                      \
2920    lsb  = pos;                                                 \
2921                                                                \
2922    if (lsb > msb || (msb > TARGET_LONG_BITS)) {                \
2923        return rt;                                              \
2924    }                                                           \
2925                                                                \
2926    filter = ((int64_t)0x01 << size) - 1;                       \
2927    filter = filter << pos;                                     \
2928    temprs = (rs << pos) & filter;                              \
2929    temprt = rt & ~filter;                                      \
2930    temp = temprs | temprt;                                     \
2931                                                                \
2932    return (target_long)(ret_type)temp;                         \
2933}
2934
2935BIT_INSV(insv, 0x1F, 0x3F, int32_t);
2936#ifdef TARGET_MIPS64
2937BIT_INSV(dinsv, 0x7F, 0x3F, target_long);
2938#endif
2939
2940#undef BIT_INSV
2941
2942
2943/** DSP Compare-Pick Sub-class insns **/
2944#define CMP_HAS_RET(name, func, split_num, filter, bit_size) \
2945target_ulong helper_##name(target_ulong rs, target_ulong rt) \
2946{                                                       \
2947    uint32_t rs_t, rt_t;                                \
2948    uint8_t cc;                                         \
2949    uint32_t temp = 0;                                  \
2950    int i;                                              \
2951                                                        \
2952    for (i = 0; i < split_num; i++) {                   \
2953        rs_t = (rs >> (bit_size * i)) & filter;         \
2954        rt_t = (rt >> (bit_size * i)) & filter;         \
2955        cc = mipsdsp_##func(rs_t, rt_t);                \
2956        temp |= cc << i;                                \
2957    }                                                   \
2958                                                        \
2959    return (target_ulong)temp;                          \
2960}
2961
2962CMP_HAS_RET(cmpgu_eq_qb, cmpu_eq, 4, MIPSDSP_Q0, 8);
2963CMP_HAS_RET(cmpgu_lt_qb, cmpu_lt, 4, MIPSDSP_Q0, 8);
2964CMP_HAS_RET(cmpgu_le_qb, cmpu_le, 4, MIPSDSP_Q0, 8);
2965
2966#ifdef TARGET_MIPS64
2967CMP_HAS_RET(cmpgu_eq_ob, cmpu_eq, 8, MIPSDSP_Q0, 8);
2968CMP_HAS_RET(cmpgu_lt_ob, cmpu_lt, 8, MIPSDSP_Q0, 8);
2969CMP_HAS_RET(cmpgu_le_ob, cmpu_le, 8, MIPSDSP_Q0, 8);
2970#endif
2971
2972#undef CMP_HAS_RET
2973
2974
2975#define CMP_NO_RET(name, func, split_num, filter, bit_size) \
2976void helper_##name(target_ulong rs, target_ulong rt,        \
2977                            CPUMIPSState *env)              \
2978{                                                           \
2979    int##bit_size##_t rs_t, rt_t;                           \
2980    int##bit_size##_t flag = 0;                             \
2981    int##bit_size##_t cc;                                   \
2982    int i;                                                  \
2983                                                            \
2984    for (i = 0; i < split_num; i++) {                       \
2985        rs_t = (rs >> (bit_size * i)) & filter;             \
2986        rt_t = (rt >> (bit_size * i)) & filter;             \
2987                                                            \
2988        cc = mipsdsp_##func((int32_t)rs_t, (int32_t)rt_t);  \
2989        flag |= cc << i;                                    \
2990    }                                                       \
2991                                                            \
2992    set_DSPControl_24(flag, split_num, env);                \
2993}
2994
2995CMP_NO_RET(cmpu_eq_qb, cmpu_eq, 4, MIPSDSP_Q0, 8);
2996CMP_NO_RET(cmpu_lt_qb, cmpu_lt, 4, MIPSDSP_Q0, 8);
2997CMP_NO_RET(cmpu_le_qb, cmpu_le, 4, MIPSDSP_Q0, 8);
2998
2999CMP_NO_RET(cmp_eq_ph, cmp_eq, 2, MIPSDSP_LO, 16);
3000CMP_NO_RET(cmp_lt_ph, cmp_lt, 2, MIPSDSP_LO, 16);
3001CMP_NO_RET(cmp_le_ph, cmp_le, 2, MIPSDSP_LO, 16);
3002
3003#ifdef TARGET_MIPS64
3004CMP_NO_RET(cmpu_eq_ob, cmpu_eq, 8, MIPSDSP_Q0, 8);
3005CMP_NO_RET(cmpu_lt_ob, cmpu_lt, 8, MIPSDSP_Q0, 8);
3006CMP_NO_RET(cmpu_le_ob, cmpu_le, 8, MIPSDSP_Q0, 8);
3007
3008CMP_NO_RET(cmp_eq_qh, cmp_eq, 4, MIPSDSP_LO, 16);
3009CMP_NO_RET(cmp_lt_qh, cmp_lt, 4, MIPSDSP_LO, 16);
3010CMP_NO_RET(cmp_le_qh, cmp_le, 4, MIPSDSP_LO, 16);
3011
3012CMP_NO_RET(cmp_eq_pw, cmp_eq, 2, MIPSDSP_LLO, 32);
3013CMP_NO_RET(cmp_lt_pw, cmp_lt, 2, MIPSDSP_LLO, 32);
3014CMP_NO_RET(cmp_le_pw, cmp_le, 2, MIPSDSP_LLO, 32);
3015#endif
3016#undef CMP_NO_RET
3017
3018#if defined(TARGET_MIPS64)
3019
3020#define CMPGDU_OB(name) \
3021target_ulong helper_cmpgdu_##name##_ob(target_ulong rs, target_ulong rt, \
3022                                       CPUMIPSState *env)  \
3023{                                                     \
3024    int i;                                            \
3025    uint8_t rs_t, rt_t;                               \
3026    uint32_t cond;                                    \
3027                                                      \
3028    cond = 0;                                         \
3029                                                      \
3030    for (i = 0; i < 8; i++) {                         \
3031        rs_t = (rs >> (8 * i)) & MIPSDSP_Q0;          \
3032        rt_t = (rt >> (8 * i)) & MIPSDSP_Q0;          \
3033                                                      \
3034        if (mipsdsp_cmpu_##name(rs_t, rt_t)) {        \
3035            cond |= 0x01 << i;                        \
3036        }                                             \
3037    }                                                 \
3038                                                      \
3039    set_DSPControl_24(cond, 8, env);                  \
3040                                                      \
3041    return (uint64_t)cond;                            \
3042}
3043
3044CMPGDU_OB(eq)
3045CMPGDU_OB(lt)
3046CMPGDU_OB(le)
3047#undef CMPGDU_OB
3048#endif
3049
3050#define PICK_INSN(name, split_num, filter, bit_size, ret32bit) \
3051target_ulong helper_##name(target_ulong rs, target_ulong rt,   \
3052                            CPUMIPSState *env)                 \
3053{                                                              \
3054    uint32_t rs_t, rt_t;                                       \
3055    uint32_t cc;                                               \
3056    target_ulong dsp;                                          \
3057    int i;                                                     \
3058    target_ulong result = 0;                                   \
3059                                                               \
3060    dsp = env->active_tc.DSPControl;                           \
3061    for (i = 0; i < split_num; i++) {                          \
3062        rs_t = (rs >> (bit_size * i)) & filter;                \
3063        rt_t = (rt >> (bit_size * i)) & filter;                \
3064        cc = (dsp >> (24 + i)) & 0x01;                         \
3065        cc = cc == 1 ? rs_t : rt_t;                            \
3066                                                               \
3067        result |= (target_ulong)cc << (bit_size * i);          \
3068    }                                                          \
3069                                                               \
3070    if (ret32bit) {                                            \
3071        result = (target_long)(int32_t)(result & MIPSDSP_LLO); \
3072    }                                                          \
3073                                                               \
3074    return result;                                             \
3075}
3076
3077PICK_INSN(pick_qb, 4, MIPSDSP_Q0, 8, 1);
3078PICK_INSN(pick_ph, 2, MIPSDSP_LO, 16, 1);
3079
3080#ifdef TARGET_MIPS64
3081PICK_INSN(pick_ob, 8, MIPSDSP_Q0, 8, 0);
3082PICK_INSN(pick_qh, 4, MIPSDSP_LO, 16, 0);
3083PICK_INSN(pick_pw, 2, MIPSDSP_LLO, 32, 0);
3084#endif
3085#undef PICK_INSN
3086
3087target_ulong helper_packrl_ph(target_ulong rs, target_ulong rt)
3088{
3089    uint32_t rsl, rth;
3090
3091    rsl =  rs & MIPSDSP_LO;
3092    rth = (rt & MIPSDSP_HI) >> 16;
3093
3094    return (target_long)(int32_t)((rsl << 16) | rth);
3095}
3096
3097#if defined(TARGET_MIPS64)
3098target_ulong helper_packrl_pw(target_ulong rs, target_ulong rt)
3099{
3100    uint32_t rs0, rt1;
3101
3102    rs0 = rs & MIPSDSP_LLO;
3103    rt1 = (rt >> 32) & MIPSDSP_LLO;
3104
3105    return ((uint64_t)rs0 << 32) | (uint64_t)rt1;
3106}
3107#endif
3108
3109/** DSP Accumulator and DSPControl Access Sub-class insns **/
3110target_ulong helper_extr_w(target_ulong ac, target_ulong shift,
3111                           CPUMIPSState *env)
3112{
3113    int32_t tempI;
3114    int64_t tempDL[2];
3115
3116    shift = shift & 0x1F;
3117
3118    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
3119    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
3120        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
3121        set_DSPControl_overflow_flag(1, 23, env);
3122    }
3123
3124    tempI = (tempDL[0] >> 1) & MIPSDSP_LLO;
3125
3126    tempDL[0] += 1;
3127    if (tempDL[0] == 0) {
3128        tempDL[1] += 1;
3129    }
3130
3131    if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
3132        ((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
3133        set_DSPControl_overflow_flag(1, 23, env);
3134    }
3135
3136    return (target_long)tempI;
3137}
3138
3139target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift,
3140                             CPUMIPSState *env)
3141{
3142    int64_t tempDL[2];
3143
3144    shift = shift & 0x1F;
3145
3146    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
3147    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
3148        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
3149        set_DSPControl_overflow_flag(1, 23, env);
3150    }
3151
3152    tempDL[0] += 1;
3153    if (tempDL[0] == 0) {
3154        tempDL[1] += 1;
3155    }
3156
3157    if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
3158        ((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
3159        set_DSPControl_overflow_flag(1, 23, env);
3160    }
3161
3162    return (target_long)(int32_t)(tempDL[0] >> 1);
3163}
3164
3165target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift,
3166                              CPUMIPSState *env)
3167{
3168    int32_t tempI, temp64;
3169    int64_t tempDL[2];
3170
3171    shift = shift & 0x1F;
3172
3173    mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env);
3174    if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
3175        (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
3176        set_DSPControl_overflow_flag(1, 23, env);
3177    }
3178    tempDL[0] += 1;
3179    if (tempDL[0] == 0) {
3180        tempDL[1] += 1;
3181    }
3182    tempI = tempDL[0] >> 1;
3183
3184    if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
3185        ((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
3186        temp64 = tempDL[1] & 0x01;
3187        if (temp64 == 0) {
3188            tempI = 0x7FFFFFFF;
3189        } else {
3190            tempI = 0x80000000;
3191        }
3192        set_DSPControl_overflow_flag(1, 23, env);
3193    }
3194
3195    return (target_long)tempI;
3196}
3197
3198#if defined(TARGET_MIPS64)
3199target_ulong helper_dextr_w(target_ulong ac, target_ulong shift,
3200                            CPUMIPSState *env)
3201{
3202    uint64_t temp[3];
3203
3204    shift = shift & 0x3F;
3205
3206    mipsdsp_rndrashift_acc(temp, ac, shift, env);
3207
3208    return (int64_t)(int32_t)(temp[0] >> 1);
3209}
3210
3211target_ulong helper_dextr_r_w(target_ulong ac, target_ulong shift,
3212                              CPUMIPSState *env)
3213{
3214    uint64_t temp[3];
3215    uint32_t temp128;
3216
3217    shift = shift & 0x3F;
3218    mipsdsp_rndrashift_acc(temp, ac, shift, env);
3219
3220    temp[0] += 1;
3221    if (temp[0] == 0) {
3222        temp[1] += 1;
3223        if (temp[1] == 0) {
3224            temp[2] += 1;
3225        }
3226    }
3227
3228    temp128 = temp[2] & 0x01;
3229
3230    if ((temp128 != 0 || temp[1] != 0) &&
3231       (temp128 != 1 || temp[1] != ~0ull)) {
3232        set_DSPControl_overflow_flag(1, 23, env);
3233    }
3234
3235    return (int64_t)(int32_t)(temp[0] >> 1);
3236}
3237
3238target_ulong helper_dextr_rs_w(target_ulong ac, target_ulong shift,
3239                               CPUMIPSState *env)
3240{
3241    uint64_t temp[3];
3242    uint32_t temp128;
3243
3244    shift = shift & 0x3F;
3245    mipsdsp_rndrashift_acc(temp, ac, shift, env);
3246
3247    temp[0] += 1;
3248    if (temp[0] == 0) {
3249        temp[1] += 1;
3250        if (temp[1] == 0) {
3251            temp[2] += 1;
3252        }
3253    }
3254
3255    temp128 = temp[2] & 0x01;
3256
3257    if ((temp128 != 0 || temp[1] != 0) &&
3258       (temp128 != 1 || temp[1] != ~0ull)) {
3259        if (temp128 == 0) {
3260            temp[0] = 0x0FFFFFFFF;
3261        } else {
3262            temp[0] = 0x0100000000ULL;
3263        }
3264        set_DSPControl_overflow_flag(1, 23, env);
3265    }
3266
3267    return (int64_t)(int32_t)(temp[0] >> 1);
3268}
3269
3270target_ulong helper_dextr_l(target_ulong ac, target_ulong shift,
3271                            CPUMIPSState *env)
3272{
3273    uint64_t temp[3];
3274    target_ulong result;
3275
3276    shift = shift & 0x3F;
3277
3278    mipsdsp_rndrashift_acc(temp, ac, shift, env);
3279    result = (temp[1] << 63) | (temp[0] >> 1);
3280
3281    return result;
3282}
3283
3284target_ulong helper_dextr_r_l(target_ulong ac, target_ulong shift,
3285                              CPUMIPSState *env)
3286{
3287    uint64_t temp[3];
3288    uint32_t temp128;
3289    target_ulong result;
3290
3291    shift = shift & 0x3F;
3292    mipsdsp_rndrashift_acc(temp, ac, shift, env);
3293
3294    temp[0] += 1;
3295    if (temp[0] == 0) {
3296        temp[1] += 1;
3297        if (temp[1] == 0) {
3298            temp[2] += 1;
3299        }
3300    }
3301
3302    temp128 = temp[2] & 0x01;
3303
3304    if ((temp128 != 0 || temp[1] != 0) &&
3305       (temp128 != 1 || temp[1] != ~0ull)) {
3306        set_DSPControl_overflow_flag(1, 23, env);
3307    }
3308
3309    result = (temp[1] << 63) | (temp[0] >> 1);
3310
3311    return result;
3312}
3313
3314target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift,
3315                               CPUMIPSState *env)
3316{
3317    uint64_t temp[3];
3318    uint32_t temp128;
3319    target_ulong result;
3320
3321    shift = shift & 0x3F;
3322    mipsdsp_rndrashift_acc(temp, ac, shift, env);
3323
3324    temp[0] += 1;
3325    if (temp[0] == 0) {
3326        temp[1] += 1;
3327        if (temp[1] == 0) {
3328            temp[2] += 1;
3329        }
3330    }
3331
3332    temp128 = temp[2] & 0x01;
3333
3334    if ((temp128 != 0 || temp[1] != 0) &&
3335       (temp128 != 1 || temp[1] != ~0ull)) {
3336        if (temp128 == 0) {
3337            temp[1] &= ~0x00ull - 1;
3338            temp[0] |= ~0x00ull - 1;
3339        } else {
3340            temp[1] |= 0x01;
3341            temp[0] &= 0x01;
3342        }
3343        set_DSPControl_overflow_flag(1, 23, env);
3344    }
3345    result = (temp[1] << 63) | (temp[0] >> 1);
3346
3347    return result;
3348}
3349#endif
3350
3351target_ulong helper_extr_s_h(target_ulong ac, target_ulong shift,
3352                             CPUMIPSState *env)
3353{
3354    int64_t temp, acc;
3355
3356    shift = shift & 0x1F;
3357
3358    acc = ((int64_t)env->active_tc.HI[ac] << 32) |
3359          ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
3360
3361    temp = acc >> shift;
3362
3363    if (temp > (int64_t)0x7FFF) {
3364        temp = 0x00007FFF;
3365        set_DSPControl_overflow_flag(1, 23, env);
3366    } else if (temp < (int64_t)0xFFFFFFFFFFFF8000ULL) {
3367        temp = 0xFFFF8000;
3368        set_DSPControl_overflow_flag(1, 23, env);
3369    }
3370
3371    return (target_long)(int32_t)(temp & 0xFFFFFFFF);
3372}
3373
3374
3375#if defined(TARGET_MIPS64)
3376target_ulong helper_dextr_s_h(target_ulong ac, target_ulong shift,
3377                              CPUMIPSState *env)
3378{
3379    int64_t temp[2];
3380    uint32_t temp127;
3381
3382    shift = shift & 0x1F;
3383
3384    mipsdsp_rashift_acc((uint64_t *)temp, ac, shift, env);
3385
3386    temp127 = (temp[1] >> 63) & 0x01;
3387
3388    if ((temp127 == 0) && (temp[1] > 0 || temp[0] > 32767)) {
3389        temp[0] &= 0xFFFF0000;
3390        temp[0] |= 0x00007FFF;
3391        set_DSPControl_overflow_flag(1, 23, env);
3392    } else if ((temp127 == 1) &&
3393            (temp[1] < 0xFFFFFFFFFFFFFFFFll
3394             || temp[0] < 0xFFFFFFFFFFFF1000ll)) {
3395        temp[0] &= 0xFFFF0000;
3396        temp[0] |= 0x00008000;
3397        set_DSPControl_overflow_flag(1, 23, env);
3398    }
3399
3400    return (int64_t)(int16_t)(temp[0] & MIPSDSP_LO);
3401}
3402
3403#endif
3404
3405target_ulong helper_extp(target_ulong ac, target_ulong size, CPUMIPSState *env)
3406{
3407    int32_t start_pos;
3408    int sub;
3409    uint32_t temp;
3410    uint64_t acc;
3411
3412    size = size & 0x1F;
3413
3414    temp = 0;
3415    start_pos = get_DSPControl_pos(env);
3416    sub = start_pos - (size + 1);
3417    if (sub >= -1) {
3418        acc = ((uint64_t)env->active_tc.HI[ac] << 32) |
3419              ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
3420        temp = (acc >> (start_pos - size)) & (~0U >> (31 - size));
3421        set_DSPControl_efi(0, env);
3422    } else {
3423        set_DSPControl_efi(1, env);
3424    }
3425
3426    return (target_ulong)temp;
3427}
3428
3429target_ulong helper_extpdp(target_ulong ac, target_ulong size,
3430                           CPUMIPSState *env)
3431{
3432    int32_t start_pos;
3433    int sub;
3434    uint32_t temp;
3435    uint64_t acc;
3436
3437    size = size & 0x1F;
3438    temp = 0;
3439    start_pos = get_DSPControl_pos(env);
3440    sub = start_pos - (size + 1);
3441    if (sub >= -1) {
3442        acc  = ((uint64_t)env->active_tc.HI[ac] << 32) |
3443               ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
3444        temp = extract64(acc, start_pos - size, size + 1);
3445
3446        set_DSPControl_pos(sub, env);
3447        set_DSPControl_efi(0, env);
3448    } else {
3449        set_DSPControl_efi(1, env);
3450    }
3451
3452    return (target_ulong)temp;
3453}
3454
3455
3456#if defined(TARGET_MIPS64)
3457target_ulong helper_dextp(target_ulong ac, target_ulong size, CPUMIPSState *env)
3458{
3459    int start_pos;
3460    int len;
3461    int sub;
3462    uint64_t tempB, tempA;
3463    uint64_t temp;
3464
3465    temp = 0;
3466
3467    size = size & 0x3F;
3468    start_pos = get_DSPControl_pos(env);
3469    len = start_pos - size;
3470    tempB = env->active_tc.HI[ac];
3471    tempA = env->active_tc.LO[ac];
3472
3473    sub = start_pos - (size + 1);
3474
3475    if (sub >= -1) {
3476        temp = (tempB << (64 - len)) | (tempA >> len);
3477        temp = temp & ((0x01 << (size + 1)) - 1);
3478        set_DSPControl_efi(0, env);
3479    } else {
3480        set_DSPControl_efi(1, env);
3481    }
3482
3483    return temp;
3484}
3485
3486target_ulong helper_dextpdp(target_ulong ac, target_ulong size,
3487                            CPUMIPSState *env)
3488{
3489    int start_pos;
3490    int len;
3491    int sub;
3492    uint64_t tempB, tempA;
3493    uint64_t temp;
3494
3495    temp = 0;
3496    size = size & 0x3F;
3497    start_pos = get_DSPControl_pos(env);
3498    len = start_pos - size;
3499    tempB = env->active_tc.HI[ac];
3500    tempA = env->active_tc.LO[ac];
3501
3502    sub = start_pos - (size + 1);
3503
3504    if (sub >= -1) {
3505        temp = (tempB << (64 - len)) | (tempA >> len);
3506        temp = temp & ((0x01 << (size + 1)) - 1);
3507        set_DSPControl_pos(sub, env);
3508        set_DSPControl_efi(0, env);
3509    } else {
3510        set_DSPControl_efi(1, env);
3511    }
3512
3513    return temp;
3514}
3515
3516#endif
3517
3518void helper_shilo(target_ulong ac, target_ulong rs, CPUMIPSState *env)
3519{
3520    int8_t  rs5_0;
3521    uint64_t temp, acc;
3522
3523    rs5_0 = rs & 0x3F;
3524    rs5_0 = (int8_t)(rs5_0 << 2) >> 2;
3525
3526    if (unlikely(rs5_0 == 0)) {
3527        return;
3528    }
3529
3530    acc   = (((uint64_t)env->active_tc.HI[ac] << 32) & MIPSDSP_LHI) |
3531            ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO);
3532
3533    if (rs5_0 > 0) {
3534        temp = acc >> rs5_0;
3535    } else {
3536        temp = acc << -rs5_0;
3537    }
3538
3539    env->active_tc.HI[ac] = (target_ulong)(int32_t)((temp & MIPSDSP_LHI) >> 32);
3540    env->active_tc.LO[ac] = (target_ulong)(int32_t)(temp & MIPSDSP_LLO);
3541}
3542
3543#if defined(TARGET_MIPS64)
3544void helper_dshilo(target_ulong shift, target_ulong ac, CPUMIPSState *env)
3545{
3546    int8_t shift_t;
3547    uint64_t tempB, tempA;
3548
3549    shift_t = (int8_t)(shift << 1) >> 1;
3550
3551    tempB = env->active_tc.HI[ac];
3552    tempA = env->active_tc.LO[ac];
3553
3554    if (shift_t != 0) {
3555        if (shift_t >= 0) {
3556            tempA = (tempB << (64 - shift_t)) | (tempA >> shift_t);
3557            tempB = tempB >> shift_t;
3558        } else {
3559            shift_t = -shift_t;
3560            tempB = (tempB << shift_t) | (tempA >> (64 - shift_t));
3561            tempA = tempA << shift_t;
3562        }
3563    }
3564
3565    env->active_tc.HI[ac] = tempB;
3566    env->active_tc.LO[ac] = tempA;
3567}
3568
3569#endif
3570void helper_mthlip(target_ulong ac, target_ulong rs, CPUMIPSState *env)
3571{
3572    int32_t tempA, tempB, pos;
3573
3574    tempA = rs;
3575    tempB = env->active_tc.LO[ac];
3576    env->active_tc.HI[ac] = (target_long)tempB;
3577    env->active_tc.LO[ac] = (target_long)tempA;
3578    pos = get_DSPControl_pos(env);
3579
3580    if (pos > 32) {
3581        return;
3582    } else {
3583        set_DSPControl_pos(pos + 32, env);
3584    }
3585}
3586
3587#if defined(TARGET_MIPS64)
3588void helper_dmthlip(target_ulong rs, target_ulong ac, CPUMIPSState *env)
3589{
3590    uint8_t ac_t;
3591    uint8_t pos;
3592    uint64_t tempB, tempA;
3593
3594    ac_t = ac & 0x3;
3595
3596    tempA = rs;
3597    tempB = env->active_tc.LO[ac_t];
3598
3599    env->active_tc.HI[ac_t] = tempB;
3600    env->active_tc.LO[ac_t] = tempA;
3601
3602    pos = get_DSPControl_pos(env);
3603
3604    if (pos <= 64) {
3605        pos = pos + 64;
3606        set_DSPControl_pos(pos, env);
3607    }
3608}
3609#endif
3610
3611void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env)
3612{
3613    uint8_t  mask[6];
3614    uint8_t  i;
3615    uint32_t newbits, overwrite;
3616    target_ulong dsp;
3617
3618    newbits   = 0x00;
3619    overwrite = 0xFFFFFFFF;
3620    dsp = env->active_tc.DSPControl;
3621
3622    for (i = 0; i < 6; i++) {
3623        mask[i] = (mask_num >> i) & 0x01;
3624    }
3625
3626    if (mask[0] == 1) {
3627#if defined(TARGET_MIPS64)
3628        overwrite &= 0xFFFFFF80;
3629        newbits   &= 0xFFFFFF80;
3630        newbits   |= 0x0000007F & rs;
3631#else
3632        overwrite &= 0xFFFFFFC0;
3633        newbits   &= 0xFFFFFFC0;
3634        newbits   |= 0x0000003F & rs;
3635#endif
3636    }
3637
3638    if (mask[1] == 1) {
3639        overwrite &= 0xFFFFE07F;
3640        newbits   &= 0xFFFFE07F;
3641        newbits   |= 0x00001F80 & rs;
3642    }
3643
3644    if (mask[2] == 1) {
3645        overwrite &= 0xFFFFDFFF;
3646        newbits   &= 0xFFFFDFFF;
3647        newbits   |= 0x00002000 & rs;
3648    }
3649
3650    if (mask[3] == 1) {
3651        overwrite &= 0xFF00FFFF;
3652        newbits   &= 0xFF00FFFF;
3653        newbits   |= 0x00FF0000 & rs;
3654    }
3655
3656    if (mask[4] == 1) {
3657        overwrite &= 0x00FFFFFF;
3658        newbits   &= 0x00FFFFFF;
3659#if defined(TARGET_MIPS64)
3660        newbits   |= 0xFF000000 & rs;
3661#else
3662        newbits   |= 0x0F000000 & rs;
3663#endif
3664    }
3665
3666    if (mask[5] == 1) {
3667        overwrite &= 0xFFFFBFFF;
3668        newbits   &= 0xFFFFBFFF;
3669        newbits   |= 0x00004000 & rs;
3670    }
3671
3672    dsp = dsp & overwrite;
3673    dsp = dsp | newbits;
3674    env->active_tc.DSPControl = dsp;
3675}
3676
3677void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env)
3678{
3679    return cpu_wrdsp(rs, mask_num, env);
3680}
3681
3682uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env)
3683{
3684    uint8_t  mask[6];
3685    uint32_t ruler, i;
3686    target_ulong temp;
3687    target_ulong dsp;
3688
3689    ruler = 0x01;
3690    for (i = 0; i < 6; i++) {
3691        mask[i] = (mask_num & ruler) >> i ;
3692        ruler = ruler << 1;
3693    }
3694
3695    temp  = 0x00;
3696    dsp = env->active_tc.DSPControl;
3697
3698    if (mask[0] == 1) {
3699#if defined(TARGET_MIPS64)
3700        temp |= dsp & 0x7F;
3701#else
3702        temp |= dsp & 0x3F;
3703#endif
3704    }
3705
3706    if (mask[1] == 1) {
3707        temp |= dsp & 0x1F80;
3708    }
3709
3710    if (mask[2] == 1) {
3711        temp |= dsp & 0x2000;
3712    }
3713
3714    if (mask[3] == 1) {
3715        temp |= dsp & 0x00FF0000;
3716    }
3717
3718    if (mask[4] == 1) {
3719#if defined(TARGET_MIPS64)
3720        temp |= dsp & 0xFF000000;
3721#else
3722        temp |= dsp & 0x0F000000;
3723#endif
3724    }
3725
3726    if (mask[5] == 1) {
3727        temp |= dsp & 0x4000;
3728    }
3729
3730    return temp;
3731}
3732
3733target_ulong helper_rddsp(target_ulong mask_num, CPUMIPSState *env)
3734{
3735    return cpu_rddsp(mask_num, env);
3736}
3737
3738
3739#undef MIPSDSP_LHI
3740#undef MIPSDSP_LLO
3741#undef MIPSDSP_HI
3742#undef MIPSDSP_LO
3743#undef MIPSDSP_Q3
3744#undef MIPSDSP_Q2
3745#undef MIPSDSP_Q1
3746#undef MIPSDSP_Q0
3747
3748#undef MIPSDSP_SPLIT32_8
3749#undef MIPSDSP_SPLIT32_16
3750
3751#undef MIPSDSP_RETURN32_8
3752#undef MIPSDSP_RETURN32_16
3753
3754#ifdef TARGET_MIPS64
3755#undef MIPSDSP_SPLIT64_16
3756#undef MIPSDSP_SPLIT64_32
3757#undef MIPSDSP_RETURN64_16
3758#undef MIPSDSP_RETURN64_32
3759#endif
3760