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