]> git.proxmox.com Git - qemu.git/blame - target-mips/dsp_helper.c
target-mips: Add ASE DSP internal functions
[qemu.git] / target-mips / dsp_helper.c
CommitLineData
235eb015
JL
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
27static 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
33static inline void set_DSPControl_carryflag(uint32_t flag, CPUMIPSState *env)
34{
35 env->active_tc.DSPControl |= (target_ulong)flag << 13;
36}
37
38static inline uint32_t get_DSPControl_carryflag(CPUMIPSState *env)
39{
40 return (env->active_tc.DSPControl >> 13) & 0x01;
41}
42
43static 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
54static 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
63static 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
78static 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
94static 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) \
101static 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}
111DO_MIPS_SAT_ABS(8)
112DO_MIPS_SAT_ABS(16)
113DO_MIPS_SAT_ABS(32)
114#undef DO_MIPS_SAT_ABS
115
116/* get sum value */
117static 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
130static 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
149static 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
168static 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
181static 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
195static 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
212static 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
229static 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. */
274static 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
301static 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
327static 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
342static inline int32_t mipsdsp_mul_u16_u16(int32_t a, int32_t b)
343{
344 return a * b;
345}
346
347static inline int32_t mipsdsp_mul_i32_i32(int32_t a, int32_t b)
348{
349 return a * b;
350}
351
352static 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
371static 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 */
387static inline uint8_t mipsdsp_rshift_u8(uint8_t a, target_ulong mov)
388{
389 return a >> mov;
390}
391
392static inline uint16_t mipsdsp_rshift_u16(uint16_t a, target_ulong mov)
393{
394 return a >> mov;
395}
396
397static inline int8_t mipsdsp_rashift8(int8_t a, target_ulong mov)
398{
399 return a >> mov;
400}
401
402static inline int16_t mipsdsp_rashift16(int16_t a, target_ulong mov)
403{
404 return a >> mov;
405}
406
407static inline int32_t mipsdsp_rashift32(int32_t a, target_ulong mov)
408{
409 return a >> mov;
410}
411
412static 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 */
422static 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
432static 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
441static 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
451static 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
460static 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
469static 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
478static 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
487static 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. */
517static 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 */
536static 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.*/
557static 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
583static 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
598static 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
613static inline uint16_t mipsdsp_mul_u8_u8(uint8_t a, uint8_t b)
614{
615 return (uint16_t)a * (uint16_t)b;
616}
617
618static 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
632static inline uint64_t mipsdsp_mul_u32_u32(uint32_t a, uint32_t b)
633{
634 return (uint64_t)a * (uint64_t)b;
635}
636
637static 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
653static 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
669static 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
684static 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
706static 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
729static 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
754static 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
771static 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
797static 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
823static 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
836static 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
849static 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
863static 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
875static 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
893static 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
911static 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
920static 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
930static 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
939static 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
949static 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
963static 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
980static 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
994static 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
1009static 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
1021static 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
1034static inline int32_t mipsdsp_cmp_eq(int32_t a, int32_t b)
1035{
1036 return a == b;
1037}
1038
1039static inline int32_t mipsdsp_cmp_le(int32_t a, int32_t b)
1040{
1041 return a <= b;
1042}
1043
1044static inline int32_t mipsdsp_cmp_lt(int32_t a, int32_t b)
1045{
1046 return a < b;
1047}
1048
1049static inline int32_t mipsdsp_cmpu_eq(uint32_t a, uint32_t b)
1050{
1051 return a == b;
1052}
1053
1054static inline int32_t mipsdsp_cmpu_le(uint32_t a, uint32_t b)
1055{
1056 return a <= b;
1057}
1058
1059static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b)
1060{
1061 return a < b;
1062}
1063/*** MIPS DSP internal functions end ***/