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 |
|