]> git.proxmox.com Git - qemu.git/blob - target-arm/op.c
ARM TCG conversion 5/16.
[qemu.git] / target-arm / op.c
1 /*
2 * ARM micro operations
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2005-2007 CodeSourcery, LLC
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 #include "exec.h"
22
23 void OPPROTO op_addl_T0_T1_cc(void)
24 {
25 unsigned int src1;
26 src1 = T0;
27 T0 += T1;
28 env->NZF = T0;
29 env->CF = T0 < src1;
30 env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
31 }
32
33 void OPPROTO op_adcl_T0_T1_cc(void)
34 {
35 unsigned int src1;
36 src1 = T0;
37 if (!env->CF) {
38 T0 += T1;
39 env->CF = T0 < src1;
40 } else {
41 T0 += T1 + 1;
42 env->CF = T0 <= src1;
43 }
44 env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
45 env->NZF = T0;
46 FORCE_RET();
47 }
48
49 #define OPSUB(sub, sbc, res, T0, T1) \
50 \
51 void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
52 { \
53 unsigned int src1; \
54 src1 = T0; \
55 T0 -= T1; \
56 env->NZF = T0; \
57 env->CF = src1 >= T1; \
58 env->VF = (src1 ^ T1) & (src1 ^ T0); \
59 res = T0; \
60 } \
61 \
62 void OPPROTO op_ ## sbc ## l_T0_T1(void) \
63 { \
64 res = T0 - T1 + env->CF - 1; \
65 } \
66 \
67 void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
68 { \
69 unsigned int src1; \
70 src1 = T0; \
71 if (!env->CF) { \
72 T0 = T0 - T1 - 1; \
73 env->CF = src1 > T1; \
74 } else { \
75 T0 = T0 - T1; \
76 env->CF = src1 >= T1; \
77 } \
78 env->VF = (src1 ^ T1) & (src1 ^ T0); \
79 env->NZF = T0; \
80 res = T0; \
81 FORCE_RET(); \
82 }
83
84 OPSUB(sub, sbc, T0, T0, T1)
85
86 OPSUB(rsb, rsc, T0, T1, T0)
87
88 #define EIP (env->regs[15])
89
90 void OPPROTO op_test_eq(void)
91 {
92 if (env->NZF == 0)
93 GOTO_LABEL_PARAM(1);;
94 FORCE_RET();
95 }
96
97 void OPPROTO op_test_ne(void)
98 {
99 if (env->NZF != 0)
100 GOTO_LABEL_PARAM(1);;
101 FORCE_RET();
102 }
103
104 void OPPROTO op_test_cs(void)
105 {
106 if (env->CF != 0)
107 GOTO_LABEL_PARAM(1);
108 FORCE_RET();
109 }
110
111 void OPPROTO op_test_cc(void)
112 {
113 if (env->CF == 0)
114 GOTO_LABEL_PARAM(1);
115 FORCE_RET();
116 }
117
118 void OPPROTO op_test_mi(void)
119 {
120 if ((env->NZF & 0x80000000) != 0)
121 GOTO_LABEL_PARAM(1);
122 FORCE_RET();
123 }
124
125 void OPPROTO op_test_pl(void)
126 {
127 if ((env->NZF & 0x80000000) == 0)
128 GOTO_LABEL_PARAM(1);
129 FORCE_RET();
130 }
131
132 void OPPROTO op_test_vs(void)
133 {
134 if ((env->VF & 0x80000000) != 0)
135 GOTO_LABEL_PARAM(1);
136 FORCE_RET();
137 }
138
139 void OPPROTO op_test_vc(void)
140 {
141 if ((env->VF & 0x80000000) == 0)
142 GOTO_LABEL_PARAM(1);
143 FORCE_RET();
144 }
145
146 void OPPROTO op_test_hi(void)
147 {
148 if (env->CF != 0 && env->NZF != 0)
149 GOTO_LABEL_PARAM(1);
150 FORCE_RET();
151 }
152
153 void OPPROTO op_test_ls(void)
154 {
155 if (env->CF == 0 || env->NZF == 0)
156 GOTO_LABEL_PARAM(1);
157 FORCE_RET();
158 }
159
160 void OPPROTO op_test_ge(void)
161 {
162 if (((env->VF ^ env->NZF) & 0x80000000) == 0)
163 GOTO_LABEL_PARAM(1);
164 FORCE_RET();
165 }
166
167 void OPPROTO op_test_lt(void)
168 {
169 if (((env->VF ^ env->NZF) & 0x80000000) != 0)
170 GOTO_LABEL_PARAM(1);
171 FORCE_RET();
172 }
173
174 void OPPROTO op_test_gt(void)
175 {
176 if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
177 GOTO_LABEL_PARAM(1);
178 FORCE_RET();
179 }
180
181 void OPPROTO op_test_le(void)
182 {
183 if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
184 GOTO_LABEL_PARAM(1);
185 FORCE_RET();
186 }
187
188 void OPPROTO op_test_T0(void)
189 {
190 if (T0)
191 GOTO_LABEL_PARAM(1);
192 FORCE_RET();
193 }
194 void OPPROTO op_testn_T0(void)
195 {
196 if (!T0)
197 GOTO_LABEL_PARAM(1);
198 FORCE_RET();
199 }
200
201 void OPPROTO op_movl_T0_cpsr(void)
202 {
203 /* Execution state bits always read as zero. */
204 T0 = cpsr_read(env) & ~CPSR_EXEC;
205 FORCE_RET();
206 }
207
208 void OPPROTO op_movl_T0_spsr(void)
209 {
210 T0 = env->spsr;
211 }
212
213 void OPPROTO op_movl_spsr_T0(void)
214 {
215 uint32_t mask = PARAM1;
216 env->spsr = (env->spsr & ~mask) | (T0 & mask);
217 }
218
219 void OPPROTO op_movl_cpsr_T0(void)
220 {
221 cpsr_write(env, T0, PARAM1);
222 FORCE_RET();
223 }
224
225 /* 48 bit signed mul, top 32 bits */
226 void OPPROTO op_imulw_T0_T1(void)
227 {
228 uint64_t res;
229 res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
230 T0 = res >> 16;
231 }
232
233 void OPPROTO op_addq_T0_T1(void)
234 {
235 uint64_t res;
236 res = ((uint64_t)T1 << 32) | T0;
237 res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
238 T1 = res >> 32;
239 T0 = res;
240 }
241
242 void OPPROTO op_addq_lo_T0_T1(void)
243 {
244 uint64_t res;
245 res = ((uint64_t)T1 << 32) | T0;
246 res += (uint64_t)(env->regs[PARAM1]);
247 T1 = res >> 32;
248 T0 = res;
249 }
250
251 /* Dual 16-bit accumulate. */
252 void OPPROTO op_addq_T0_T1_dual(void)
253 {
254 uint64_t res;
255 res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
256 res += (int32_t)T0;
257 res += (int32_t)T1;
258 env->regs[PARAM1] = (uint32_t)res;
259 env->regs[PARAM2] = res >> 32;
260 }
261
262 /* Dual 16-bit subtract accumulate. */
263 void OPPROTO op_subq_T0_T1_dual(void)
264 {
265 uint64_t res;
266 res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
267 res += (int32_t)T0;
268 res -= (int32_t)T1;
269 env->regs[PARAM1] = (uint32_t)res;
270 env->regs[PARAM2] = res >> 32;
271 }
272
273 void OPPROTO op_logicq_cc(void)
274 {
275 env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
276 }
277
278 /* memory access */
279
280 #define MEMSUFFIX _raw
281 #include "op_mem.h"
282
283 #if !defined(CONFIG_USER_ONLY)
284 #define MEMSUFFIX _user
285 #include "op_mem.h"
286 #define MEMSUFFIX _kernel
287 #include "op_mem.h"
288 #endif
289
290 void OPPROTO op_clrex(void)
291 {
292 cpu_lock();
293 helper_clrex(env);
294 cpu_unlock();
295 }
296
297 /* T1 based, use T0 as shift count */
298
299 void OPPROTO op_shll_T1_T0(void)
300 {
301 int shift;
302 shift = T0 & 0xff;
303 if (shift >= 32)
304 T1 = 0;
305 else
306 T1 = T1 << shift;
307 FORCE_RET();
308 }
309
310 void OPPROTO op_shrl_T1_T0(void)
311 {
312 int shift;
313 shift = T0 & 0xff;
314 if (shift >= 32)
315 T1 = 0;
316 else
317 T1 = (uint32_t)T1 >> shift;
318 FORCE_RET();
319 }
320
321 void OPPROTO op_sarl_T1_T0(void)
322 {
323 int shift;
324 shift = T0 & 0xff;
325 if (shift >= 32)
326 shift = 31;
327 T1 = (int32_t)T1 >> shift;
328 }
329
330 void OPPROTO op_rorl_T1_T0(void)
331 {
332 int shift;
333 shift = T0 & 0x1f;
334 if (shift) {
335 T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
336 }
337 FORCE_RET();
338 }
339
340 /* T1 based, use T0 as shift count and compute CF */
341
342 void OPPROTO op_shll_T1_T0_cc(void)
343 {
344 int shift;
345 shift = T0 & 0xff;
346 if (shift >= 32) {
347 if (shift == 32)
348 env->CF = T1 & 1;
349 else
350 env->CF = 0;
351 T1 = 0;
352 } else if (shift != 0) {
353 env->CF = (T1 >> (32 - shift)) & 1;
354 T1 = T1 << shift;
355 }
356 FORCE_RET();
357 }
358
359 void OPPROTO op_shrl_T1_T0_cc(void)
360 {
361 int shift;
362 shift = T0 & 0xff;
363 if (shift >= 32) {
364 if (shift == 32)
365 env->CF = (T1 >> 31) & 1;
366 else
367 env->CF = 0;
368 T1 = 0;
369 } else if (shift != 0) {
370 env->CF = (T1 >> (shift - 1)) & 1;
371 T1 = (uint32_t)T1 >> shift;
372 }
373 FORCE_RET();
374 }
375
376 void OPPROTO op_sarl_T1_T0_cc(void)
377 {
378 int shift;
379 shift = T0 & 0xff;
380 if (shift >= 32) {
381 env->CF = (T1 >> 31) & 1;
382 T1 = (int32_t)T1 >> 31;
383 } else if (shift != 0) {
384 env->CF = (T1 >> (shift - 1)) & 1;
385 T1 = (int32_t)T1 >> shift;
386 }
387 FORCE_RET();
388 }
389
390 void OPPROTO op_rorl_T1_T0_cc(void)
391 {
392 int shift1, shift;
393 shift1 = T0 & 0xff;
394 shift = shift1 & 0x1f;
395 if (shift == 0) {
396 if (shift1 != 0)
397 env->CF = (T1 >> 31) & 1;
398 } else {
399 env->CF = (T1 >> (shift - 1)) & 1;
400 T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
401 }
402 FORCE_RET();
403 }
404
405 /* exceptions */
406
407 void OPPROTO op_swi(void)
408 {
409 env->exception_index = EXCP_SWI;
410 cpu_loop_exit();
411 }
412
413 void OPPROTO op_undef_insn(void)
414 {
415 env->exception_index = EXCP_UDEF;
416 cpu_loop_exit();
417 }
418
419 void OPPROTO op_debug(void)
420 {
421 env->exception_index = EXCP_DEBUG;
422 cpu_loop_exit();
423 }
424
425 void OPPROTO op_wfi(void)
426 {
427 env->exception_index = EXCP_HLT;
428 env->halted = 1;
429 cpu_loop_exit();
430 }
431
432 void OPPROTO op_bkpt(void)
433 {
434 env->exception_index = EXCP_BKPT;
435 cpu_loop_exit();
436 }
437
438 void OPPROTO op_exception_exit(void)
439 {
440 env->exception_index = EXCP_EXCEPTION_EXIT;
441 cpu_loop_exit();
442 }
443
444 /* VFP support. We follow the convention used for VFP instrunctions:
445 Single precition routines have a "s" suffix, double precision a
446 "d" suffix. */
447
448 #define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void)
449
450 #define VFP_BINOP(name) \
451 VFP_OP(name, s) \
452 { \
453 FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \
454 } \
455 VFP_OP(name, d) \
456 { \
457 FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \
458 }
459 VFP_BINOP(add)
460 VFP_BINOP(sub)
461 VFP_BINOP(mul)
462 VFP_BINOP(div)
463 #undef VFP_BINOP
464
465 #define VFP_HELPER(name) \
466 VFP_OP(name, s) \
467 { \
468 do_vfp_##name##s(); \
469 } \
470 VFP_OP(name, d) \
471 { \
472 do_vfp_##name##d(); \
473 }
474 VFP_HELPER(abs)
475 VFP_HELPER(sqrt)
476 VFP_HELPER(cmp)
477 VFP_HELPER(cmpe)
478 #undef VFP_HELPER
479
480 /* XXX: Will this do the right thing for NANs. Should invert the signbit
481 without looking at the rest of the value. */
482 VFP_OP(neg, s)
483 {
484 FT0s = float32_chs(FT0s);
485 }
486
487 VFP_OP(neg, d)
488 {
489 FT0d = float64_chs(FT0d);
490 }
491
492 VFP_OP(F1_ld0, s)
493 {
494 union {
495 uint32_t i;
496 float32 s;
497 } v;
498 v.i = 0;
499 FT1s = v.s;
500 }
501
502 VFP_OP(F1_ld0, d)
503 {
504 union {
505 uint64_t i;
506 float64 d;
507 } v;
508 v.i = 0;
509 FT1d = v.d;
510 }
511
512 /* Helper routines to perform bitwise copies between float and int. */
513 static inline float32 vfp_itos(uint32_t i)
514 {
515 union {
516 uint32_t i;
517 float32 s;
518 } v;
519
520 v.i = i;
521 return v.s;
522 }
523
524 static inline uint32_t vfp_stoi(float32 s)
525 {
526 union {
527 uint32_t i;
528 float32 s;
529 } v;
530
531 v.s = s;
532 return v.i;
533 }
534
535 static inline float64 vfp_itod(uint64_t i)
536 {
537 union {
538 uint64_t i;
539 float64 d;
540 } v;
541
542 v.i = i;
543 return v.d;
544 }
545
546 static inline uint64_t vfp_dtoi(float64 d)
547 {
548 union {
549 uint64_t i;
550 float64 d;
551 } v;
552
553 v.d = d;
554 return v.i;
555 }
556
557 /* Integer to float conversion. */
558 VFP_OP(uito, s)
559 {
560 FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
561 }
562
563 VFP_OP(uito, d)
564 {
565 FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
566 }
567
568 VFP_OP(sito, s)
569 {
570 FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
571 }
572
573 VFP_OP(sito, d)
574 {
575 FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
576 }
577
578 /* Float to integer conversion. */
579 VFP_OP(toui, s)
580 {
581 FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status));
582 }
583
584 VFP_OP(toui, d)
585 {
586 FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status));
587 }
588
589 VFP_OP(tosi, s)
590 {
591 FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status));
592 }
593
594 VFP_OP(tosi, d)
595 {
596 FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status));
597 }
598
599 /* TODO: Set rounding mode properly. */
600 VFP_OP(touiz, s)
601 {
602 FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status));
603 }
604
605 VFP_OP(touiz, d)
606 {
607 FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status));
608 }
609
610 VFP_OP(tosiz, s)
611 {
612 FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status));
613 }
614
615 VFP_OP(tosiz, d)
616 {
617 FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status));
618 }
619
620 /* floating point conversion */
621 VFP_OP(fcvtd, s)
622 {
623 FT0d = float32_to_float64(FT0s, &env->vfp.fp_status);
624 }
625
626 VFP_OP(fcvts, d)
627 {
628 FT0s = float64_to_float32(FT0d, &env->vfp.fp_status);
629 }
630
631 /* VFP3 fixed point conversion. */
632 #define VFP_CONV_FIX(name, p, ftype, itype, sign) \
633 VFP_OP(name##to, p) \
634 { \
635 ftype tmp; \
636 tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \
637 &env->vfp.fp_status); \
638 FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \
639 } \
640 VFP_OP(to##name, p) \
641 { \
642 ftype tmp; \
643 tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \
644 FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \
645 &env->vfp.fp_status)); \
646 }
647
648 VFP_CONV_FIX(sh, d, float64, int16, )
649 VFP_CONV_FIX(sl, d, float64, int32, )
650 VFP_CONV_FIX(uh, d, float64, uint16, u)
651 VFP_CONV_FIX(ul, d, float64, uint32, u)
652 VFP_CONV_FIX(sh, s, float32, int16, )
653 VFP_CONV_FIX(sl, s, float32, int32, )
654 VFP_CONV_FIX(uh, s, float32, uint16, u)
655 VFP_CONV_FIX(ul, s, float32, uint32, u)
656
657 /* Get and Put values from registers. */
658 VFP_OP(getreg_F0, d)
659 {
660 FT0d = *(float64 *)((char *) env + PARAM1);
661 }
662
663 VFP_OP(getreg_F0, s)
664 {
665 FT0s = *(float32 *)((char *) env + PARAM1);
666 }
667
668 VFP_OP(getreg_F1, d)
669 {
670 FT1d = *(float64 *)((char *) env + PARAM1);
671 }
672
673 VFP_OP(getreg_F1, s)
674 {
675 FT1s = *(float32 *)((char *) env + PARAM1);
676 }
677
678 VFP_OP(setreg_F0, d)
679 {
680 *(float64 *)((char *) env + PARAM1) = FT0d;
681 }
682
683 VFP_OP(setreg_F0, s)
684 {
685 *(float32 *)((char *) env + PARAM1) = FT0s;
686 }
687
688 void OPPROTO op_vfp_movl_T0_fpscr(void)
689 {
690 do_vfp_get_fpscr ();
691 }
692
693 void OPPROTO op_vfp_movl_T0_fpscr_flags(void)
694 {
695 T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28);
696 }
697
698 void OPPROTO op_vfp_movl_fpscr_T0(void)
699 {
700 do_vfp_set_fpscr();
701 }
702
703 void OPPROTO op_vfp_movl_T0_xreg(void)
704 {
705 T0 = env->vfp.xregs[PARAM1];
706 }
707
708 void OPPROTO op_vfp_movl_xreg_T0(void)
709 {
710 env->vfp.xregs[PARAM1] = T0;
711 }
712
713 /* Move between FT0s to T0 */
714 void OPPROTO op_vfp_mrs(void)
715 {
716 T0 = vfp_stoi(FT0s);
717 }
718
719 void OPPROTO op_vfp_msr(void)
720 {
721 FT0s = vfp_itos(T0);
722 }
723
724 /* Move between FT0d and {T0,T1} */
725 void OPPROTO op_vfp_mrrd(void)
726 {
727 CPU_DoubleU u;
728
729 u.d = FT0d;
730 T0 = u.l.lower;
731 T1 = u.l.upper;
732 }
733
734 void OPPROTO op_vfp_mdrr(void)
735 {
736 CPU_DoubleU u;
737
738 u.l.lower = T0;
739 u.l.upper = T1;
740 FT0d = u.d;
741 }
742
743 /* Load immediate. PARAM1 is the 32 most significant bits of the value. */
744 void OPPROTO op_vfp_fconstd(void)
745 {
746 CPU_DoubleU u;
747 u.l.upper = PARAM1;
748 u.l.lower = 0;
749 FT0d = u.d;
750 }
751
752 void OPPROTO op_vfp_fconsts(void)
753 {
754 FT0s = vfp_itos(PARAM1);
755 }
756
757 /* Copy the most significant bit of T0 to all bits of T1. */
758 void OPPROTO op_signbit_T1_T0(void)
759 {
760 T1 = (int32_t)T0 >> 31;
761 }
762
763 void OPPROTO op_movl_cp_T0(void)
764 {
765 helper_set_cp(env, PARAM1, T0);
766 FORCE_RET();
767 }
768
769 void OPPROTO op_movl_T0_cp(void)
770 {
771 T0 = helper_get_cp(env, PARAM1);
772 FORCE_RET();
773 }
774
775 void OPPROTO op_movl_cp15_T0(void)
776 {
777 helper_set_cp15(env, PARAM1, T0);
778 FORCE_RET();
779 }
780
781 void OPPROTO op_movl_T0_cp15(void)
782 {
783 T0 = helper_get_cp15(env, PARAM1);
784 FORCE_RET();
785 }
786
787 /* Access to user mode registers from privileged modes. */
788 void OPPROTO op_movl_T0_user(void)
789 {
790 int regno = PARAM1;
791 if (regno == 13) {
792 T0 = env->banked_r13[0];
793 } else if (regno == 14) {
794 T0 = env->banked_r14[0];
795 } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
796 T0 = env->usr_regs[regno - 8];
797 } else {
798 T0 = env->regs[regno];
799 }
800 FORCE_RET();
801 }
802
803
804 void OPPROTO op_movl_user_T0(void)
805 {
806 int regno = PARAM1;
807 if (regno == 13) {
808 env->banked_r13[0] = T0;
809 } else if (regno == 14) {
810 env->banked_r14[0] = T0;
811 } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
812 env->usr_regs[regno - 8] = T0;
813 } else {
814 env->regs[regno] = T0;
815 }
816 FORCE_RET();
817 }
818
819 /* ARMv6 Media instructions. */
820
821 /* Note that signed overflow is undefined in C. The following routines are
822 careful to use unsigned types where modulo arithmetic is required.
823 Failure to do so _will_ break on newer gcc. */
824
825 /* Signed saturating arithmetic. */
826
827 /* Perform 16-bit signed satruating addition. */
828 static inline uint16_t add16_sat(uint16_t a, uint16_t b)
829 {
830 uint16_t res;
831
832 res = a + b;
833 if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
834 if (a & 0x8000)
835 res = 0x8000;
836 else
837 res = 0x7fff;
838 }
839 return res;
840 }
841
842 /* Perform 8-bit signed satruating addition. */
843 static inline uint8_t add8_sat(uint8_t a, uint8_t b)
844 {
845 uint8_t res;
846
847 res = a + b;
848 if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
849 if (a & 0x80)
850 res = 0x80;
851 else
852 res = 0x7f;
853 }
854 return res;
855 }
856
857 /* Perform 16-bit signed satruating subtraction. */
858 static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
859 {
860 uint16_t res;
861
862 res = a - b;
863 if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
864 if (a & 0x8000)
865 res = 0x8000;
866 else
867 res = 0x7fff;
868 }
869 return res;
870 }
871
872 /* Perform 8-bit signed satruating subtraction. */
873 static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
874 {
875 uint8_t res;
876
877 res = a - b;
878 if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
879 if (a & 0x80)
880 res = 0x80;
881 else
882 res = 0x7f;
883 }
884 return res;
885 }
886
887 #define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
888 #define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
889 #define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8);
890 #define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8);
891 #define PFX q
892
893 #include "op_addsub.h"
894
895 /* Unsigned saturating arithmetic. */
896 static inline uint16_t add16_usat(uint16_t a, uint8_t b)
897 {
898 uint16_t res;
899 res = a + b;
900 if (res < a)
901 res = 0xffff;
902 return res;
903 }
904
905 static inline uint16_t sub16_usat(uint16_t a, uint8_t b)
906 {
907 if (a < b)
908 return a - b;
909 else
910 return 0;
911 }
912
913 static inline uint8_t add8_usat(uint8_t a, uint8_t b)
914 {
915 uint8_t res;
916 res = a + b;
917 if (res < a)
918 res = 0xff;
919 return res;
920 }
921
922 static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
923 {
924 if (a < b)
925 return a - b;
926 else
927 return 0;
928 }
929
930 #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
931 #define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
932 #define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8);
933 #define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8);
934 #define PFX uq
935
936 #include "op_addsub.h"
937
938 /* Signed modulo arithmetic. */
939 #define SARITH16(a, b, n, op) do { \
940 int32_t sum; \
941 sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \
942 RESULT(sum, n, 16); \
943 if (sum >= 0) \
944 ge |= 3 << (n * 2); \
945 } while(0)
946
947 #define SARITH8(a, b, n, op) do { \
948 int32_t sum; \
949 sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \
950 RESULT(sum, n, 8); \
951 if (sum >= 0) \
952 ge |= 1 << n; \
953 } while(0)
954
955
956 #define ADD16(a, b, n) SARITH16(a, b, n, +)
957 #define SUB16(a, b, n) SARITH16(a, b, n, -)
958 #define ADD8(a, b, n) SARITH8(a, b, n, +)
959 #define SUB8(a, b, n) SARITH8(a, b, n, -)
960 #define PFX s
961 #define ARITH_GE
962
963 #include "op_addsub.h"
964
965 /* Unsigned modulo arithmetic. */
966 #define ADD16(a, b, n) do { \
967 uint32_t sum; \
968 sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
969 RESULT(sum, n, 16); \
970 if ((sum >> 16) == 0) \
971 ge |= 3 << (n * 2); \
972 } while(0)
973
974 #define ADD8(a, b, n) do { \
975 uint32_t sum; \
976 sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
977 RESULT(sum, n, 8); \
978 if ((sum >> 8) == 0) \
979 ge |= 3 << (n * 2); \
980 } while(0)
981
982 #define SUB16(a, b, n) do { \
983 uint32_t sum; \
984 sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
985 RESULT(sum, n, 16); \
986 if ((sum >> 16) == 0) \
987 ge |= 3 << (n * 2); \
988 } while(0)
989
990 #define SUB8(a, b, n) do { \
991 uint32_t sum; \
992 sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
993 RESULT(sum, n, 8); \
994 if ((sum >> 8) == 0) \
995 ge |= 3 << (n * 2); \
996 } while(0)
997
998 #define PFX u
999 #define ARITH_GE
1000
1001 #include "op_addsub.h"
1002
1003 /* Halved signed arithmetic. */
1004 #define ADD16(a, b, n) \
1005 RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
1006 #define SUB16(a, b, n) \
1007 RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
1008 #define ADD8(a, b, n) \
1009 RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
1010 #define SUB8(a, b, n) \
1011 RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
1012 #define PFX sh
1013
1014 #include "op_addsub.h"
1015
1016 /* Halved unsigned arithmetic. */
1017 #define ADD16(a, b, n) \
1018 RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
1019 #define SUB16(a, b, n) \
1020 RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
1021 #define ADD8(a, b, n) \
1022 RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
1023 #define SUB8(a, b, n) \
1024 RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
1025 #define PFX uh
1026
1027 #include "op_addsub.h"
1028
1029 void OPPROTO op_pkhtb_T0_T1(void)
1030 {
1031 T0 = (T0 & 0xffff0000) | (T1 & 0xffff);
1032 }
1033
1034 void OPPROTO op_pkhbt_T0_T1(void)
1035 {
1036 T0 = (T0 & 0xffff) | (T1 & 0xffff0000);
1037 }
1038
1039 void OPPROTO op_rev16_T0(void)
1040 {
1041 T0 = ((T0 & 0xff000000) >> 8)
1042 | ((T0 & 0x00ff0000) << 8)
1043 | ((T0 & 0x0000ff00) >> 8)
1044 | ((T0 & 0x000000ff) << 8);
1045 }
1046
1047 void OPPROTO op_revsh_T0(void)
1048 {
1049 T0 = (int16_t)( ((T0 & 0x0000ff00) >> 8)
1050 | ((T0 & 0x000000ff) << 8));
1051 }
1052
1053 void OPPROTO op_rbit_T0(void)
1054 {
1055 T0 = ((T0 & 0xff000000) >> 24)
1056 | ((T0 & 0x00ff0000) >> 8)
1057 | ((T0 & 0x0000ff00) << 8)
1058 | ((T0 & 0x000000ff) << 24);
1059 T0 = ((T0 & 0xf0f0f0f0) >> 4)
1060 | ((T0 & 0x0f0f0f0f) << 4);
1061 T0 = ((T0 & 0x88888888) >> 3)
1062 | ((T0 & 0x44444444) >> 1)
1063 | ((T0 & 0x22222222) << 1)
1064 | ((T0 & 0x11111111) << 3);
1065 }
1066
1067 /* Dual 16-bit signed multiply. */
1068 void OPPROTO op_mul_dual_T0_T1(void)
1069 {
1070 int32_t low;
1071 int32_t high;
1072 low = (int32_t)(int16_t)T0 * (int32_t)(int16_t)T1;
1073 high = (((int32_t)T0) >> 16) * (((int32_t)T1) >> 16);
1074 T0 = low;
1075 T1 = high;
1076 }
1077
1078 void OPPROTO op_sel_T0_T1(void)
1079 {
1080 uint32_t mask;
1081 uint32_t flags;
1082
1083 flags = env->GE;
1084 mask = 0;
1085 if (flags & 1)
1086 mask |= 0xff;
1087 if (flags & 2)
1088 mask |= 0xff00;
1089 if (flags & 4)
1090 mask |= 0xff0000;
1091 if (flags & 8)
1092 mask |= 0xff000000;
1093 T0 = (T0 & mask) | (T1 & ~mask);
1094 FORCE_RET();
1095 }
1096
1097 void OPPROTO op_roundqd_T0_T1(void)
1098 {
1099 T0 = T1 + ((uint32_t)T0 >> 31);
1100 }
1101
1102 /* Signed saturation. */
1103 static inline uint32_t do_ssat(int32_t val, int shift)
1104 {
1105 int32_t top;
1106 uint32_t mask;
1107
1108 shift = PARAM1;
1109 top = val >> shift;
1110 mask = (1u << shift) - 1;
1111 if (top > 0) {
1112 env->QF = 1;
1113 return mask;
1114 } else if (top < -1) {
1115 env->QF = 1;
1116 return ~mask;
1117 }
1118 return val;
1119 }
1120
1121 /* Unsigned saturation. */
1122 static inline uint32_t do_usat(int32_t val, int shift)
1123 {
1124 uint32_t max;
1125
1126 shift = PARAM1;
1127 max = (1u << shift) - 1;
1128 if (val < 0) {
1129 env->QF = 1;
1130 return 0;
1131 } else if (val > max) {
1132 env->QF = 1;
1133 return max;
1134 }
1135 return val;
1136 }
1137
1138 /* Signed saturate. */
1139 void OPPROTO op_ssat_T1(void)
1140 {
1141 T0 = do_ssat(T0, PARAM1);
1142 FORCE_RET();
1143 }
1144
1145 /* Dual halfword signed saturate. */
1146 void OPPROTO op_ssat16_T1(void)
1147 {
1148 uint32_t res;
1149
1150 res = (uint16_t)do_ssat((int16_t)T0, PARAM1);
1151 res |= do_ssat(((int32_t)T0) >> 16, PARAM1) << 16;
1152 T0 = res;
1153 FORCE_RET();
1154 }
1155
1156 /* Unsigned saturate. */
1157 void OPPROTO op_usat_T1(void)
1158 {
1159 T0 = do_usat(T0, PARAM1);
1160 FORCE_RET();
1161 }
1162
1163 /* Dual halfword unsigned saturate. */
1164 void OPPROTO op_usat16_T1(void)
1165 {
1166 uint32_t res;
1167
1168 res = (uint16_t)do_usat((int16_t)T0, PARAM1);
1169 res |= do_usat(((int32_t)T0) >> 16, PARAM1) << 16;
1170 T0 = res;
1171 FORCE_RET();
1172 }
1173
1174 /* Dual 16-bit add. */
1175 static inline uint8_t do_usad(uint8_t a, uint8_t b)
1176 {
1177 if (a > b)
1178 return a - b;
1179 else
1180 return b - a;
1181 }
1182
1183 /* Unsigned sum of absolute byte differences. */
1184 void OPPROTO op_usad8_T0_T1(void)
1185 {
1186 uint32_t sum;
1187 sum = do_usad(T0, T1);
1188 sum += do_usad(T0 >> 8, T1 >> 8);
1189 sum += do_usad(T0 >> 16, T1 >>16);
1190 sum += do_usad(T0 >> 24, T1 >> 24);
1191 T0 = sum;
1192 }
1193
1194 /* Thumb-2 instructions. */
1195
1196 /* Insert T1 into T0. Result goes in T1. */
1197 void OPPROTO op_bfi_T1_T0(void)
1198 {
1199 int shift = PARAM1;
1200 uint32_t mask = PARAM2;
1201 uint32_t bits;
1202
1203 bits = (T1 << shift) & mask;
1204 T1 = (T0 & ~mask) | bits;
1205 }
1206
1207 /* Unsigned bitfield extract. */
1208 void OPPROTO op_ubfx_T1(void)
1209 {
1210 uint32_t shift = PARAM1;
1211 uint32_t mask = PARAM2;
1212
1213 T1 >>= shift;
1214 T1 &= mask;
1215 }
1216
1217 /* Signed bitfield extract. */
1218 void OPPROTO op_sbfx_T1(void)
1219 {
1220 uint32_t shift = PARAM1;
1221 uint32_t width = PARAM2;
1222 int32_t val;
1223
1224 val = T1 << (32 - (shift + width));
1225 T1 = val >> (32 - width);
1226 }
1227
1228 void OPPROTO op_sdivl_T0_T1(void)
1229 {
1230 int32_t num;
1231 int32_t den;
1232 num = T0;
1233 den = T1;
1234 if (den == 0)
1235 T0 = 0;
1236 else
1237 T0 = num / den;
1238 FORCE_RET();
1239 }
1240
1241 void OPPROTO op_udivl_T0_T1(void)
1242 {
1243 uint32_t num;
1244 uint32_t den;
1245 num = T0;
1246 den = T1;
1247 if (den == 0)
1248 T0 = 0;
1249 else
1250 T0 = num / den;
1251 FORCE_RET();
1252 }
1253
1254 void OPPROTO op_movl_T1_r13_banked(void)
1255 {
1256 T1 = helper_get_r13_banked(env, PARAM1);
1257 }
1258
1259 void OPPROTO op_movl_r13_T1_banked(void)
1260 {
1261 helper_set_r13_banked(env, PARAM1, T1);
1262 }
1263
1264 void OPPROTO op_v7m_mrs_T0(void)
1265 {
1266 T0 = helper_v7m_mrs(env, PARAM1);
1267 }
1268
1269 void OPPROTO op_v7m_msr_T0(void)
1270 {
1271 helper_v7m_msr(env, PARAM1, T0);
1272 }
1273
1274 void OPPROTO op_movl_T0_sp(void)
1275 {
1276 if (PARAM1 == env->v7m.current_sp)
1277 T0 = env->regs[13];
1278 else
1279 T0 = env->v7m.other_sp;
1280 FORCE_RET();
1281 }
1282
1283 #include "op_neon.h"
1284
1285 /* iwMMXt support */
1286 #include "op_iwmmxt.c"