222 |
222 |
|
223 |
223 |
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
|
224 |
224 |
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
|
225 |
|
#define gen_op_rev_T0() tcg_gen_bswap_i32(cpu_T[0], cpu_T[0])
|
226 |
225 |
|
227 |
226 |
#define gen_op_mul_T0_T1() tcg_gen_mul_i32(cpu_T[0], cpu_T[0], cpu_T[1])
|
228 |
227 |
|
... | ... | |
804 |
803 |
gen_op_##name##_kernel(); \
|
805 |
804 |
} while (0)
|
806 |
805 |
#endif
|
|
806 |
static inline TCGv gen_ld8s(TCGv addr, int index)
|
|
807 |
{
|
|
808 |
TCGv tmp = new_tmp();
|
|
809 |
tcg_gen_qemu_ld8s(tmp, addr, index);
|
|
810 |
return tmp;
|
|
811 |
}
|
|
812 |
static inline TCGv gen_ld8u(TCGv addr, int index)
|
|
813 |
{
|
|
814 |
TCGv tmp = new_tmp();
|
|
815 |
tcg_gen_qemu_ld8u(tmp, addr, index);
|
|
816 |
return tmp;
|
|
817 |
}
|
|
818 |
static inline TCGv gen_ld16s(TCGv addr, int index)
|
|
819 |
{
|
|
820 |
TCGv tmp = new_tmp();
|
|
821 |
tcg_gen_qemu_ld16s(tmp, addr, index);
|
|
822 |
return tmp;
|
|
823 |
}
|
|
824 |
static inline TCGv gen_ld16u(TCGv addr, int index)
|
|
825 |
{
|
|
826 |
TCGv tmp = new_tmp();
|
|
827 |
tcg_gen_qemu_ld16u(tmp, addr, index);
|
|
828 |
return tmp;
|
|
829 |
}
|
|
830 |
static inline TCGv gen_ld32(TCGv addr, int index)
|
|
831 |
{
|
|
832 |
TCGv tmp = new_tmp();
|
|
833 |
tcg_gen_qemu_ld32u(tmp, addr, index);
|
|
834 |
return tmp;
|
|
835 |
}
|
|
836 |
static inline void gen_st8(TCGv val, TCGv addr, int index)
|
|
837 |
{
|
|
838 |
tcg_gen_qemu_st8(val, addr, index);
|
|
839 |
dead_tmp(val);
|
|
840 |
}
|
|
841 |
static inline void gen_st16(TCGv val, TCGv addr, int index)
|
|
842 |
{
|
|
843 |
tcg_gen_qemu_st16(val, addr, index);
|
|
844 |
dead_tmp(val);
|
|
845 |
}
|
|
846 |
static inline void gen_st32(TCGv val, TCGv addr, int index)
|
|
847 |
{
|
|
848 |
tcg_gen_qemu_st32(val, addr, index);
|
|
849 |
dead_tmp(val);
|
|
850 |
}
|
807 |
851 |
|
808 |
852 |
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
|
809 |
853 |
{
|
... | ... | |
859 |
903 |
s->is_jmp = DISAS_UPDATE;
|
860 |
904 |
}
|
861 |
905 |
|
862 |
|
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
|
|
906 |
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
|
|
907 |
TCGv var)
|
863 |
908 |
{
|
864 |
909 |
int val, rm, shift, shiftop;
|
865 |
910 |
TCGv offset;
|
... | ... | |
870 |
915 |
if (!(insn & (1 << 23)))
|
871 |
916 |
val = -val;
|
872 |
917 |
if (val != 0)
|
873 |
|
gen_op_addl_T1_im(val);
|
|
918 |
tcg_gen_addi_i32(var, var, val);
|
874 |
919 |
} else {
|
875 |
920 |
/* shift/register */
|
876 |
921 |
rm = (insn) & 0xf;
|
... | ... | |
879 |
924 |
offset = load_reg(s, rm);
|
880 |
925 |
gen_arm_shift_im(offset, shiftop, shift, 0);
|
881 |
926 |
if (!(insn & (1 << 23)))
|
882 |
|
tcg_gen_sub_i32(cpu_T[1], cpu_T[1], offset);
|
|
927 |
tcg_gen_sub_i32(var, var, offset);
|
883 |
928 |
else
|
884 |
|
tcg_gen_add_i32(cpu_T[1], cpu_T[1], offset);
|
|
929 |
tcg_gen_add_i32(var, var, offset);
|
885 |
930 |
dead_tmp(offset);
|
886 |
931 |
}
|
887 |
932 |
}
|
888 |
933 |
|
889 |
934 |
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
|
890 |
|
int extra)
|
|
935 |
int extra, TCGv var)
|
891 |
936 |
{
|
892 |
937 |
int val, rm;
|
893 |
938 |
TCGv offset;
|
... | ... | |
899 |
944 |
val = -val;
|
900 |
945 |
val += extra;
|
901 |
946 |
if (val != 0)
|
902 |
|
gen_op_addl_T1_im(val);
|
|
947 |
tcg_gen_addi_i32(var, var, val);
|
903 |
948 |
} else {
|
904 |
949 |
/* register */
|
905 |
950 |
if (extra)
|
906 |
|
gen_op_addl_T1_im(extra);
|
|
951 |
tcg_gen_addi_i32(var, var, extra);
|
907 |
952 |
rm = (insn) & 0xf;
|
908 |
953 |
offset = load_reg(s, rm);
|
909 |
954 |
if (!(insn & (1 << 23)))
|
910 |
|
tcg_gen_sub_i32(cpu_T[1], cpu_T[1], offset);
|
|
955 |
tcg_gen_sub_i32(var, var, offset);
|
911 |
956 |
else
|
912 |
|
tcg_gen_add_i32(cpu_T[1], cpu_T[1], offset);
|
|
957 |
tcg_gen_add_i32(var, var, offset);
|
913 |
958 |
dead_tmp(offset);
|
914 |
959 |
}
|
915 |
960 |
}
|
... | ... | |
1090 |
1135 |
{
|
1091 |
1136 |
int rd, wrd;
|
1092 |
1137 |
int rdhi, rdlo, rd0, rd1, i;
|
|
1138 |
TCGv tmp;
|
1093 |
1139 |
|
1094 |
1140 |
if ((insn & 0x0e000e00) == 0x0c000000) {
|
1095 |
1141 |
if ((insn & 0x0fe00ff0) == 0x0c400000) {
|
... | ... | |
1114 |
1160 |
return 1;
|
1115 |
1161 |
if (insn & ARM_CP_RW_BIT) {
|
1116 |
1162 |
if ((insn >> 28) == 0xf) { /* WLDRW wCx */
|
1117 |
|
gen_ldst(ldl, s);
|
|
1163 |
tmp = gen_ld32(cpu_T[1], IS_USER(s));
|
|
1164 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
1165 |
dead_tmp(tmp);
|
1118 |
1166 |
gen_op_iwmmxt_movl_wCx_T0(wrd);
|
1119 |
1167 |
} else {
|
1120 |
1168 |
if (insn & (1 << 8))
|
... | ... | |
1132 |
1180 |
} else {
|
1133 |
1181 |
if ((insn >> 28) == 0xf) { /* WSTRW wCx */
|
1134 |
1182 |
gen_op_iwmmxt_movl_T0_wCx(wrd);
|
1135 |
|
gen_ldst(stl, s);
|
|
1183 |
tmp = new_tmp();
|
|
1184 |
tcg_gen_mov_i32(tmp, cpu_T[0]);
|
|
1185 |
gen_st32(tmp, cpu_T[1], IS_USER(s));
|
1136 |
1186 |
} else {
|
1137 |
1187 |
gen_op_iwmmxt_movq_M0_wRn(wrd);
|
1138 |
1188 |
if (insn & (1 << 8))
|
... | ... | |
2970 |
3020 |
s->is_jmp = DISAS_UPDATE;
|
2971 |
3021 |
}
|
2972 |
3022 |
|
2973 |
|
/* Generate a v6 exception return. */
|
2974 |
|
static void gen_rfe(DisasContext *s)
|
|
3023 |
/* Generate a v6 exception return. Marks both values as dead. */
|
|
3024 |
static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
|
2975 |
3025 |
{
|
2976 |
|
gen_set_cpsr(cpu_T[0], 0xffffffff);
|
2977 |
|
gen_op_movl_T0_T2();
|
2978 |
|
gen_set_pc_T0();
|
|
3026 |
gen_set_cpsr(cpsr, 0xffffffff);
|
|
3027 |
dead_tmp(cpsr);
|
|
3028 |
store_reg(s, 15, pc);
|
2979 |
3029 |
s->is_jmp = DISAS_UPDATE;
|
2980 |
3030 |
}
|
2981 |
3031 |
|
... | ... | |
3288 |
3338 |
int shift;
|
3289 |
3339 |
uint32_t mask;
|
3290 |
3340 |
int n;
|
|
3341 |
TCGv tmp;
|
3291 |
3342 |
|
3292 |
3343 |
if (!vfp_enabled(env))
|
3293 |
3344 |
return 1;
|
... | ... | |
3316 |
3367 |
for (pass = 0; pass < 2; pass++) {
|
3317 |
3368 |
if (size == 2) {
|
3318 |
3369 |
if (load) {
|
3319 |
|
gen_ldst(ldl, s);
|
|
3370 |
tmp = gen_ld32(cpu_T[1], IS_USER(s));
|
|
3371 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3372 |
dead_tmp(tmp);
|
3320 |
3373 |
NEON_SET_REG(T0, rd, pass);
|
3321 |
3374 |
} else {
|
3322 |
3375 |
NEON_GET_REG(T0, rd, pass);
|
3323 |
|
gen_ldst(stl, s);
|
|
3376 |
tmp = new_tmp();
|
|
3377 |
tcg_gen_mov_i32(tmp, cpu_T[0]);
|
|
3378 |
gen_st32(tmp, cpu_T[1], IS_USER(s));
|
3324 |
3379 |
}
|
3325 |
3380 |
gen_op_addl_T1_im(stride);
|
3326 |
3381 |
} else if (size == 1) {
|
3327 |
3382 |
if (load) {
|
3328 |
|
gen_ldst(lduw, s);
|
|
3383 |
tmp = gen_ld16u(cpu_T[1], IS_USER(s));
|
|
3384 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3385 |
dead_tmp(tmp);
|
3329 |
3386 |
gen_op_addl_T1_im(stride);
|
3330 |
3387 |
gen_op_movl_T2_T0();
|
3331 |
|
gen_ldst(lduw, s);
|
|
3388 |
tmp = gen_ld16u(cpu_T[1], IS_USER(s));
|
|
3389 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3390 |
dead_tmp(tmp);
|
3332 |
3391 |
gen_op_addl_T1_im(stride);
|
3333 |
3392 |
gen_op_neon_insert_elt(16, 0xffff);
|
3334 |
3393 |
NEON_SET_REG(T2, rd, pass);
|
3335 |
3394 |
} else {
|
3336 |
3395 |
NEON_GET_REG(T2, rd, pass);
|
3337 |
3396 |
gen_op_movl_T0_T2();
|
3338 |
|
gen_ldst(stw, s);
|
|
3397 |
tmp = new_tmp();
|
|
3398 |
tcg_gen_mov_i32(tmp, cpu_T[0]);
|
|
3399 |
gen_st16(tmp, cpu_T[1], IS_USER(s));
|
3339 |
3400 |
gen_op_addl_T1_im(stride);
|
3340 |
3401 |
gen_op_neon_extract_elt(16, 0xffff0000);
|
3341 |
|
gen_ldst(stw, s);
|
|
3402 |
tmp = new_tmp();
|
|
3403 |
tcg_gen_mov_i32(tmp, cpu_T[0]);
|
|
3404 |
gen_st16(tmp, cpu_T[1], IS_USER(s));
|
3342 |
3405 |
gen_op_addl_T1_im(stride);
|
3343 |
3406 |
}
|
3344 |
3407 |
} else /* size == 0 */ {
|
3345 |
3408 |
if (load) {
|
3346 |
3409 |
mask = 0xff;
|
3347 |
3410 |
for (n = 0; n < 4; n++) {
|
3348 |
|
gen_ldst(ldub, s);
|
|
3411 |
tmp = gen_ld8u(cpu_T[1], IS_USER(s));
|
|
3412 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3413 |
dead_tmp(tmp);
|
3349 |
3414 |
gen_op_addl_T1_im(stride);
|
3350 |
3415 |
if (n == 0) {
|
3351 |
3416 |
gen_op_movl_T2_T0();
|
... | ... | |
3364 |
3429 |
} else {
|
3365 |
3430 |
gen_op_neon_extract_elt(n * 8, mask);
|
3366 |
3431 |
}
|
3367 |
|
gen_ldst(stb, s);
|
|
3432 |
tmp = new_tmp();
|
|
3433 |
tcg_gen_mov_i32(tmp, cpu_T[0]);
|
|
3434 |
gen_st8(tmp, cpu_T[1], IS_USER(s));
|
3368 |
3435 |
gen_op_addl_T1_im(stride);
|
3369 |
3436 |
mask <<= 8;
|
3370 |
3437 |
}
|
... | ... | |
3387 |
3454 |
for (reg = 0; reg < nregs; reg++) {
|
3388 |
3455 |
switch (size) {
|
3389 |
3456 |
case 0:
|
3390 |
|
gen_ldst(ldub, s);
|
|
3457 |
tmp = gen_ld8u(cpu_T[1], IS_USER(s));
|
|
3458 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3459 |
dead_tmp(tmp);
|
3391 |
3460 |
gen_op_neon_dup_u8(0);
|
3392 |
3461 |
break;
|
3393 |
3462 |
case 1:
|
3394 |
|
gen_ldst(lduw, s);
|
|
3463 |
tmp = gen_ld16u(cpu_T[1], IS_USER(s));
|
|
3464 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3465 |
dead_tmp(tmp);
|
3395 |
3466 |
gen_op_neon_dup_low16();
|
3396 |
3467 |
break;
|
3397 |
3468 |
case 2:
|
3398 |
|
gen_ldst(ldl, s);
|
|
3469 |
tmp = gen_ld32(cpu_T[0], IS_USER(s));
|
|
3470 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3471 |
dead_tmp(tmp);
|
3399 |
3472 |
break;
|
3400 |
3473 |
case 3:
|
3401 |
3474 |
return 1;
|
... | ... | |
3437 |
3510 |
}
|
3438 |
3511 |
switch (size) {
|
3439 |
3512 |
case 0:
|
3440 |
|
gen_ldst(ldub, s);
|
|
3513 |
tmp = gen_ld8u(cpu_T[1], IS_USER(s));
|
3441 |
3514 |
break;
|
3442 |
3515 |
case 1:
|
3443 |
|
gen_ldst(lduw, s);
|
|
3516 |
tmp = gen_ld16u(cpu_T[1], IS_USER(s));
|
3444 |
3517 |
break;
|
3445 |
3518 |
case 2:
|
3446 |
|
gen_ldst(ldl, s);
|
3447 |
|
NEON_SET_REG(T0, rd, pass);
|
|
3519 |
tmp = gen_ld32(cpu_T[1], IS_USER(s));
|
3448 |
3520 |
break;
|
3449 |
3521 |
}
|
|
3522 |
tcg_gen_mov_i32(cpu_T[0], tmp);
|
|
3523 |
dead_tmp(tmp);
|
3450 |
3524 |
if (size != 2) {
|
3451 |
3525 |
gen_op_neon_insert_elt(shift, ~mask);
|
3452 |
3526 |
NEON_SET_REG(T0, rd, pass);
|
|
3527 |
} else {
|
|
3528 |
NEON_SET_REG(T0, rd, pass);
|
3453 |
3529 |
}
|
3454 |
3530 |
} else { /* Store */
|
3455 |
3531 |
if (size == 2) {
|
... | ... | |
3458 |
3534 |
NEON_GET_REG(T2, rd, pass);
|
3459 |
3535 |
gen_op_neon_extract_elt(shift, mask);
|
3460 |
3536 |
}
|
|
3537 |
tmp = new_tmp();
|
|
3538 |
tcg_gen_mov_i32(tmp, cpu_T[0]);
|
3461 |
3539 |
switch (size) {
|
3462 |
3540 |
case 0:
|
3463 |
|
gen_ldst(stb, s);
|
|
3541 |
gen_st8(tmp, cpu_T[1], IS_USER(s));
|
3464 |
3542 |
break;
|
3465 |
3543 |
case 1:
|
3466 |
|
gen_ldst(stw, s);
|
|
3544 |
gen_st16(tmp, cpu_T[1], IS_USER(s));
|
3467 |
3545 |
break;
|
3468 |
3546 |
case 2:
|
3469 |
|
gen_ldst(stl, s);
|
|
3547 |
gen_st32(tmp, cpu_T[1], IS_USER(s));
|
3470 |
3548 |
break;
|
3471 |
3549 |
}
|
3472 |
3550 |
}
|
... | ... | |
4647 |
4725 |
NEON_GET_REG(T0, rm, pass * 2);
|
4648 |
4726 |
NEON_GET_REG(T1, rm, pass * 2 + 1);
|
4649 |
4727 |
switch (size) {
|
4650 |
|
case 0: gen_op_rev_T0(); break;
|
|
4728 |
case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
|
4651 |
4729 |
case 1: gen_swap_half(cpu_T[0]); break;
|
4652 |
4730 |
case 2: /* no-op */ break;
|
4653 |
4731 |
default: abort();
|
... | ... | |
4658 |
4736 |
} else {
|
4659 |
4737 |
gen_op_movl_T0_T1();
|
4660 |
4738 |
switch (size) {
|
4661 |
|
case 0: gen_op_rev_T0(); break;
|
|
4739 |
case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
|
4662 |
4740 |
case 1: gen_swap_half(cpu_T[0]); break;
|
4663 |
4741 |
default: abort();
|
4664 |
4742 |
}
|
... | ... | |
4827 |
4905 |
switch (op) {
|
4828 |
4906 |
case 1: /* VREV32 */
|
4829 |
4907 |
switch (size) {
|
4830 |
|
case 0: gen_op_rev_T0(); break;
|
|
4908 |
case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
|
4831 |
4909 |
case 1: gen_swap_half(cpu_T[0]); break;
|
4832 |
4910 |
default: return 1;
|
4833 |
4911 |
}
|
... | ... | |
5099 |
5177 |
TCGv tmp;
|
5100 |
5178 |
TCGv tmp2;
|
5101 |
5179 |
TCGv tmp3;
|
|
5180 |
TCGv addr;
|
5102 |
5181 |
|
5103 |
5182 |
insn = ldl_code(s->pc);
|
5104 |
5183 |
s->pc += 4;
|
... | ... | |
5160 |
5239 |
ARCH(6);
|
5161 |
5240 |
op1 = (insn & 0x1f);
|
5162 |
5241 |
if (op1 == (env->uncached_cpsr & CPSR_M)) {
|
5163 |
|
gen_movl_T1_reg(s, 13);
|
|
5242 |
addr = load_reg(s, 13);
|
5164 |
5243 |
} else {
|
5165 |
|
gen_op_movl_T1_r13_banked(op1);
|
|
5244 |
addr = new_tmp();
|
|
5245 |
gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op1));
|
5166 |
5246 |
}
|
5167 |
5247 |
i = (insn >> 23) & 3;
|
5168 |
5248 |
switch (i) {
|
... | ... | |
5173 |
5253 |
default: abort();
|
5174 |
5254 |
}
|
5175 |
5255 |
if (offset)
|
5176 |
|
gen_op_addl_T1_im(offset);
|
5177 |
|
gen_movl_T0_reg(s, 14);
|
5178 |
|
gen_ldst(stl, s);
|
5179 |
|
gen_helper_cpsr_read(cpu_T[0]);
|
5180 |
|
gen_op_addl_T1_im(4);
|
5181 |
|
gen_ldst(stl, s);
|
|
5256 |
tcg_gen_addi_i32(addr, addr, offset);
|
|
5257 |
tmp = load_reg(s, 14);
|
|
5258 |
gen_st32(tmp, addr, 0);
|
|
5259 |
tmp = new_tmp();
|
|
5260 |
gen_helper_cpsr_read(tmp);
|
|
5261 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
5262 |
gen_st32(tmp, addr, 0);
|
5182 |
5263 |
if (insn & (1 << 21)) {
|
5183 |
5264 |
/* Base writeback. */
|
5184 |
5265 |
switch (i) {
|
... | ... | |
5189 |
5270 |
default: abort();
|
5190 |
5271 |
}
|
5191 |
5272 |
if (offset)
|
5192 |
|
gen_op_addl_T1_im(offset);
|
|
5273 |
tcg_gen_addi_i32(addr, tmp, offset);
|
5193 |
5274 |
if (op1 == (env->uncached_cpsr & CPSR_M)) {
|
5194 |
5275 |
gen_movl_reg_T1(s, 13);
|
5195 |
5276 |
} else {
|
5196 |
|
gen_op_movl_r13_T1_banked(op1);
|
|
5277 |
gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), cpu_T[1]);
|
5197 |
5278 |
}
|
|
5279 |
} else {
|
|
5280 |
dead_tmp(addr);
|
5198 |
5281 |
}
|
5199 |
5282 |
} else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
|
5200 |
5283 |
/* rfe */
|
... | ... | |
5203 |
5286 |
goto illegal_op;
|
5204 |
5287 |
ARCH(6);
|
5205 |
5288 |
rn = (insn >> 16) & 0xf;
|
5206 |
|
gen_movl_T1_reg(s, rn);
|
|
5289 |
addr = load_reg(s, rn);
|
5207 |
5290 |
i = (insn >> 23) & 3;
|
5208 |
5291 |
switch (i) {
|
5209 |
|
case 0: offset = 0; break; /* DA */
|
5210 |
|
case 1: offset = -4; break; /* DB */
|
5211 |
|
case 2: offset = 4; break; /* IA */
|
5212 |
|
case 3: offset = 8; break; /* IB */
|
|
5292 |
case 0: offset = -4; break; /* DA */
|
|
5293 |
case 1: offset = -8; break; /* DB */
|
|
5294 |
case 2: offset = 0; break; /* IA */
|
|
5295 |
case 3: offset = 4; break; /* IB */
|
5213 |
5296 |
default: abort();
|
5214 |
5297 |
}
|
5215 |
5298 |
if (offset)
|
5216 |
|
gen_op_addl_T1_im(offset);
|
5217 |
|
/* Load CPSR into T2 and PC into T0. */
|
5218 |
|
gen_ldst(ldl, s);
|
5219 |
|
gen_op_movl_T2_T0();
|
5220 |
|
gen_op_addl_T1_im(-4);
|
5221 |
|
gen_ldst(ldl, s);
|
|
5299 |
tcg_gen_addi_i32(addr, addr, offset);
|
|
5300 |
/* Load PC into tmp and CPSR into tmp2. */
|
|
5301 |
tmp = gen_ld32(addr, 0);
|
|
5302 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
5303 |
tmp2 = gen_ld32(addr, 0);
|
5222 |
5304 |
if (insn & (1 << 21)) {
|
5223 |
5305 |
/* Base writeback. */
|
5224 |
5306 |
switch (i) {
|
5225 |
|
case 0: offset = -4; break;
|
5226 |
|
case 1: offset = 0; break;
|
5227 |
|
case 2: offset = 8; break;
|
5228 |
|
case 3: offset = 4; break;
|
|
5307 |
case 0: offset = -8; break;
|
|
5308 |
case 1: offset = -4; break;
|
|
5309 |
case 2: offset = 4; break;
|
|
5310 |
case 3: offset = 0; break;
|
5229 |
5311 |
default: abort();
|
5230 |
5312 |
}
|
5231 |
5313 |
if (offset)
|
5232 |
|
gen_op_addl_T1_im(offset);
|
5233 |
|
gen_movl_reg_T1(s, rn);
|
|
5314 |
tcg_gen_addi_i32(addr, addr, offset);
|
|
5315 |
store_reg(s, rn, addr);
|
|
5316 |
} else {
|
|
5317 |
dead_tmp(addr);
|
5234 |
5318 |
}
|
5235 |
|
gen_rfe(s);
|
|
5319 |
gen_rfe(s, tmp, tmp2);
|
5236 |
5320 |
} else if ((insn & 0x0e000000) == 0x0a000000) {
|
5237 |
5321 |
/* branch link and change to thumb (blx <offset>) */
|
5238 |
5322 |
int32_t offset;
|
... | ... | |
5707 |
5791 |
/* Misc load/store */
|
5708 |
5792 |
rn = (insn >> 16) & 0xf;
|
5709 |
5793 |
rd = (insn >> 12) & 0xf;
|
5710 |
|
gen_movl_T1_reg(s, rn);
|
|
5794 |
addr = load_reg(s, rn);
|
5711 |
5795 |
if (insn & (1 << 24))
|
5712 |
|
gen_add_datah_offset(s, insn, 0);
|
|
5796 |
gen_add_datah_offset(s, insn, 0, addr);
|
5713 |
5797 |
address_offset = 0;
|
5714 |
5798 |
if (insn & (1 << 20)) {
|
5715 |
5799 |
/* load */
|
5716 |
5800 |
switch(sh) {
|
5717 |
5801 |
case 1:
|
5718 |
|
gen_ldst(lduw, s);
|
|
5802 |
tmp = gen_ld16u(addr, IS_USER(s));
|
5719 |
5803 |
break;
|
5720 |
5804 |
case 2:
|
5721 |
|
gen_ldst(ldsb, s);
|
|
5805 |
tmp = gen_ld8s(addr, IS_USER(s));
|
5722 |
5806 |
break;
|
5723 |
5807 |
default:
|
5724 |
5808 |
case 3:
|
5725 |
|
gen_ldst(ldsw, s);
|
|
5809 |
tmp = gen_ld16s(addr, IS_USER(s));
|
5726 |
5810 |
break;
|
5727 |
5811 |
}
|
5728 |
5812 |
load = 1;
|
... | ... | |
5730 |
5814 |
/* doubleword */
|
5731 |
5815 |
if (sh & 1) {
|
5732 |
5816 |
/* store */
|
5733 |
|
gen_movl_T0_reg(s, rd);
|
5734 |
|
gen_ldst(stl, s);
|
5735 |
|
gen_op_addl_T1_im(4);
|
5736 |
|
gen_movl_T0_reg(s, rd + 1);
|
5737 |
|
gen_ldst(stl, s);
|
|
5817 |
tmp = load_reg(s, rd);
|
|
5818 |
gen_st32(tmp, addr, IS_USER(s));
|
|
5819 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
5820 |
tmp = load_reg(s, rd + 1);
|
|
5821 |
gen_st32(tmp, addr, IS_USER(s));
|
5738 |
5822 |
load = 0;
|
5739 |
5823 |
} else {
|
5740 |
5824 |
/* load */
|
5741 |
|
gen_ldst(ldl, s);
|
5742 |
|
gen_movl_reg_T0(s, rd);
|
5743 |
|
gen_op_addl_T1_im(4);
|
5744 |
|
gen_ldst(ldl, s);
|
|
5825 |
tmp = gen_ld32(addr, IS_USER(s));
|
|
5826 |
store_reg(s, rd, tmp);
|
|
5827 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
5828 |
tmp = gen_ld32(addr, IS_USER(s));
|
5745 |
5829 |
rd++;
|
5746 |
5830 |
load = 1;
|
5747 |
5831 |
}
|
5748 |
5832 |
address_offset = -4;
|
5749 |
5833 |
} else {
|
5750 |
5834 |
/* store */
|
5751 |
|
gen_movl_T0_reg(s, rd);
|
5752 |
|
gen_ldst(stw, s);
|
|
5835 |
tmp = load_reg(s, rd);
|
|
5836 |
gen_st16(tmp, addr, IS_USER(s));
|
5753 |
5837 |
load = 0;
|
5754 |
5838 |
}
|
5755 |
5839 |
/* Perform base writeback before the loaded value to
|
... | ... | |
5757 |
5841 |
ldrd with base writeback is is undefined if the
|
5758 |
5842 |
destination and index registers overlap. */
|
5759 |
5843 |
if (!(insn & (1 << 24))) {
|
5760 |
|
gen_add_datah_offset(s, insn, address_offset);
|
5761 |
|
gen_movl_reg_T1(s, rn);
|
|
5844 |
gen_add_datah_offset(s, insn, address_offset, addr);
|
|
5845 |
store_reg(s, rn, addr);
|
5762 |
5846 |
} else if (insn & (1 << 21)) {
|
5763 |
5847 |
if (address_offset)
|
5764 |
|
gen_op_addl_T1_im(address_offset);
|
5765 |
|
gen_movl_reg_T1(s, rn);
|
|
5848 |
tcg_gen_addi_i32(addr, addr, address_offset);
|
|
5849 |
store_reg(s, rn, addr);
|
|
5850 |
} else {
|
|
5851 |
dead_tmp(addr);
|
5766 |
5852 |
}
|
5767 |
5853 |
if (load) {
|
5768 |
5854 |
/* Complete the load. */
|
5769 |
|
gen_movl_reg_T0(s, rd);
|
|
5855 |
store_reg(s, rd, tmp);
|
5770 |
5856 |
}
|
5771 |
5857 |
}
|
5772 |
5858 |
break;
|
... | ... | |
5882 |
5968 |
gen_movl_reg_T1(s, rd);
|
5883 |
5969 |
} else if ((insn & 0x003f0f60) == 0x003f0f20) {
|
5884 |
5970 |
/* rev */
|
5885 |
|
gen_movl_T0_reg(s, rm);
|
|
5971 |
tmp = load_reg(s, rm);
|
5886 |
5972 |
if (insn & (1 << 22)) {
|
5887 |
5973 |
if (insn & (1 << 7)) {
|
5888 |
|
gen_revsh(cpu_T[0]);
|
|
5974 |
gen_revsh(tmp);
|
5889 |
5975 |
} else {
|
5890 |
5976 |
ARCH(6T2);
|
5891 |
|
gen_helper_rbit(cpu_T[0], cpu_T[0]);
|
|
5977 |
gen_helper_rbit(tmp, tmp);
|
5892 |
5978 |
}
|
5893 |
5979 |
} else {
|
5894 |
5980 |
if (insn & (1 << 7))
|
5895 |
|
gen_rev16(cpu_T[0]);
|
|
5981 |
gen_rev16(tmp);
|
5896 |
5982 |
else
|
5897 |
|
gen_op_rev_T0();
|
|
5983 |
tcg_gen_bswap_i32(tmp, tmp);
|
5898 |
5984 |
}
|
5899 |
|
gen_movl_reg_T0(s, rd);
|
|
5985 |
store_reg(s, rd, tmp);
|
5900 |
5986 |
} else {
|
5901 |
5987 |
goto illegal_op;
|
5902 |
5988 |
}
|
... | ... | |
6020 |
6106 |
/* load/store byte/word */
|
6021 |
6107 |
rn = (insn >> 16) & 0xf;
|
6022 |
6108 |
rd = (insn >> 12) & 0xf;
|
6023 |
|
gen_movl_T1_reg(s, rn);
|
|
6109 |
tmp2 = load_reg(s, rn);
|
6024 |
6110 |
i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
|
6025 |
6111 |
if (insn & (1 << 24))
|
6026 |
|
gen_add_data_offset(s, insn);
|
|
6112 |
gen_add_data_offset(s, insn, tmp2);
|
6027 |
6113 |
if (insn & (1 << 20)) {
|
6028 |
6114 |
/* load */
|
6029 |
6115 |
s->is_mem = 1;
|
6030 |
|
#if defined(CONFIG_USER_ONLY)
|
6031 |
|
if (insn & (1 << 22))
|
6032 |
|
gen_op_ldub_raw();
|
6033 |
|
else
|
6034 |
|
gen_op_ldl_raw();
|
6035 |
|
#else
|
6036 |
6116 |
if (insn & (1 << 22)) {
|
6037 |
|
if (i)
|
6038 |
|
gen_op_ldub_user();
|
6039 |
|
else
|
6040 |
|
gen_op_ldub_kernel();
|
|
6117 |
tmp = gen_ld8u(tmp2, i);
|
6041 |
6118 |
} else {
|
6042 |
|
if (i)
|
6043 |
|
gen_op_ldl_user();
|
6044 |
|
else
|
6045 |
|
gen_op_ldl_kernel();
|
|
6119 |
tmp = gen_ld32(tmp2, i);
|
6046 |
6120 |
}
|
6047 |
|
#endif
|
6048 |
6121 |
} else {
|
6049 |
6122 |
/* store */
|
6050 |
|
gen_movl_T0_reg(s, rd);
|
6051 |
|
#if defined(CONFIG_USER_ONLY)
|
|
6123 |
tmp = load_reg(s, rd);
|
6052 |
6124 |
if (insn & (1 << 22))
|
6053 |
|
gen_op_stb_raw();
|
|
6125 |
gen_st8(tmp, tmp2, i);
|
6054 |
6126 |
else
|
6055 |
|
gen_op_stl_raw();
|
6056 |
|
#else
|
6057 |
|
if (insn & (1 << 22)) {
|
6058 |
|
if (i)
|
6059 |
|
gen_op_stb_user();
|
6060 |
|
else
|
6061 |
|
gen_op_stb_kernel();
|
6062 |
|
} else {
|
6063 |
|
if (i)
|
6064 |
|
gen_op_stl_user();
|
6065 |
|
else
|
6066 |
|
gen_op_stl_kernel();
|
6067 |
|
}
|
6068 |
|
#endif
|
|
6127 |
gen_st32(tmp, tmp2, i);
|
6069 |
6128 |
}
|
6070 |
6129 |
if (!(insn & (1 << 24))) {
|
6071 |
|
gen_add_data_offset(s, insn);
|
6072 |
|
gen_movl_reg_T1(s, rn);
|
6073 |
|
} else if (insn & (1 << 21))
|
6074 |
|
gen_movl_reg_T1(s, rn); {
|
|
6130 |
gen_add_data_offset(s, insn, tmp2);
|
|
6131 |
store_reg(s, rn, tmp2);
|
|
6132 |
} else if (insn & (1 << 21)) {
|
|
6133 |
store_reg(s, rn, tmp2);
|
|
6134 |
} else {
|
|
6135 |
dead_tmp(tmp2);
|
6075 |
6136 |
}
|
6076 |
6137 |
if (insn & (1 << 20)) {
|
6077 |
6138 |
/* Complete the load. */
|
6078 |
6139 |
if (rd == 15)
|
6079 |
|
gen_bx_T0(s);
|
|
6140 |
gen_bx(s, tmp);
|
6080 |
6141 |
else
|
6081 |
|
gen_movl_reg_T0(s, rd);
|
|
6142 |
store_reg(s, rd, tmp);
|
6082 |
6143 |
}
|
6083 |
6144 |
break;
|
6084 |
6145 |
case 0x08:
|
6085 |
6146 |
case 0x09:
|
6086 |
6147 |
{
|
6087 |
6148 |
int j, n, user, loaded_base;
|
|
6149 |
TCGv loaded_var;
|
6088 |
6150 |
/* load/store multiple words */
|
6089 |
6151 |
/* XXX: store correct base if write back */
|
6090 |
6152 |
user = 0;
|
... | ... | |
6096 |
6158 |
user = 1;
|
6097 |
6159 |
}
|
6098 |
6160 |
rn = (insn >> 16) & 0xf;
|
6099 |
|
gen_movl_T1_reg(s, rn);
|
|
6161 |
addr = load_reg(s, rn);
|
6100 |
6162 |
|
6101 |
6163 |
/* compute total size */
|
6102 |
6164 |
loaded_base = 0;
|
... | ... | |
6109 |
6171 |
if (insn & (1 << 23)) {
|
6110 |
6172 |
if (insn & (1 << 24)) {
|
6111 |
6173 |
/* pre increment */
|
6112 |
|
gen_op_addl_T1_im(4);
|
|
6174 |
tcg_gen_addi_i32(addr, addr, 4);
|
6113 |
6175 |
} else {
|
6114 |
6176 |
/* post increment */
|
6115 |
6177 |
}
|
6116 |
6178 |
} else {
|
6117 |
6179 |
if (insn & (1 << 24)) {
|
6118 |
6180 |
/* pre decrement */
|
6119 |
|
gen_op_addl_T1_im(-(n * 4));
|
|
6181 |
tcg_gen_addi_i32(addr, addr, -(n * 4));
|
6120 |
6182 |
} else {
|
6121 |
6183 |
/* post decrement */
|
6122 |
6184 |
if (n != 1)
|
6123 |
|
gen_op_addl_T1_im(-((n - 1) * 4));
|
|
6185 |
tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
|
6124 |
6186 |
}
|
6125 |
6187 |
}
|
6126 |
6188 |
j = 0;
|
... | ... | |
6128 |
6190 |
if (insn & (1 << i)) {
|
6129 |
6191 |
if (insn & (1 << 20)) {
|
6130 |
6192 |
/* load */
|
6131 |
|
gen_ldst(ldl, s);
|
|
6193 |
tmp = gen_ld32(addr, IS_USER(s));
|
6132 |
6194 |
if (i == 15) {
|
6133 |
|
gen_bx_T0(s);
|
|
6195 |
gen_bx(s, tmp);
|
6134 |
6196 |
} else if (user) {
|
6135 |
|
gen_op_movl_user_T0(i);
|
|
6197 |
gen_helper_set_user_reg(tcg_const_i32(i), tmp);
|
|
6198 |
dead_tmp(tmp);
|
6136 |
6199 |
} else if (i == rn) {
|
6137 |
|
gen_op_movl_T2_T0();
|
|
6200 |
loaded_var = tmp;
|
6138 |
6201 |
loaded_base = 1;
|
6139 |
6202 |
} else {
|
6140 |
|
gen_movl_reg_T0(s, i);
|
|
6203 |
store_reg(s, i, tmp);
|
6141 |
6204 |
}
|
6142 |
6205 |
} else {
|
6143 |
6206 |
/* store */
|
6144 |
6207 |
if (i == 15) {
|
6145 |
6208 |
/* special case: r15 = PC + 8 */
|
6146 |
6209 |
val = (long)s->pc + 4;
|
6147 |
|
gen_op_movl_T0_im(val);
|
|
6210 |
tmp = new_tmp();
|
|
6211 |
tcg_gen_movi_i32(tmp, val);
|
6148 |
6212 |
} else if (user) {
|
6149 |
|
gen_op_movl_T0_user(i);
|
|
6213 |
tmp = new_tmp();
|
|
6214 |
gen_helper_get_user_reg(tmp, tcg_const_i32(i));
|
6150 |
6215 |
} else {
|
6151 |
|
gen_movl_T0_reg(s, i);
|
|
6216 |
tmp = load_reg(s, i);
|
6152 |
6217 |
}
|
6153 |
|
gen_ldst(stl, s);
|
|
6218 |
gen_st32(tmp, addr, IS_USER(s));
|
6154 |
6219 |
}
|
6155 |
6220 |
j++;
|
6156 |
6221 |
/* no need to add after the last transfer */
|
6157 |
6222 |
if (j != n)
|
6158 |
|
gen_op_addl_T1_im(4);
|
|
6223 |
tcg_gen_addi_i32(addr, addr, 4);
|
6159 |
6224 |
}
|
6160 |
6225 |
}
|
6161 |
6226 |
if (insn & (1 << 21)) {
|
... | ... | |
6165 |
6230 |
/* pre increment */
|
6166 |
6231 |
} else {
|
6167 |
6232 |
/* post increment */
|
6168 |
|
gen_op_addl_T1_im(4);
|
|
6233 |
tcg_gen_addi_i32(addr, addr, 4);
|
6169 |
6234 |
}
|
6170 |
6235 |
} else {
|
6171 |
6236 |
if (insn & (1 << 24)) {
|
6172 |
6237 |
/* pre decrement */
|
6173 |
6238 |
if (n != 1)
|
6174 |
|
gen_op_addl_T1_im(-((n - 1) * 4));
|
|
6239 |
tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
|
6175 |
6240 |
} else {
|
6176 |
6241 |
/* post decrement */
|
6177 |
|
gen_op_addl_T1_im(-(n * 4));
|
|
6242 |
tcg_gen_addi_i32(addr, addr, -(n * 4));
|
6178 |
6243 |
}
|
6179 |
6244 |
}
|
6180 |
|
gen_movl_reg_T1(s, rn);
|
|
6245 |
store_reg(s, rn, addr);
|
|
6246 |
} else {
|
|
6247 |
dead_tmp(addr);
|
6181 |
6248 |
}
|
6182 |
6249 |
if (loaded_base) {
|
6183 |
|
gen_op_movl_T0_T2();
|
6184 |
|
gen_movl_reg_T0(s, rn);
|
|
6250 |
store_reg(s, rn, loaded_var);
|
6185 |
6251 |
}
|
6186 |
6252 |
if ((insn & (1 << 22)) && !user) {
|
6187 |
6253 |
/* Restore CPSR from SPSR. */
|
... | ... | |
6319 |
6385 |
is not legal. */
|
6320 |
6386 |
static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
|
6321 |
6387 |
{
|
6322 |
|
uint32_t insn, imm, shift, offset, addr;
|
|
6388 |
uint32_t insn, imm, shift, offset;
|
6323 |
6389 |
uint32_t rd, rn, rm, rs;
|
6324 |
6390 |
TCGv tmp;
|
6325 |
6391 |
TCGv tmp2;
|
6326 |
6392 |
TCGv tmp3;
|
|
6393 |
TCGv addr;
|
6327 |
6394 |
int op;
|
6328 |
6395 |
int shiftop;
|
6329 |
6396 |
int conds;
|
... | ... | |
6341 |
6408 |
tcg_gen_addi_i32(tmp, tmp, offset);
|
6342 |
6409 |
tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
|
6343 |
6410 |
|
6344 |
|
addr = (uint32_t)s->pc;
|
6345 |
6411 |
tmp2 = new_tmp();
|
6346 |
|
tcg_gen_movi_i32(tmp2, addr | 1);
|
|
6412 |
tcg_gen_movi_i32(tmp2, s->pc | 1);
|
6347 |
6413 |
store_reg(s, 14, tmp2);
|
6348 |
6414 |
gen_bx(s, tmp);
|
6349 |
6415 |
return 0;
|
... | ... | |
6354 |
6420 |
tmp = load_reg(s, 14);
|
6355 |
6421 |
tcg_gen_addi_i32(tmp, tmp, 14);
|
6356 |
6422 |
|
6357 |
|
addr = (uint32_t)s->pc;
|
6358 |
6423 |
tmp2 = new_tmp();
|
6359 |
|
tcg_gen_movi_i32(tmp2, addr | 1);
|
|
6424 |
tcg_gen_movi_i32(tmp2, s->pc | 1);
|
6360 |
6425 |
store_reg(s, 14, tmp2);
|
6361 |
6426 |
gen_bx(s, tmp);
|
6362 |
6427 |
return 0;
|
... | ... | |
6366 |
6431 |
16-bit instructions in case the second half causes an
|
6367 |
6432 |
prefetch abort. */
|
6368 |
6433 |
offset = ((int32_t)insn << 21) >> 9;
|
6369 |
|
addr = s->pc + 2 + offset;
|
6370 |
|
gen_op_movl_T0_im(addr);
|
|
6434 |
gen_op_movl_T0_im(s->pc + 2 + offset);
|
6371 |
6435 |
gen_movl_reg_T0(s, 14);
|
6372 |
6436 |
return 0;
|
6373 |
6437 |
}
|
... | ... | |
6396 |
6460 |
if (insn & 0x01200000) {
|
6397 |
6461 |
/* Load/store doubleword. */
|
6398 |
6462 |
if (rn == 15) {
|
6399 |
|
gen_op_movl_T1_im(s->pc & ~3);
|
|
6463 |
addr = new_tmp();
|
|
6464 |
tcg_gen_movi_i32(addr, s->pc & ~3);
|
6400 |
6465 |
} else {
|
6401 |
|
gen_movl_T1_reg(s, rn);
|
|
6466 |
addr = load_reg(s, rn);
|
6402 |
6467 |
}
|
6403 |
6468 |
offset = (insn & 0xff) * 4;
|
6404 |
6469 |
if ((insn & (1 << 23)) == 0)
|
6405 |
6470 |
offset = -offset;
|
6406 |
6471 |
if (insn & (1 << 24)) {
|
6407 |
|
gen_op_addl_T1_im(offset);
|
|
6472 |
tcg_gen_addi_i32(addr, addr, offset);
|
6408 |
6473 |
offset = 0;
|
6409 |
6474 |
}
|
6410 |
6475 |
if (insn & (1 << 20)) {
|
6411 |
6476 |
/* ldrd */
|
6412 |
|
gen_ldst(ldl, s);
|
6413 |
|
gen_movl_reg_T0(s, rs);
|
6414 |
|
gen_op_addl_T1_im(4);
|
6415 |
|
gen_ldst(ldl, s);
|
6416 |
|
gen_movl_reg_T0(s, rd);
|
|
6477 |
tmp = gen_ld32(addr, IS_USER(s));
|
|
6478 |
store_reg(s, rs, tmp);
|
|
6479 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
6480 |
tmp = gen_ld32(addr, IS_USER(s));
|
|
6481 |
store_reg(s, rd, tmp);
|
6417 |
6482 |
} else {
|
6418 |
6483 |
/* strd */
|
6419 |
|
gen_movl_T0_reg(s, rs);
|
6420 |
|
gen_ldst(stl, s);
|
6421 |
|
gen_op_addl_T1_im(4);
|
6422 |
|
gen_movl_T0_reg(s, rd);
|
6423 |
|
gen_ldst(stl, s);
|
|
6484 |
tmp = load_reg(s, rs);
|
|
6485 |
gen_st32(tmp, addr, IS_USER(s));
|
|
6486 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
6487 |
tmp = load_reg(s, rd);
|
|
6488 |
gen_st32(tmp, addr, IS_USER(s));
|
6424 |
6489 |
}
|
6425 |
6490 |
if (insn & (1 << 21)) {
|
6426 |
6491 |
/* Base writeback. */
|
6427 |
6492 |
if (rn == 15)
|
6428 |
6493 |
goto illegal_op;
|
6429 |
|
gen_op_addl_T1_im(offset - 4);
|
6430 |
|
gen_movl_reg_T1(s, rn);
|
|
6494 |
tcg_gen_addi_i32(addr, addr, offset - 4);
|
|
6495 |
store_reg(s, rn, addr);
|
|
6496 |
} else {
|
|
6497 |
dead_tmp(addr);
|
6431 |
6498 |
}
|
6432 |
6499 |
} else if ((insn & (1 << 23)) == 0) {
|
6433 |
6500 |
/* Load/store exclusive word. */
|
... | ... | |
6442 |
6509 |
} else if ((insn & (1 << 6)) == 0) {
|
6443 |
6510 |
/* Table Branch. */
|
6444 |
6511 |
if (rn == 15) {
|
6445 |
|
gen_op_movl_T1_im(s->pc);
|
|
6512 |
addr = new_tmp();
|
|
6513 |
tcg_gen_movi_i32(addr, s->pc);
|
6446 |
6514 |
} else {
|
6447 |
|
gen_movl_T1_reg(s, rn);
|
|
6515 |
addr = load_reg(s, rn);
|
6448 |
6516 |
}
|
6449 |
6517 |
tmp = load_reg(s, rm);
|
6450 |
|
tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
|
|
6518 |
tcg_gen_add_i32(addr, addr, tmp);
|
6451 |
6519 |
if (insn & (1 << 4)) {
|
6452 |
6520 |
/* tbh */
|
6453 |
|
tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
|
|
6521 |
tcg_gen_add_i32(addr, addr, tmp);
|
6454 |
6522 |
dead_tmp(tmp);
|
6455 |
|
gen_ldst(lduw, s);
|
|
6523 |
tmp = gen_ld16u(addr, IS_USER(s));
|
6456 |
6524 |
} else { /* tbb */
|
6457 |
6525 |
dead_tmp(tmp);
|
6458 |
|
gen_ldst(ldub, s);
|
|
6526 |
tmp = gen_ld8u(addr, IS_USER(s));
|
6459 |
6527 |
}
|
6460 |
|
tcg_gen_shli_i32(cpu_T[0], cpu_T[0], 1);
|
6461 |
|
tcg_gen_addi_i32(cpu_T[0], cpu_T[0], s->pc);
|
6462 |
|
gen_movl_reg_T0(s, 15);
|
|
6528 |
dead_tmp(addr);
|
|
6529 |
tcg_gen_shli_i32(tmp, tmp, 1);
|
|
6530 |
tcg_gen_addi_i32(tmp, tmp, s->pc);
|
|
6531 |
store_reg(s, 15, tmp);
|
6463 |
6532 |
} else {
|
6464 |
6533 |
/* Load/store exclusive byte/halfword/doubleword. */
|
6465 |
6534 |
op = (insn >> 4) & 0x3;
|
... | ... | |
6503 |
6572 |
/* Load/store multiple, RFE, SRS. */
|
6504 |
6573 |
if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
|
6505 |
6574 |
/* Not available in user mode. */
|
6506 |
|
if (!IS_USER(s))
|
|
6575 |
if (IS_USER(s))
|
6507 |
6576 |
goto illegal_op;
|
6508 |
6577 |
if (insn & (1 << 20)) {
|
6509 |
6578 |
/* rfe */
|
6510 |
|
gen_movl_T1_reg(s, rn);
|
6511 |
|
if (insn & (1 << 24)) {
|
6512 |
|
gen_op_addl_T1_im(4);
|
6513 |
|
} else {
|
6514 |
|
gen_op_addl_T1_im(-4);
|
6515 |
|
}
|
6516 |
|
/* Load CPSR into T2 and PC into T0. */
|
6517 |
|
gen_ldst(ldl, s);
|
6518 |
|
gen_op_movl_T2_T0();
|
6519 |
|
gen_op_addl_T1_im(-4);
|
6520 |
|
gen_ldst(ldl, s);
|
|
6579 |
addr = load_reg(s, rn);
|
|
6580 |
if ((insn & (1 << 24)) == 0)
|
|
6581 |
tcg_gen_addi_i32(addr, addr, -8);
|
|
6582 |
/* Load PC into tmp and CPSR into tmp2. */
|
|
6583 |
tmp = gen_ld32(addr, 0);
|
|
6584 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
6585 |
tmp2 = gen_ld32(addr, 0);
|
6521 |
6586 |
if (insn & (1 << 21)) {
|
6522 |
6587 |
/* Base writeback. */
|
6523 |
|
if (insn & (1 << 24))
|
6524 |
|
gen_op_addl_T1_im(8);
|
6525 |
|
gen_movl_reg_T1(s, rn);
|
|
6588 |
if (insn & (1 << 24)) {
|
|
6589 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
6590 |
} else {
|
|
6591 |
tcg_gen_addi_i32(addr, addr, -4);
|
|
6592 |
}
|
|
6593 |
store_reg(s, rn, addr);
|
|
6594 |
} else {
|
|
6595 |
dead_tmp(addr);
|
6526 |
6596 |
}
|
6527 |
|
gen_rfe(s);
|
|
6597 |
gen_rfe(s, tmp, tmp2);
|
6528 |
6598 |
} else {
|
6529 |
6599 |
/* srs */
|
6530 |
6600 |
op = (insn & 0x1f);
|
6531 |
6601 |
if (op == (env->uncached_cpsr & CPSR_M)) {
|
6532 |
|
gen_movl_T1_reg(s, 13);
|
|
6602 |
addr = load_reg(s, 13);
|
6533 |
6603 |
} else {
|
6534 |
|
gen_op_movl_T1_r13_banked(op);
|
|
6604 |
addr = new_tmp();
|
|
6605 |
gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op));
|
6535 |
6606 |
}
|
6536 |
6607 |
if ((insn & (1 << 24)) == 0) {
|
6537 |
|
gen_op_addl_T1_im(-8);
|
|
6608 |
tcg_gen_addi_i32(addr, addr, -8);
|
6538 |
6609 |
}
|
6539 |
|
gen_movl_T0_reg(s, 14);
|
6540 |
|
gen_ldst(stl, s);
|
6541 |
|
gen_helper_cpsr_read(cpu_T[0]);
|
6542 |
|
gen_op_addl_T1_im(4);
|
6543 |
|
gen_ldst(stl, s);
|
|
6610 |
tmp = load_reg(s, 14);
|
|
6611 |
gen_st32(tmp, addr, 0);
|
|
6612 |
tcg_gen_addi_i32(addr, addr, 4);
|
|
6613 |
tmp = new_tmp();
|
|
6614 |
gen_helper_cpsr_read(tmp);
|
|
6615 |
gen_st32(tmp, addr, 0);
|
6544 |
6616 |
if (insn & (1 << 21)) {
|
6545 |
6617 |
if ((insn & (1 << 24)) == 0) {
|
6546 |
|
gen_op_addl_T1_im(-4);
|
|
6618 |
tcg_gen_addi_i32(addr, addr, -4);
|
6547 |
6619 |
} else {
|
6548 |
|
gen_op_addl_T1_im(4);
|
|
6620 |
tcg_gen_addi_i32(addr, addr, 4);
|
6549 |
6621 |
}
|
6550 |
6622 |
if (op == (env->uncached_cpsr & CPSR_M)) {
|
6551 |
|
gen_movl_reg_T1(s, 13);
|
|
6623 |
store_reg(s, 13, addr);
|
6552 |
6624 |
} else {
|
6553 |
|
gen_op_movl_r13_T1_banked(op);
|
|
6625 |
gen_helper_set_r13_banked(cpu_env,
|
|
6626 |
tcg_const_i32(op), addr);
|
6554 |
6627 |
}
|
|
6628 |
} else {
|
|
6629 |
dead_tmp(addr);
|
6555 |
6630 |
}
|
6556 |
6631 |
}
|
6557 |
6632 |
} else {
|
6558 |
6633 |
int i;
|
6559 |
6634 |
/* Load/store multiple. */
|
6560 |
|
gen_movl_T1_reg(s, rn);
|
|
6635 |
addr = load_reg(s, rn);
|
6561 |
6636 |
offset = 0;
|
6562 |
6637 |
for (i = 0; i < 16; i++) {
|
6563 |
6638 |
if (insn & (1 << i))
|
6564 |
6639 |
offset += 4;
|
6565 |
6640 |
}
|
6566 |
6641 |
if (insn & (1 << 24)) {
|
6567 |
|
gen_op_addl_T1_im(-offset);
|
|
6642 |
tcg_gen_addi_i32(addr, addr, -offset);
|
6568 |
6643 |
}
|
6569 |
6644 |
|
6570 |
6645 |
for (i = 0; i < 16; i++) {
|
... | ... | |
6572 |
6647 |
continue;
|
6573 |
6648 |
if (insn & (1 << 20)) {
|
6574 |
6649 |
/* Load. */
|
6575 |
|
gen_ldst(ldl, s);
|
|
6650 |
tmp = gen_ld32(addr, IS_USER(s));
|
6576 |
6651 |
if (i == 15) {
|
6577 |
|
gen_bx_T0(s);
|
|
6652 |
gen_bx(s, tmp);
|
6578 |
6653 |
} else {
|
6579 |
|
gen_movl_reg_T0(s, i);
|
|
6654 |
store_reg(s, i, tmp);
|
6580 |
6655 |
}
|
6581 |
6656 |
} else {
|
6582 |
6657 |
/* Store. */
|
6583 |
|
gen_movl_T0_reg(s, i);
|
6584 |
|
gen_ldst(stl, s);
|
|
6658 |
tmp = load_reg(s, i);
|
|
6659 |
gen_st32(tmp, addr, IS_USER(s));
|
6585 |
6660 |
}
|
6586 |
|
gen_op_addl_T1_im(4);
|
|
6661 |
tcg_gen_addi_i32(addr, addr, 4);
|
6587 |
6662 |
}
|
6588 |
6663 |
if (insn & (1 << 21)) {
|
6589 |
6664 |
/* Base register writeback. */
|
6590 |
6665 |
if (insn & (1 << 24)) {
|
6591 |
|
gen_op_addl_T1_im(-offset);
|
|
6666 |
tcg_gen_addi_i32(addr, addr, -offset);
|
6592 |
6667 |
}
|
6593 |
6668 |
/* Fault if writeback register is in register list. */
|
6594 |
6669 |
if (insn & (1 << rn))
|
6595 |
6670 |
goto illegal_op;
|
6596 |
|
gen_movl_reg_T1(s, rn);
|
|
6671 |
store_reg(s, rn, addr);
|
|
6672 |
} else {
|
|
6673 |
dead_tmp(addr);
|
6597 |
6674 |
}
|
6598 |
6675 |
}
|
6599 |
6676 |
}
|
... | ... | |
6892 |
6969 |
offset ^= ((~insn) & (1 << 13)) << 10;
|
6893 |
6970 |
offset ^= ((~insn) & (1 << 11)) << 11;
|
6894 |
6971 |
|
6895 |
|
addr = s->pc;
|
6896 |
6972 |
if (insn & (1 << 14)) {
|
6897 |
6973 |
/* Branch and link. */
|
6898 |
|
gen_op_movl_T1_im(addr | 1);
|
|
6974 |
gen_op_movl_T1_im(s->pc | 1);
|
6899 |
6975 |
gen_movl_reg_T1(s, 14);
|
6900 |
6976 |
}
|
6901 |
6977 |
|
6902 |
|
addr += offset;
|
|
6978 |
offset += s->pc;
|
6903 |
6979 |
if (insn & (1 << 12)) {
|
6904 |
6980 |
/* b/bl */
|
6905 |
|
gen_jmp(s, addr);
|
|
6981 |
gen_jmp(s, offset);
|
6906 |
6982 |
} else {
|
6907 |
6983 |
/* blx */
|
6908 |
|
addr &= ~(uint32_t)2;
|
6909 |
|
gen_bx_im(s, addr);
|
|
6984 |
offset &= ~(uint32_t)2;
|
|
6985 |
gen_bx_im(s, offset);
|
6910 |
6986 |
}
|
6911 |
6987 |
} else if (((insn >> 23) & 7) == 7) {
|
6912 |
6988 |
/* Misc control */
|
... | ... | |
7025 |
7101 |
offset |= (insn & (1 << 11)) << 8;
|
7026 |
7102 |
|
7027 |
7103 |
/* jump to the offset */
|
7028 |
|
addr = s->pc + offset;
|
7029 |
|
gen_jmp(s, addr);
|
|
7104 |
gen_jmp(s, s->pc + offset);
|
7030 |
7105 |
}
|
7031 |
7106 |
} else {
|
7032 |
7107 |
/* Data processing immediate. */
|
... | ... | |
7114 |
7189 |
} else {
|
7115 |
7190 |
/* Add/sub 12-bit immediate. */
|
7116 |
7191 |
if (rn == 15) {
|
7117 |
|
addr = s->pc & ~(uint32_t)3;
|
|
7192 |
offset = s->pc & ~(uint32_t)3;
|
7118 |
7193 |
if (insn & (1 << 23))
|
7119 |
|
addr -= imm;
|
|
7194 |
offset -= imm;
|
7120 |
7195 |
else
|
7121 |
|
addr += imm;
|
7122 |
|
gen_op_movl_T0_im(addr);
|
|
7196 |
offset += imm;
|
|
7197 |
gen_op_movl_T0_im(offset);
|
7123 |
7198 |
} else {
|
7124 |
7199 |
gen_movl_T0_reg(s, rn);
|
7125 |
7200 |
gen_op_movl_T1_im(imm);
|
... | ... | |
7179 |
7254 |
{
|
7180 |
7255 |
int postinc = 0;
|
7181 |
7256 |
int writeback = 0;
|
|
7257 |
int user;
|
7182 |
7258 |
if ((insn & 0x01100000) == 0x01000000) {
|
7183 |
7259 |
if (disas_neon_ls_insn(env, s, insn))
|
7184 |
7260 |
goto illegal_op;
|
7185 |
7261 |
break;
|
7186 |
7262 |
}
|
|
7263 |
user = IS_USER(s);
|
7187 |
7264 |
if (rn == 15) {
|
|
7265 |
addr = new_tmp();
|
7188 |
7266 |
/* PC relative. */
|
7189 |
7267 |
/* s->pc has already been incremented by 4. */
|
7190 |
7268 |
imm = s->pc & 0xfffffffc;
|
... | ... | |
7192 |
7270 |
imm += insn & 0xfff;
|
7193 |
7271 |
else
|
7194 |
7272 |
imm -= insn & 0xfff;
|
7195 |
|
gen_op_movl_T1_im(imm);
|
|
7273 |
tcg_gen_movi_i32(addr, imm);
|
7196 |
7274 |
} else {
|
7197 |
|
gen_movl_T1_reg(s, rn);
|
|
7275 |
addr = load_reg(s, rn);
|
7198 |
7276 |
if (insn & (1 << 23)) {
|
7199 |
7277 |
/* Positive offset. */
|
7200 |
7278 |
imm = insn & 0xfff;
|
7201 |
|
gen_op_addl_T1_im(imm);
|
|
7279 |
tcg_gen_addi_i32(addr, addr, imm);
|
7202 |
7280 |
} else {
|
7203 |
7281 |
op = (insn >> 8) & 7;
|
7204 |
7282 |
imm = insn & 0xff;
|
... | ... | |
7210 |
7288 |
tmp = load_reg(s, rm);
|
7211 |
7289 |
if (shift)
|
7212 |
7290 |
tcg_gen_shli_i32(tmp, tmp, shift);
|
7213 |
|
tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
|
|
7291 |
tcg_gen_add_i32(addr, addr, tmp);
|
7214 |
7292 |
dead_tmp(tmp);
|
7215 |
7293 |
break;
|
7216 |
7294 |
case 4: /* Negative offset. */
|
7217 |
|
gen_op_addl_T1_im(-imm);
|
|
7295 |
tcg_gen_addi_i32(addr, addr, -imm);
|
7218 |
7296 |
break;
|
7219 |
7297 |
case 6: /* User privilege. */
|
7220 |
|
gen_op_addl_T1_im(imm);
|
|
7298 |
tcg_gen_addi_i32(addr, addr, imm);
|
|
7299 |
user = 1;
|
7221 |
7300 |
break;
|
7222 |
7301 |
case 1: /* Post-decrement. */
|
7223 |
7302 |
imm = -imm;
|
... | ... | |
7230 |
7309 |
imm = -imm;
|
7231 |
7310 |
/* Fall through. */
|
7232 |
7311 |
case 7: /* Pre-increment. */
|
7233 |
|
gen_op_addl_T1_im(imm);
|
|
7312 |
tcg_gen_addi_i32(addr, addr, imm);
|
7234 |
7313 |
writeback = 1;
|
7235 |
7314 |
break;
|
7236 |
7315 |
default:
|
... | ... | |
7247 |
7326 |
/* Memory hint. Implemented as NOP. */
|
7248 |
7327 |
} else {
|
7249 |
7328 |
switch (op) {
|
7250 |
|
case 0: gen_ldst(ldub, s); break;
|
7251 |
|
case 4: gen_ldst(ldsb, s); break;
|
7252 |
|
case 1: gen_ldst(lduw, s); break;
|
7253 |
|
case 5: gen_ldst(ldsw, s); break;
|
7254 |
|
case 2: gen_ldst(ldl, s); break;
|
|
7329 |
case 0: tmp = gen_ld8u(addr, user); break;
|
|
7330 |
case 4: tmp = gen_ld8s(addr, user); break;
|
|
7331 |
case 1: tmp = gen_ld16u(addr, user); break;
|
|
7332 |
case 5: tmp = gen_ld16s(addr, user); break;
|
|
7333 |
case 2: tmp = gen_ld32(addr, user); break;
|
7255 |
7334 |
default: goto illegal_op;
|
7256 |
7335 |
}
|
7257 |
7336 |
if (rs == 15) {
|
7258 |
|
gen_bx_T0(s);
|
|
7337 |
gen_bx(s, tmp);
|
7259 |
7338 |
} else {
|
7260 |
|
gen_movl_reg_T0(s, rs);
|
|
7339 |
store_reg(s, rs, tmp);
|
7261 |
7340 |
}
|
7262 |
7341 |
}
|
7263 |
7342 |
} else {
|
7264 |
7343 |
/* Store. */
|
7265 |
7344 |
if (rs == 15)
|
7266 |
7345 |
goto illegal_op;
|
7267 |
|
gen_movl_T0_reg(s, rs);
|
|
7346 |
tmp = load_reg(s, rs);
|
7268 |
7347 |
switch (op) {
|
7269 |
|
case 0: gen_ldst(stb, s); break;
|
7270 |
|
case 1: gen_ldst(stw, s); break;
|
7271 |
|
case 2: gen_ldst(stl, s); break;
|
|
7348 |
case 0: gen_st8(tmp, addr, user); break;
|
|
7349 |
case 1: gen_st16(tmp, addr, user); break;
|
|
7350 |
case 2: gen_st32(tmp, addr, user); break;
|
7272 |
7351 |
default: goto illegal_op;
|
7273 |
7352 |
}
|
7274 |
7353 |
}
|
7275 |
7354 |
if (postinc)
|
7276 |
|
gen_op_addl_T1_im(imm);
|
7277 |
|
if (writeback)
|
7278 |
|
gen_movl_reg_T1(s, rn);
|
|
7355 |
tcg_gen_addi_i32(addr, addr, imm);
|
|
7356 |
if (writeback) {
|
|
7357 |
store_reg(s, rn, addr);
|
|
7358 |
} else {
|
|
7359 |
dead_tmp(addr);
|
|
7360 |
}
|
7279 |
7361 |
}
|
7280 |
7362 |
break;
|
7281 |
7363 |
default:
|
... | ... | |
7293 |
7375 |
int i;
|
7294 |
7376 |
TCGv tmp;
|
7295 |
7377 |
TCGv tmp2;
|
|
7378 |
TCGv addr;
|
7296 |
7379 |
|
7297 |
7380 |
if (s->condexec_mask) {
|
7298 |
7381 |
cond = s->condexec_cond;
|
... | ... | |
7383 |
7466 |
/* load pc-relative. Bit 1 of PC is ignored. */
|
7384 |
7467 |
val = s->pc + 2 + ((insn & 0xff) * 4);
|
7385 |
7468 |
val &= ~(uint32_t)2;
|
7386 |
|
gen_op_movl_T1_im(val);
|
7387 |
|
gen_ldst(ldl, s);
|
7388 |
|
gen_movl_reg_T0(s, rd);
|
|
7469 |
addr = new_tmp();
|
|
7470 |
tcg_gen_movi_i32(addr, val);
|
|
7471 |
tmp = gen_ld32(addr, IS_USER(s));
|
|
7472 |
dead_tmp(addr);
|
|
7473 |
store_reg(s, rd, tmp);
|
7389 |
7474 |
break;
|
7390 |
7475 |
}
|
7391 |
7476 |
if (insn & (1 << 10)) {
|
... | ... | |
7410 |
7495 |
gen_movl_reg_T0(s, rd);
|
7411 |
7496 |
break;
|
7412 |
7497 |
case 3:/* branch [and link] exchange thumb register */
|
|
7498 |
tmp = load_reg(s, rm);
|
7413 |
7499 |
if (insn & (1 << 7)) {
|
7414 |
7500 |
val = (uint32_t)s->pc | 1;
|
7415 |
|
gen_op_movl_T1_im(val);
|
7416 |
|
gen_movl_reg_T1(s, 14);
|
|
7501 |
tmp2 = new_tmp();
|
|
7502 |
tcg_gen_movi_i32(tmp2, val);
|
|
7503 |
store_reg(s, 14, tmp2);
|
7417 |
7504 |
}
|
7418 |
|
tmp = load_reg(s, rm);
|
7419 |
7505 |
gen_bx(s, tmp);
|
7420 |
7506 |
break;
|
7421 |
7507 |
}
|
... | ... | |
7553 |
7639 |
rn = (insn >> 3) & 7;
|