| 28 |
#include "exec-all.h" |
#include "exec-all.h" |
| 29 |
#include "disas.h" |
#include "disas.h" |
| 30 |
|
|
| 31 |
|
#define ENABLE_ARCH_5J 0 |
| 32 |
|
#define ENABLE_ARCH_6 1 |
| 33 |
|
#define ENABLE_ARCH_6T2 1 |
| 34 |
|
|
| 35 |
|
#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op; |
| 36 |
|
|
| 37 |
/* internal defines */ |
/* internal defines */ |
| 38 |
typedef struct DisasContext { |
typedef struct DisasContext { |
| 39 |
target_ulong pc; |
target_ulong pc; |
| 45 |
struct TranslationBlock *tb; |
struct TranslationBlock *tb; |
| 46 |
int singlestep_enabled; |
int singlestep_enabled; |
| 47 |
int thumb; |
int thumb; |
| 48 |
|
#if !defined(CONFIG_USER_ONLY) |
| 49 |
|
int user; |
| 50 |
|
#endif |
| 51 |
} DisasContext; |
} DisasContext; |
| 52 |
|
|
| 53 |
|
#if defined(CONFIG_USER_ONLY) |
| 54 |
|
#define IS_USER(s) 1 |
| 55 |
|
#else |
| 56 |
|
#define IS_USER(s) (s->user) |
| 57 |
|
#endif |
| 58 |
|
|
| 59 |
#define DISAS_JUMP_NEXT 4 |
#define DISAS_JUMP_NEXT 4 |
| 60 |
|
|
| 61 |
#ifdef USE_DIRECT_JUMP |
#ifdef USE_DIRECT_JUMP |
| 285 |
gen_op_bx_T0(); |
gen_op_bx_T0(); |
| 286 |
} |
} |
| 287 |
|
|
| 288 |
|
|
| 289 |
|
#if defined(CONFIG_USER_ONLY) |
| 290 |
|
#define gen_ldst(name, s) gen_op_##name##_raw() |
| 291 |
|
#else |
| 292 |
|
#define gen_ldst(name, s) do { \ |
| 293 |
|
if (IS_USER(s)) \ |
| 294 |
|
gen_op_##name##_user(); \ |
| 295 |
|
else \ |
| 296 |
|
gen_op_##name##_kernel(); \ |
| 297 |
|
} while (0) |
| 298 |
|
#endif |
| 299 |
|
|
| 300 |
static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) |
static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) |
| 301 |
{ |
{ |
| 302 |
int val; |
int val; |
| 346 |
gen_movl_reg_TN(s, reg, 1); |
gen_movl_reg_TN(s, reg, 1); |
| 347 |
} |
} |
| 348 |
|
|
| 349 |
|
/* Force a TB lookup after an instruction that changes the CPU state. */ |
| 350 |
|
static inline void gen_lookup_tb(DisasContext *s) |
| 351 |
|
{ |
| 352 |
|
gen_op_movl_T0_im(s->pc); |
| 353 |
|
gen_movl_reg_T0(s, 15); |
| 354 |
|
s->is_jmp = DISAS_UPDATE; |
| 355 |
|
} |
| 356 |
|
|
| 357 |
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) |
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) |
| 358 |
{ |
{ |
| 359 |
int val, rm, shift, shiftop; |
int val, rm, shift, shiftop; |
| 430 |
VFP_OP(touiz) |
VFP_OP(touiz) |
| 431 |
VFP_OP(tosi) |
VFP_OP(tosi) |
| 432 |
VFP_OP(tosiz) |
VFP_OP(tosiz) |
|
VFP_OP(ld) |
|
|
VFP_OP(st) |
|
| 433 |
|
|
| 434 |
#undef VFP_OP |
#undef VFP_OP |
| 435 |
|
|
| 436 |
|
static inline void gen_vfp_ld(DisasContext *s, int dp) |
| 437 |
|
{ |
| 438 |
|
if (dp) |
| 439 |
|
gen_ldst(vfp_ldd, s); |
| 440 |
|
else |
| 441 |
|
gen_ldst(vfp_lds, s); |
| 442 |
|
} |
| 443 |
|
|
| 444 |
|
static inline void gen_vfp_st(DisasContext *s, int dp) |
| 445 |
|
{ |
| 446 |
|
if (dp) |
| 447 |
|
gen_ldst(vfp_std, s); |
| 448 |
|
else |
| 449 |
|
gen_ldst(vfp_sts, s); |
| 450 |
|
} |
| 451 |
|
|
| 452 |
static inline long |
static inline long |
| 453 |
vfp_reg_offset (int dp, int reg) |
vfp_reg_offset (int dp, int reg) |
| 454 |
{ |
{ |
| 486 |
gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); |
gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); |
| 487 |
} |
} |
| 488 |
|
|
| 489 |
|
/* Disassemble system coprocessor (cp15) instruction. Return nonzero if |
| 490 |
|
instruction is not defined. */ |
| 491 |
|
static int disas_cp15_insn(DisasContext *s, uint32_t insn) |
| 492 |
|
{ |
| 493 |
|
uint32_t rd; |
| 494 |
|
|
| 495 |
|
/* ??? Some cp15 registers are accessible from userspace. */ |
| 496 |
|
if (IS_USER(s)) { |
| 497 |
|
return 1; |
| 498 |
|
} |
| 499 |
|
rd = (insn >> 12) & 0xf; |
| 500 |
|
if (insn & (1 << 20)) { |
| 501 |
|
gen_op_movl_T0_cp15(insn); |
| 502 |
|
/* If the destination register is r15 then sets condition codes. */ |
| 503 |
|
if (rd != 15) |
| 504 |
|
gen_movl_reg_T0(s, rd); |
| 505 |
|
} else { |
| 506 |
|
gen_movl_T0_reg(s, rd); |
| 507 |
|
gen_op_movl_cp15_T0(insn); |
| 508 |
|
} |
| 509 |
|
gen_lookup_tb(s); |
| 510 |
|
return 0; |
| 511 |
|
} |
| 512 |
|
|
| 513 |
/* Disassemble a VFP instruction. Returns nonzero if an error occured |
/* Disassemble a VFP instruction. Returns nonzero if an error occured |
| 514 |
(ie. an undefined instruction). */ |
(ie. an undefined instruction). */ |
| 515 |
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) |
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) |
| 572 |
gen_op_vfp_mrs(); |
gen_op_vfp_mrs(); |
| 573 |
} |
} |
| 574 |
if (rd == 15) { |
if (rd == 15) { |
| 575 |
/* This will only set the 4 flag bits */ |
/* Set the 4 flag bits in the CPSR. */ |
| 576 |
gen_op_movl_psr_T0(); |
gen_op_movl_cpsr_T0(0xf0000000); |
| 577 |
} else |
} else |
| 578 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 579 |
} else { |
} else { |
| 589 |
gen_op_vfp_movl_fpscr_T0(); |
gen_op_vfp_movl_fpscr_T0(); |
| 590 |
/* This could change vector settings, so jump to |
/* This could change vector settings, so jump to |
| 591 |
the next instuction. */ |
the next instuction. */ |
| 592 |
gen_op_movl_T0_im(s->pc); |
gen_lookup_tb(s); |
|
gen_movl_reg_T0(s, 15); |
|
|
s->is_jmp = DISAS_UPDATE; |
|
| 593 |
break; |
break; |
| 594 |
default: |
default: |
| 595 |
return 1; |
return 1; |
| 919 |
offset = -offset; |
offset = -offset; |
| 920 |
gen_op_addl_T1_im(offset); |
gen_op_addl_T1_im(offset); |
| 921 |
if (insn & (1 << 20)) { |
if (insn & (1 << 20)) { |
| 922 |
gen_vfp_ld(dp); |
gen_vfp_ld(s, dp); |
| 923 |
gen_mov_vreg_F0(dp, rd); |
gen_mov_vreg_F0(dp, rd); |
| 924 |
} else { |
} else { |
| 925 |
gen_mov_F0_vreg(dp, rd); |
gen_mov_F0_vreg(dp, rd); |
| 926 |
gen_vfp_st(dp); |
gen_vfp_st(s, dp); |
| 927 |
} |
} |
| 928 |
} else { |
} else { |
| 929 |
/* load/store multiple */ |
/* load/store multiple */ |
| 942 |
for (i = 0; i < n; i++) { |
for (i = 0; i < n; i++) { |
| 943 |
if (insn & (1 << 20)) { |
if (insn & (1 << 20)) { |
| 944 |
/* load */ |
/* load */ |
| 945 |
gen_vfp_ld(dp); |
gen_vfp_ld(s, dp); |
| 946 |
gen_mov_vreg_F0(dp, rd + i); |
gen_mov_vreg_F0(dp, rd + i); |
| 947 |
} else { |
} else { |
| 948 |
/* store */ |
/* store */ |
| 949 |
gen_mov_F0_vreg(dp, rd + i); |
gen_mov_F0_vreg(dp, rd + i); |
| 950 |
gen_vfp_st(dp); |
gen_vfp_st(s, dp); |
| 951 |
} |
} |
| 952 |
gen_op_addl_T1_im(offset); |
gen_op_addl_T1_im(offset); |
| 953 |
} |
} |
| 1010 |
} |
} |
| 1011 |
} |
} |
| 1012 |
|
|
| 1013 |
|
static inline void gen_mulxy(int x, int y) |
| 1014 |
|
{ |
| 1015 |
|
if (x & 2) |
| 1016 |
|
gen_op_sarl_T0_im(16); |
| 1017 |
|
else |
| 1018 |
|
gen_op_sxth_T0(); |
| 1019 |
|
if (y & 1) |
| 1020 |
|
gen_op_sarl_T1_im(16); |
| 1021 |
|
else |
| 1022 |
|
gen_op_sxth_T1(); |
| 1023 |
|
gen_op_mul_T0_T1(); |
| 1024 |
|
} |
| 1025 |
|
|
| 1026 |
|
/* Return the mask of PSR bits set by a MSR instruction. */ |
| 1027 |
|
static uint32_t msr_mask(DisasContext *s, int flags) { |
| 1028 |
|
uint32_t mask; |
| 1029 |
|
|
| 1030 |
|
mask = 0; |
| 1031 |
|
if (flags & (1 << 0)) |
| 1032 |
|
mask |= 0xff; |
| 1033 |
|
if (flags & (1 << 1)) |
| 1034 |
|
mask |= 0xff00; |
| 1035 |
|
if (flags & (1 << 2)) |
| 1036 |
|
mask |= 0xff0000; |
| 1037 |
|
if (flags & (1 << 3)) |
| 1038 |
|
mask |= 0xff000000; |
| 1039 |
|
/* Mask out undefined bits and state bits. */ |
| 1040 |
|
mask &= 0xf89f03df; |
| 1041 |
|
/* Mask out privileged bits. */ |
| 1042 |
|
if (IS_USER(s)) |
| 1043 |
|
mask &= 0xf80f0200; |
| 1044 |
|
return mask; |
| 1045 |
|
} |
| 1046 |
|
|
| 1047 |
|
/* Returns nonzero if access to the PSR is not permitted. */ |
| 1048 |
|
static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr) |
| 1049 |
|
{ |
| 1050 |
|
if (spsr) { |
| 1051 |
|
/* ??? This is also undefined in system mode. */ |
| 1052 |
|
if (IS_USER(s)) |
| 1053 |
|
return 1; |
| 1054 |
|
gen_op_movl_spsr_T0(mask); |
| 1055 |
|
} else { |
| 1056 |
|
gen_op_movl_cpsr_T0(mask); |
| 1057 |
|
} |
| 1058 |
|
gen_lookup_tb(s); |
| 1059 |
|
return 0; |
| 1060 |
|
} |
| 1061 |
|
|
| 1062 |
|
static void gen_exception_return(DisasContext *s) |
| 1063 |
|
{ |
| 1064 |
|
gen_op_movl_reg_TN[0][15](); |
| 1065 |
|
gen_op_movl_T0_spsr(); |
| 1066 |
|
gen_op_movl_cpsr_T0(0xffffffff); |
| 1067 |
|
s->is_jmp = DISAS_UPDATE; |
| 1068 |
|
} |
| 1069 |
|
|
| 1070 |
static void disas_arm_insn(CPUState * env, DisasContext *s) |
static void disas_arm_insn(CPUState * env, DisasContext *s) |
| 1071 |
{ |
{ |
| 1072 |
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; |
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; |
| 1073 |
|
|
| 1074 |
insn = ldl(s->pc); |
insn = ldl_code(s->pc); |
| 1075 |
s->pc += 4; |
s->pc += 4; |
| 1076 |
|
|
| 1077 |
cond = insn >> 28; |
cond = insn >> 28; |
| 1099 |
/* Coprocessor double register transfer. */ |
/* Coprocessor double register transfer. */ |
| 1100 |
} else if ((insn & 0x0f000010) == 0x0e000010) { |
} else if ((insn & 0x0f000010) == 0x0e000010) { |
| 1101 |
/* Additional coprocessor register transfer. */ |
/* Additional coprocessor register transfer. */ |
| 1102 |
|
} else if ((insn & 0x0ff10010) == 0x01000000) { |
| 1103 |
|
/* cps (privileged) */ |
| 1104 |
|
} else if ((insn & 0x0ffffdff) == 0x01010000) { |
| 1105 |
|
/* setend */ |
| 1106 |
|
if (insn & (1 << 9)) { |
| 1107 |
|
/* BE8 mode not implemented. */ |
| 1108 |
|
goto illegal_op; |
| 1109 |
|
} |
| 1110 |
|
return; |
| 1111 |
} |
} |
| 1112 |
goto illegal_op; |
goto illegal_op; |
| 1113 |
} |
} |
| 1121 |
//s->is_jmp = DISAS_JUMP_NEXT; |
//s->is_jmp = DISAS_JUMP_NEXT; |
| 1122 |
} |
} |
| 1123 |
if ((insn & 0x0f900000) == 0x03000000) { |
if ((insn & 0x0f900000) == 0x03000000) { |
| 1124 |
if ((insn & 0x0ff0f000) != 0x0360f000) |
if ((insn & 0x0fb0f000) != 0x0320f000) |
| 1125 |
goto illegal_op; |
goto illegal_op; |
| 1126 |
/* CPSR = immediate */ |
/* CPSR = immediate */ |
| 1127 |
val = insn & 0xff; |
val = insn & 0xff; |
| 1129 |
if (shift) |
if (shift) |
| 1130 |
val = (val >> shift) | (val << (32 - shift)); |
val = (val >> shift) | (val << (32 - shift)); |
| 1131 |
gen_op_movl_T0_im(val); |
gen_op_movl_T0_im(val); |
| 1132 |
if (insn & (1 << 19)) |
if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf), |
| 1133 |
gen_op_movl_psr_T0(); |
(insn & (1 << 22)) != 0)) |
| 1134 |
|
goto illegal_op; |
| 1135 |
} else if ((insn & 0x0f900000) == 0x01000000 |
} else if ((insn & 0x0f900000) == 0x01000000 |
| 1136 |
&& (insn & 0x00000090) != 0x00000090) { |
&& (insn & 0x00000090) != 0x00000090) { |
| 1137 |
/* miscellaneous instructions */ |
/* miscellaneous instructions */ |
| 1140 |
rm = insn & 0xf; |
rm = insn & 0xf; |
| 1141 |
switch (sh) { |
switch (sh) { |
| 1142 |
case 0x0: /* move program status register */ |
case 0x0: /* move program status register */ |
|
if (op1 & 2) { |
|
|
/* SPSR not accessible in user mode */ |
|
|
goto illegal_op; |
|
|
} |
|
| 1143 |
if (op1 & 1) { |
if (op1 & 1) { |
| 1144 |
/* CPSR = reg */ |
/* PSR = reg */ |
| 1145 |
gen_movl_T0_reg(s, rm); |
gen_movl_T0_reg(s, rm); |
| 1146 |
if (insn & (1 << 19)) |
if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf), |
| 1147 |
gen_op_movl_psr_T0(); |
(op1 & 2) != 0)) |
| 1148 |
|
goto illegal_op; |
| 1149 |
} else { |
} else { |
| 1150 |
/* reg = CPSR */ |
/* reg = CPSR */ |
| 1151 |
rd = (insn >> 12) & 0xf; |
rd = (insn >> 12) & 0xf; |
| 1152 |
gen_op_movl_T0_psr(); |
if (op1 & 2) { |
| 1153 |
|
if (IS_USER(s)) |
| 1154 |
|
goto illegal_op; |
| 1155 |
|
gen_op_movl_T0_spsr(); |
| 1156 |
|
} else { |
| 1157 |
|
gen_op_movl_T0_cpsr(); |
| 1158 |
|
} |
| 1159 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 1160 |
} |
} |
| 1161 |
break; |
break; |
| 1174 |
goto illegal_op; |
goto illegal_op; |
| 1175 |
} |
} |
| 1176 |
break; |
break; |
| 1177 |
|
case 0x2: |
| 1178 |
|
if (op1 == 1) { |
| 1179 |
|
ARCH(5J); /* bxj */ |
| 1180 |
|
/* Trivial implementation equivalent to bx. */ |
| 1181 |
|
gen_movl_T0_reg(s, rm); |
| 1182 |
|
gen_bx(s); |
| 1183 |
|
} else { |
| 1184 |
|
goto illegal_op; |
| 1185 |
|
} |
| 1186 |
|
break; |
| 1187 |
case 0x3: |
case 0x3: |
| 1188 |
if (op1 != 1) |
if (op1 != 1) |
| 1189 |
goto illegal_op; |
goto illegal_op; |
| 1222 |
if (sh & 4) |
if (sh & 4) |
| 1223 |
gen_op_sarl_T1_im(16); |
gen_op_sarl_T1_im(16); |
| 1224 |
else |
else |
| 1225 |
gen_op_sxl_T1(); |
gen_op_sxth_T1(); |
| 1226 |
gen_op_imulw_T0_T1(); |
gen_op_imulw_T0_T1(); |
| 1227 |
if ((sh & 2) == 0) { |
if ((sh & 2) == 0) { |
| 1228 |
gen_movl_T1_reg(s, rn); |
gen_movl_T1_reg(s, rn); |
| 1232 |
} else { |
} else { |
| 1233 |
/* 16 * 16 */ |
/* 16 * 16 */ |
| 1234 |
gen_movl_T0_reg(s, rm); |
gen_movl_T0_reg(s, rm); |
|
if (sh & 2) |
|
|
gen_op_sarl_T0_im(16); |
|
|
else |
|
|
gen_op_sxl_T0(); |
|
| 1235 |
gen_movl_T1_reg(s, rs); |
gen_movl_T1_reg(s, rs); |
| 1236 |
if (sh & 4) |
gen_mulxy(sh & 2, sh & 4); |
|
gen_op_sarl_T1_im(16); |
|
|
else |
|
|
gen_op_sxl_T1(); |
|
| 1237 |
if (op1 == 2) { |
if (op1 == 2) { |
| 1238 |
gen_op_imull_T0_T1(); |
gen_op_signbit_T1_T0(); |
| 1239 |
gen_op_addq_T0_T1(rn, rd); |
gen_op_addq_T0_T1(rn, rd); |
| 1240 |
gen_movl_reg_T0(s, rn); |
gen_movl_reg_T0(s, rn); |
| 1241 |
gen_movl_reg_T1(s, rd); |
gen_movl_reg_T1(s, rd); |
| 1242 |
} else { |
} else { |
|
gen_op_mul_T0_T1(); |
|
| 1243 |
if (op1 == 0) { |
if (op1 == 0) { |
| 1244 |
gen_movl_T1_reg(s, rn); |
gen_movl_T1_reg(s, rn); |
| 1245 |
gen_op_addl_T0_T1_setq(); |
gen_op_addl_T0_T1_setq(); |
| 1319 |
gen_op_logic_T0_cc(); |
gen_op_logic_T0_cc(); |
| 1320 |
break; |
break; |
| 1321 |
case 0x02: |
case 0x02: |
| 1322 |
if (set_cc) |
if (set_cc && rd == 15) { |
| 1323 |
|
/* SUBS r15, ... is used for exception return. */ |
| 1324 |
|
if (IS_USER(s)) |
| 1325 |
|
goto illegal_op; |
| 1326 |
gen_op_subl_T0_T1_cc(); |
gen_op_subl_T0_T1_cc(); |
| 1327 |
else |
gen_exception_return(s); |
| 1328 |
gen_op_subl_T0_T1(); |
} else { |
| 1329 |
gen_movl_reg_T0(s, rd); |
if (set_cc) |
| 1330 |
|
gen_op_subl_T0_T1_cc(); |
| 1331 |
|
else |
| 1332 |
|
gen_op_subl_T0_T1(); |
| 1333 |
|
gen_movl_reg_T0(s, rd); |
| 1334 |
|
} |
| 1335 |
break; |
break; |
| 1336 |
case 0x03: |
case 0x03: |
| 1337 |
if (set_cc) |
if (set_cc) |
| 1397 |
gen_op_logic_T0_cc(); |
gen_op_logic_T0_cc(); |
| 1398 |
break; |
break; |
| 1399 |
case 0x0d: |
case 0x0d: |
| 1400 |
gen_movl_reg_T1(s, rd); |
if (logic_cc && rd == 15) { |
| 1401 |
if (logic_cc) |
/* MOVS r15, ... is used for exception return. */ |
| 1402 |
gen_op_logic_T1_cc(); |
if (IS_USER(s)) |
| 1403 |
|
goto illegal_op; |
| 1404 |
|
gen_op_movl_T0_T1(); |
| 1405 |
|
gen_exception_return(s); |
| 1406 |
|
} else { |
| 1407 |
|
gen_movl_reg_T1(s, rd); |
| 1408 |
|
if (logic_cc) |
| 1409 |
|
gen_op_logic_T1_cc(); |
| 1410 |
|
} |
| 1411 |
break; |
break; |
| 1412 |
case 0x0e: |
case 0x0e: |
| 1413 |
gen_op_bicl_T0_T1(); |
gen_op_bicl_T0_T1(); |
| 1460 |
if (insn & (1 << 21)) /* mult accumulate */ |
if (insn & (1 << 21)) /* mult accumulate */ |
| 1461 |
gen_op_addq_T0_T1(rn, rd); |
gen_op_addq_T0_T1(rn, rd); |
| 1462 |
if (!(insn & (1 << 23))) { /* double accumulate */ |
if (!(insn & (1 << 23))) { /* double accumulate */ |
| 1463 |
|
ARCH(6); |
| 1464 |
gen_op_addq_lo_T0_T1(rn); |
gen_op_addq_lo_T0_T1(rn); |
| 1465 |
gen_op_addq_lo_T0_T1(rd); |
gen_op_addq_lo_T0_T1(rd); |
| 1466 |
} |
} |
| 1482 |
gen_movl_T0_reg(s, rm); |
gen_movl_T0_reg(s, rm); |
| 1483 |
gen_movl_T1_reg(s, rn); |
gen_movl_T1_reg(s, rn); |
| 1484 |
if (insn & (1 << 22)) { |
if (insn & (1 << 22)) { |
| 1485 |
gen_op_swpb_T0_T1(); |
gen_ldst(swpb, s); |
| 1486 |
} else { |
} else { |
| 1487 |
gen_op_swpl_T0_T1(); |
gen_ldst(swpl, s); |
| 1488 |
} |
} |
| 1489 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 1490 |
} |
} |
| 1500 |
/* load */ |
/* load */ |
| 1501 |
switch(sh) { |
switch(sh) { |
| 1502 |
case 1: |
case 1: |
| 1503 |
gen_op_lduw_T0_T1(); |
gen_ldst(lduw, s); |
| 1504 |
break; |
break; |
| 1505 |
case 2: |
case 2: |
| 1506 |
gen_op_ldsb_T0_T1(); |
gen_ldst(ldsb, s); |
| 1507 |
break; |
break; |
| 1508 |
default: |
default: |
| 1509 |
case 3: |
case 3: |
| 1510 |
gen_op_ldsw_T0_T1(); |
gen_ldst(ldsw, s); |
| 1511 |
break; |
break; |
| 1512 |
} |
} |
| 1513 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 1516 |
if (sh & 1) { |
if (sh & 1) { |
| 1517 |
/* store */ |
/* store */ |
| 1518 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 1519 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 1520 |
gen_op_addl_T1_im(4); |
gen_op_addl_T1_im(4); |
| 1521 |
gen_movl_T0_reg(s, rd + 1); |
gen_movl_T0_reg(s, rd + 1); |
| 1522 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 1523 |
if ((insn & (1 << 24)) || (insn & (1 << 20))) |
if ((insn & (1 << 24)) || (insn & (1 << 20))) |
| 1524 |
gen_op_addl_T1_im(-4); |
gen_op_addl_T1_im(-4); |
| 1525 |
} else { |
} else { |
| 1526 |
/* load */ |
/* load */ |
| 1527 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 1528 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 1529 |
gen_op_addl_T1_im(4); |
gen_op_addl_T1_im(4); |
| 1530 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 1531 |
gen_movl_reg_T0(s, rd + 1); |
gen_movl_reg_T0(s, rd + 1); |
| 1532 |
if ((insn & (1 << 24)) || (insn & (1 << 20))) |
if ((insn & (1 << 24)) || (insn & (1 << 20))) |
| 1533 |
gen_op_addl_T1_im(-4); |
gen_op_addl_T1_im(-4); |
| 1535 |
} else { |
} else { |
| 1536 |
/* store */ |
/* store */ |
| 1537 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 1538 |
gen_op_stw_T0_T1(); |
gen_ldst(stw, s); |
| 1539 |
} |
} |
| 1540 |
if (!(insn & (1 << 24))) { |
if (!(insn & (1 << 24))) { |
| 1541 |
gen_add_datah_offset(s, insn); |
gen_add_datah_offset(s, insn); |
| 1553 |
rn = (insn >> 16) & 0xf; |
rn = (insn >> 16) & 0xf; |
| 1554 |
rd = (insn >> 12) & 0xf; |
rd = (insn >> 12) & 0xf; |
| 1555 |
gen_movl_T1_reg(s, rn); |
gen_movl_T1_reg(s, rn); |
| 1556 |
|
i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); |
| 1557 |
if (insn & (1 << 24)) |
if (insn & (1 << 24)) |
| 1558 |
gen_add_data_offset(s, insn); |
gen_add_data_offset(s, insn); |
| 1559 |
if (insn & (1 << 20)) { |
if (insn & (1 << 20)) { |
| 1560 |
/* load */ |
/* load */ |
| 1561 |
|
#if defined(CONFIG_USER_ONLY) |
| 1562 |
if (insn & (1 << 22)) |
if (insn & (1 << 22)) |
| 1563 |
gen_op_ldub_T0_T1(); |
gen_op_ldub_raw(); |
| 1564 |
else |
else |
| 1565 |
gen_op_ldl_T0_T1(); |
gen_op_ldl_raw(); |
| 1566 |
|
#else |
| 1567 |
|
if (insn & (1 << 22)) { |
| 1568 |
|
if (i) |
| 1569 |
|
gen_op_ldub_user(); |
| 1570 |
|
else |
| 1571 |
|
gen_op_ldub_kernel(); |
| 1572 |
|
} else { |
| 1573 |
|
if (i) |
| 1574 |
|
gen_op_ldl_user(); |
| 1575 |
|
else |
| 1576 |
|
gen_op_ldl_kernel(); |
| 1577 |
|
} |
| 1578 |
|
#endif |
| 1579 |
if (rd == 15) |
if (rd == 15) |
| 1580 |
gen_bx(s); |
gen_bx(s); |
| 1581 |
else |
else |
| 1583 |
} else { |
} else { |
| 1584 |
/* store */ |
/* store */ |
| 1585 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 1586 |
|
#if defined(CONFIG_USER_ONLY) |
| 1587 |
if (insn & (1 << 22)) |
if (insn & (1 << 22)) |
| 1588 |
gen_op_stb_T0_T1(); |
gen_op_stb_raw(); |
| 1589 |
else |
else |
| 1590 |
gen_op_stl_T0_T1(); |
gen_op_stl_raw(); |
| 1591 |
|
#else |
| 1592 |
|
if (insn & (1 << 22)) { |
| 1593 |
|
if (i) |
| 1594 |
|
gen_op_stb_user(); |
| 1595 |
|
else |
| 1596 |
|
gen_op_stb_kernel(); |
| 1597 |
|
} else { |
| 1598 |
|
if (i) |
| 1599 |
|
gen_op_stl_user(); |
| 1600 |
|
else |
| 1601 |
|
gen_op_stl_kernel(); |
| 1602 |
|
} |
| 1603 |
|
#endif |
| 1604 |
} |
} |
| 1605 |
if (!(insn & (1 << 24))) { |
if (!(insn & (1 << 24))) { |
| 1606 |
gen_add_data_offset(s, insn); |
gen_add_data_offset(s, insn); |
| 1612 |
case 0x08: |
case 0x08: |
| 1613 |
case 0x09: |
case 0x09: |
| 1614 |
{ |
{ |
| 1615 |
int j, n; |
int j, n, user; |
| 1616 |
/* load/store multiple words */ |
/* load/store multiple words */ |
| 1617 |
/* XXX: store correct base if write back */ |
/* XXX: store correct base if write back */ |
| 1618 |
if (insn & (1 << 22)) |
user = 0; |
| 1619 |
goto illegal_op; /* only usable in supervisor mode */ |
if (insn & (1 << 22)) { |
| 1620 |
|
if (IS_USER(s)) |
| 1621 |
|
goto illegal_op; /* only usable in supervisor mode */ |
| 1622 |
|
|
| 1623 |
|
if ((insn & (1 << 15)) == 0) |
| 1624 |
|
user = 1; |
| 1625 |
|
} |
| 1626 |
rn = (insn >> 16) & 0xf; |
rn = (insn >> 16) & 0xf; |
| 1627 |
gen_movl_T1_reg(s, rn); |
gen_movl_T1_reg(s, rn); |
| 1628 |
|
|
| 1655 |
if (insn & (1 << i)) { |
if (insn & (1 << i)) { |
| 1656 |
if (insn & (1 << 20)) { |
if (insn & (1 << 20)) { |
| 1657 |
/* load */ |
/* load */ |
| 1658 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 1659 |
if (i == 15) |
if (i == 15) { |
| 1660 |
gen_bx(s); |
gen_bx(s); |
| 1661 |
else |
} else if (user) { |
| 1662 |
|
gen_op_movl_user_T0(i); |
| 1663 |
|
} else { |
| 1664 |
gen_movl_reg_T0(s, i); |
gen_movl_reg_T0(s, i); |
| 1665 |
|
} |
| 1666 |
} else { |
} else { |
| 1667 |
/* store */ |
/* store */ |
| 1668 |
if (i == 15) { |
if (i == 15) { |
| 1669 |
/* special case: r15 = PC + 12 */ |
/* special case: r15 = PC + 12 */ |
| 1670 |
val = (long)s->pc + 8; |
val = (long)s->pc + 8; |
| 1671 |
gen_op_movl_TN_im[0](val); |
gen_op_movl_TN_im[0](val); |
| 1672 |
|
} else if (user) { |
| 1673 |
|
gen_op_movl_T0_user(i); |
| 1674 |
} else { |
} else { |
| 1675 |
gen_movl_T0_reg(s, i); |
gen_movl_T0_reg(s, i); |
| 1676 |
} |
} |
| 1677 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 1678 |
} |
} |
| 1679 |
j++; |
j++; |
| 1680 |
/* no need to add after the last transfer */ |
/* no need to add after the last transfer */ |
| 1703 |
} |
} |
| 1704 |
gen_movl_reg_T1(s, rn); |
gen_movl_reg_T1(s, rn); |
| 1705 |
} |
} |
| 1706 |
|
if ((insn & (1 << 22)) && !user) { |
| 1707 |
|
/* Restore CPSR from SPSR. */ |
| 1708 |
|
gen_op_movl_T0_spsr(); |
| 1709 |
|
gen_op_movl_cpsr_T0(0xffffffff); |
| 1710 |
|
s->is_jmp = DISAS_UPDATE; |
| 1711 |
|
} |
| 1712 |
} |
} |
| 1713 |
break; |
break; |
| 1714 |
case 0xa: |
case 0xa: |
| 1738 |
if (disas_vfp_insn (env, s, insn)) |
if (disas_vfp_insn (env, s, insn)) |
| 1739 |
goto illegal_op; |
goto illegal_op; |
| 1740 |
break; |
break; |
| 1741 |
|
case 15: |
| 1742 |
|
if (disas_cp15_insn (s, insn)) |
| 1743 |
|
goto illegal_op; |
| 1744 |
|
break; |
| 1745 |
default: |
default: |
| 1746 |
/* unknown coprocessor. */ |
/* unknown coprocessor. */ |
| 1747 |
goto illegal_op; |
goto illegal_op; |
| 1771 |
int32_t offset; |
int32_t offset; |
| 1772 |
int i; |
int i; |
| 1773 |
|
|
| 1774 |
insn = lduw(s->pc); |
insn = lduw_code(s->pc); |
| 1775 |
s->pc += 2; |
s->pc += 2; |
| 1776 |
|
|
| 1777 |
switch (insn >> 12) { |
switch (insn >> 12) { |
| 1778 |
case 0: case 1: |
case 0: case 1: |
| 1779 |
rd = insn & 7; |
rd = insn & 7; |
| 1838 |
val = s->pc + 2 + ((insn & 0xff) * 4); |
val = s->pc + 2 + ((insn & 0xff) * 4); |
| 1839 |
val &= ~(uint32_t)2; |
val &= ~(uint32_t)2; |
| 1840 |
gen_op_movl_T1_im(val); |
gen_op_movl_T1_im(val); |
| 1841 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 1842 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 1843 |
break; |
break; |
| 1844 |
} |
} |
| 1981 |
|
|
| 1982 |
switch (op) { |
switch (op) { |
| 1983 |
case 0: /* str */ |
case 0: /* str */ |
| 1984 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 1985 |
break; |
break; |
| 1986 |
case 1: /* strh */ |
case 1: /* strh */ |
| 1987 |
gen_op_stw_T0_T1(); |
gen_ldst(stw, s); |
| 1988 |
break; |
break; |
| 1989 |
case 2: /* strb */ |
case 2: /* strb */ |
| 1990 |
gen_op_stb_T0_T1(); |
gen_ldst(stb, s); |
| 1991 |
break; |
break; |
| 1992 |
case 3: /* ldrsb */ |
case 3: /* ldrsb */ |
| 1993 |
gen_op_ldsb_T0_T1(); |
gen_ldst(ldsb, s); |
| 1994 |
break; |
break; |
| 1995 |
case 4: /* ldr */ |
case 4: /* ldr */ |
| 1996 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 1997 |
break; |
break; |
| 1998 |
case 5: /* ldrh */ |
case 5: /* ldrh */ |
| 1999 |
gen_op_lduw_T0_T1(); |
gen_ldst(lduw, s); |
| 2000 |
break; |
break; |
| 2001 |
case 6: /* ldrb */ |
case 6: /* ldrb */ |
| 2002 |
gen_op_ldub_T0_T1(); |
gen_ldst(ldub, s); |
| 2003 |
break; |
break; |
| 2004 |
case 7: /* ldrsh */ |
case 7: /* ldrsh */ |
| 2005 |
gen_op_ldsw_T0_T1(); |
gen_ldst(ldsw, s); |
| 2006 |
break; |
break; |
| 2007 |
} |
} |
| 2008 |
if (op >= 3) /* load */ |
if (op >= 3) /* load */ |
| 2020 |
|
|
| 2021 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2022 |
/* load */ |
/* load */ |
| 2023 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 2024 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 2025 |
} else { |
} else { |
| 2026 |
/* store */ |
/* store */ |
| 2027 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 2028 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 2029 |
} |
} |
| 2030 |
break; |
break; |
| 2031 |
|
|
| 2040 |
|
|
| 2041 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2042 |
/* load */ |
/* load */ |
| 2043 |
gen_op_ldub_T0_T1(); |
gen_ldst(ldub, s); |
| 2044 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 2045 |
} else { |
} else { |
| 2046 |
/* store */ |
/* store */ |
| 2047 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 2048 |
gen_op_stb_T0_T1(); |
gen_ldst(stb, s); |
| 2049 |
} |
} |
| 2050 |
break; |
break; |
| 2051 |
|
|
| 2060 |
|
|
| 2061 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2062 |
/* load */ |
/* load */ |
| 2063 |
gen_op_lduw_T0_T1(); |
gen_ldst(lduw, s); |
| 2064 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 2065 |
} else { |
} else { |
| 2066 |
/* store */ |
/* store */ |
| 2067 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 2068 |
gen_op_stw_T0_T1(); |
gen_ldst(stw, s); |
| 2069 |
} |
} |
| 2070 |
break; |
break; |
| 2071 |
|
|
| 2079 |
|
|
| 2080 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2081 |
/* load */ |
/* load */ |
| 2082 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 2083 |
gen_movl_reg_T0(s, rd); |
gen_movl_reg_T0(s, rd); |
| 2084 |
} else { |
} else { |
| 2085 |
/* store */ |
/* store */ |
| 2086 |
gen_movl_T0_reg(s, rd); |
gen_movl_T0_reg(s, rd); |
| 2087 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 2088 |
} |
} |
| 2089 |
break; |
break; |
| 2090 |
|
|
| 2139 |
if (insn & (1 << i)) { |
if (insn & (1 << i)) { |
| 2140 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2141 |
/* pop */ |
/* pop */ |
| 2142 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 2143 |
gen_movl_reg_T0(s, i); |
gen_movl_reg_T0(s, i); |
| 2144 |
} else { |
} else { |
| 2145 |
/* push */ |
/* push */ |
| 2146 |
gen_movl_T0_reg(s, i); |
gen_movl_T0_reg(s, i); |
| 2147 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 2148 |
} |
} |
| 2149 |
/* advance to the next address. */ |
/* advance to the next address. */ |
| 2150 |
gen_op_addl_T1_T2(); |
gen_op_addl_T1_T2(); |
| 2153 |
if (insn & (1 << 8)) { |
if (insn & (1 << 8)) { |
| 2154 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2155 |
/* pop pc */ |
/* pop pc */ |
| 2156 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 2157 |
/* don't set the pc until the rest of the instruction |
/* don't set the pc until the rest of the instruction |
| 2158 |
has completed */ |
has completed */ |
| 2159 |
} else { |
} else { |
| 2160 |
/* push lr */ |
/* push lr */ |
| 2161 |
gen_movl_T0_reg(s, 14); |
gen_movl_T0_reg(s, 14); |
| 2162 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 2163 |
} |
} |
| 2164 |
gen_op_addl_T1_T2(); |
gen_op_addl_T1_T2(); |
| 2165 |
} |
} |
| 2188 |
if (insn & (1 << i)) { |
if (insn & (1 << i)) { |
| 2189 |
if (insn & (1 << 11)) { |
if (insn & (1 << 11)) { |
| 2190 |
/* load */ |
/* load */ |
| 2191 |
gen_op_ldl_T0_T1(); |
gen_ldst(ldl, s); |
| 2192 |
gen_movl_reg_T0(s, i); |
gen_movl_reg_T0(s, i); |
| 2193 |
} else { |
} else { |
| 2194 |
/* store */ |
/* store */ |
| 2195 |
gen_movl_T0_reg(s, i); |
gen_movl_T0_reg(s, i); |
| 2196 |
gen_op_stl_T0_T1(); |
gen_ldst(stl, s); |
| 2197 |
} |
} |
| 2198 |
/* advance to the next address */ |
/* advance to the next address */ |
| 2199 |
gen_op_addl_T1_T2(); |
gen_op_addl_T1_T2(); |
| 2200 |
} |
} |
| 2201 |
} |
} |
| 2202 |
/* Base register writeback. */ |
/* Base register writeback. */ |
| 2203 |
gen_movl_reg_T1(s, rn); |
if ((insn & (1 << rn)) == 0) |
| 2204 |
|
gen_movl_reg_T1(s, rn); |
| 2205 |
break; |
break; |
| 2206 |
|
|
| 2207 |
case 13: |
case 13: |
| 2247 |
case 15: |
case 15: |
| 2248 |
/* branch and link [and switch to arm] */ |
/* branch and link [and switch to arm] */ |
| 2249 |
offset = ((int32_t)insn << 21) >> 10; |
offset = ((int32_t)insn << 21) >> 10; |
| 2250 |
insn = lduw(s->pc); |
insn = lduw_code(s->pc); |
| 2251 |
offset |= insn & 0x7ff; |
offset |= insn & 0x7ff; |
| 2252 |
|
|
| 2253 |
val = (uint32_t)s->pc + 2; |
val = (uint32_t)s->pc + 2; |
| 2284 |
uint16_t *gen_opc_end; |
uint16_t *gen_opc_end; |
| 2285 |
int j, lj; |
int j, lj; |
| 2286 |
target_ulong pc_start; |
target_ulong pc_start; |
| 2287 |
|
uint32_t next_page_start; |
| 2288 |
|
|
| 2289 |
/* generate intermediate code */ |
/* generate intermediate code */ |
| 2290 |
pc_start = tb->pc; |
pc_start = tb->pc; |
| 2300 |
dc->singlestep_enabled = env->singlestep_enabled; |
dc->singlestep_enabled = env->singlestep_enabled; |
| 2301 |
dc->condjmp = 0; |
dc->condjmp = 0; |
| 2302 |
dc->thumb = env->thumb; |
dc->thumb = env->thumb; |
| 2303 |
|
#if !defined(CONFIG_USER_ONLY) |
| 2304 |
|
dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; |
| 2305 |
|
#endif |
| 2306 |
|
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; |
| 2307 |
nb_gen_labels = 0; |
nb_gen_labels = 0; |
| 2308 |
lj = -1; |
lj = -1; |
| 2309 |
do { |
do { |
| 2340 |
} |
} |
| 2341 |
/* Translation stops when a conditional branch is enoutered. |
/* Translation stops when a conditional branch is enoutered. |
| 2342 |
* Otherwise the subsequent code could get translated several times. |
* Otherwise the subsequent code could get translated several times. |
| 2343 |
*/ |
* Also stop translation when a page boundary is reached. This |
| 2344 |
|
* ensures prefech aborts occur at the right place. */ |
| 2345 |
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
| 2346 |
!env->singlestep_enabled && |
!env->singlestep_enabled && |
| 2347 |
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); |
dc->pc < next_page_start); |
| 2348 |
/* It this stage dc->condjmp will only be set when the skipped |
/* At this stage dc->condjmp will only be set when the skipped |
| 2349 |
* instruction was a conditional branch, and teh PC has already been |
* instruction was a conditional branch, and the PC has already been |
| 2350 |
* written. */ |
* written. */ |
| 2351 |
if (__builtin_expect(env->singlestep_enabled, 0)) { |
if (__builtin_expect(env->singlestep_enabled, 0)) { |
| 2352 |
/* Make sure the pc is updated, and raise a debug exception. */ |
/* Make sure the pc is updated, and raise a debug exception. */ |
| 2397 |
} |
} |
| 2398 |
} |
} |
| 2399 |
#endif |
#endif |
| 2400 |
if (!search_pc) |
if (search_pc) { |
| 2401 |
|
j = gen_opc_ptr - gen_opc_buf; |
| 2402 |
|
lj++; |
| 2403 |
|
while (lj <= j) |
| 2404 |
|
gen_opc_instr_start[lj++] = 0; |
| 2405 |
|
tb->size = 0; |
| 2406 |
|
} else { |
| 2407 |
tb->size = dc->pc - pc_start; |
tb->size = dc->pc - pc_start; |
| 2408 |
|
} |
| 2409 |
return 0; |
return 0; |
| 2410 |
} |
} |
| 2411 |
|
|
| 2419 |
return gen_intermediate_code_internal(env, tb, 1); |
return gen_intermediate_code_internal(env, tb, 1); |
| 2420 |
} |
} |
| 2421 |
|
|
| 2422 |
|
void cpu_reset(CPUARMState *env) |
| 2423 |
|
{ |
| 2424 |
|
#if defined (CONFIG_USER_ONLY) |
| 2425 |
|
/* SVC mode with interrupts disabled. */ |
| 2426 |
|
env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; |
| 2427 |
|
#else |
| 2428 |
|
env->uncached_cpsr = ARM_CPU_MODE_USR; |
| 2429 |
|
#endif |
| 2430 |
|
env->regs[15] = 0; |
| 2431 |
|
} |
| 2432 |
|
|
| 2433 |
CPUARMState *cpu_arm_init(void) |
CPUARMState *cpu_arm_init(void) |
| 2434 |
{ |
{ |
| 2435 |
CPUARMState *env; |
CPUARMState *env; |
| 2438 |
if (!env) |
if (!env) |
| 2439 |
return NULL; |
return NULL; |
| 2440 |
cpu_exec_init(env); |
cpu_exec_init(env); |
| 2441 |
|
cpu_reset(env); |
| 2442 |
|
tlb_flush(env, 1); |
| 2443 |
return env; |
return env; |
| 2444 |
} |
} |
| 2445 |
|
|
| 2448 |
free(env); |
free(env); |
| 2449 |
} |
} |
| 2450 |
|
|
| 2451 |
|
static const char *cpu_mode_names[16] = { |
| 2452 |
|
"usr", "fiq", "irq", "svc", "???", "???", "???", "abt", |
| 2453 |
|
"???", "???", "???", "und", "???", "???", "???", "sys" |
| 2454 |
|
}; |
| 2455 |
void cpu_dump_state(CPUState *env, FILE *f, |
void cpu_dump_state(CPUState *env, FILE *f, |
| 2456 |
int (*cpu_fprintf)(FILE *f, const char *fmt, ...), |
int (*cpu_fprintf)(FILE *f, const char *fmt, ...), |
| 2457 |
int flags) |
int flags) |
| 2462 |
float s; |
float s; |
| 2463 |
} s0, s1; |
} s0, s1; |
| 2464 |
CPU_DoubleU d; |
CPU_DoubleU d; |
| 2465 |
|
uint32_t psr; |
| 2466 |
|
|
| 2467 |
for(i=0;i<16;i++) { |
for(i=0;i<16;i++) { |
| 2468 |
cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); |
cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); |
| 2471 |
else |
else |
| 2472 |
cpu_fprintf(f, " "); |
cpu_fprintf(f, " "); |
| 2473 |
} |
} |
| 2474 |
cpu_fprintf(f, "PSR=%08x %c%c%c%c %c\n", |
psr = cpsr_read(env); |
| 2475 |
env->cpsr, |
cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n", |
| 2476 |
env->cpsr & (1 << 31) ? 'N' : '-', |
psr, |
| 2477 |
env->cpsr & (1 << 30) ? 'Z' : '-', |
psr & (1 << 31) ? 'N' : '-', |
| 2478 |
env->cpsr & (1 << 29) ? 'C' : '-', |
psr & (1 << 30) ? 'Z' : '-', |
| 2479 |
env->cpsr & (1 << 28) ? 'V' : '-', |
psr & (1 << 29) ? 'C' : '-', |
| 2480 |
env->thumb ? 'T' : 'A'); |
psr & (1 << 28) ? 'V' : '-', |
| 2481 |
|
psr & CPSR_T ? 'T' : 'A', |
| 2482 |
|
cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); |
| 2483 |
|
|
| 2484 |
for (i = 0; i < 16; i++) { |
for (i = 0; i < 16; i++) { |
| 2485 |
d.d = env->vfp.regs[i]; |
d.d = env->vfp.regs[i]; |
| 2494 |
cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); |
cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); |
| 2495 |
} |
} |
| 2496 |
|
|
|
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
|
|
{ |
|
|
return addr; |
|
|
} |
|
|
|
|
|
#if defined(CONFIG_USER_ONLY) |
|
|
|
|
|
int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
|
|
int is_user, int is_softmmu) |
|
|
{ |
|
|
env->cp15_6 = address; |
|
|
if (rw == 2) { |
|
|
env->exception_index = EXCP_PREFETCH_ABORT; |
|
|
} else { |
|
|
env->exception_index = EXCP_DATA_ABORT; |
|
|
} |
|
|
return 1; |
|
|
} |
|
|
|
|
|
#else |
|
|
|
|
|
#error not implemented |
|
|
|
|
|
#endif |
|