25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_arm_instr.c,v 1.60 2006/02/09 22:40:27 debug Exp $ |
* $Id: cpu_arm_instr.c,v 1.68 2006/08/11 17:43:30 debug Exp $ |
29 |
* |
* |
30 |
* ARM instructions. |
* ARM instructions. |
31 |
* |
* |
201 |
|
|
202 |
|
|
203 |
/* |
/* |
|
* nop: Do nothing. |
|
204 |
* invalid: Invalid instructions end up here. |
* invalid: Invalid instructions end up here. |
205 |
*/ |
*/ |
|
X(nop) { } |
|
206 |
X(invalid) { |
X(invalid) { |
207 |
uint32_t low_pc; |
uint32_t low_pc; |
208 |
low_pc = ((size_t)ic - (size_t) |
low_pc = ((size_t)ic - (size_t) |
211 |
<< ARM_INSTR_ALIGNMENT_SHIFT); |
<< ARM_INSTR_ALIGNMENT_SHIFT); |
212 |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
213 |
|
|
214 |
fatal("Invalid ARM instruction: pc=0x%08x\n", (int)cpu->pc); |
fatal("FATAL ERROR: An internal error occured in the ARM" |
215 |
|
" dyntrans code. Please contact the author with detailed" |
216 |
|
" repro steps on how to trigger this bug. pc = 0x%08"PRIx32"\n", |
217 |
|
(uint32_t)cpu->pc); |
218 |
|
|
|
cpu->running = 0; |
|
|
cpu->running_translated = 0; |
|
|
cpu->n_translated_instrs --; |
|
219 |
cpu->cd.arm.next_ic = ¬hing_call; |
cpu->cd.arm.next_ic = ¬hing_call; |
220 |
} |
} |
221 |
|
|
222 |
|
|
223 |
/* |
/* |
224 |
|
* nop: Do nothing. |
225 |
|
*/ |
226 |
|
X(nop) |
227 |
|
{ |
228 |
|
} |
229 |
|
|
230 |
|
|
231 |
|
/* |
232 |
* b: Branch (to a different translated page) |
* b: Branch (to a different translated page) |
233 |
* |
* |
234 |
* arg[0] = relative offset |
* arg[0] = relative offset |
762 |
cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); |
763 |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
764 |
old_pc = cpu->pc; |
old_pc = cpu->pc; |
765 |
printf("msr_spsr: old pc = 0x%08x\n", old_pc); |
printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc); |
766 |
} |
} |
767 |
exit(1); |
exit(1); |
768 |
} |
} |
857 |
X(reboot) |
X(reboot) |
858 |
{ |
{ |
859 |
cpu->running = 0; |
cpu->running = 0; |
|
cpu->running_translated = 0; |
|
860 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
861 |
cpu->cd.arm.next_ic = ¬hing_call; |
cpu->cd.arm.next_ic = ¬hing_call; |
862 |
} |
} |
880 |
useremul_syscall(cpu, ic->arg[0]); |
useremul_syscall(cpu, ic->arg[0]); |
881 |
|
|
882 |
if (!cpu->running) { |
if (!cpu->running) { |
|
cpu->running_translated = 0; |
|
883 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
884 |
cpu->cd.arm.next_ic = ¬hing_call; |
cpu->cd.arm.next_ic = ¬hing_call; |
885 |
} else if (cpu->pc != old_pc) { |
} else if (cpu->pc != old_pc) { |
1324 |
|
|
1325 |
|
|
1326 |
/* Various load/store multiple instructions: */ |
/* Various load/store multiple instructions: */ |
1327 |
uint32_t *multi_opcode[256]; |
extern uint32_t *multi_opcode[256]; |
1328 |
void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *); |
extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *); |
1329 |
X(multi_0x08b15018); |
X(multi_0x08b15018); |
1330 |
X(multi_0x08ac000c__ge); |
X(multi_0x08ac000c__ge); |
1331 |
X(multi_0x08a05018); |
X(multi_0x08a05018); |
2048 |
ic[ 0].f == instr(b_samepage__gt) && |
ic[ 0].f == instr(b_samepage__gt) && |
2049 |
ic[ 0].arg[0] == (size_t)&ic[-17]) { |
ic[ 0].arg[0] == (size_t)&ic[-17]) { |
2050 |
ic[-17].f = instr(netbsd_memset); |
ic[-17].f = instr(netbsd_memset); |
|
combined; |
|
2051 |
} |
} |
2052 |
} |
} |
2053 |
#endif |
#endif |
2077 |
ic[ 0].f == instr(b_samepage__ge) && |
ic[ 0].f == instr(b_samepage__ge) && |
2078 |
ic[ 0].arg[0] == (size_t)&ic[-5]) { |
ic[ 0].arg[0] == (size_t)&ic[-5]) { |
2079 |
ic[-5].f = instr(netbsd_memcpy); |
ic[-5].f = instr(netbsd_memcpy); |
|
combined; |
|
2080 |
} |
} |
2081 |
} |
} |
2082 |
#endif |
#endif |
2101 |
ic[-1].f == instr(b_samepage__ne) && |
ic[-1].f == instr(b_samepage__ne) && |
2102 |
ic[-1].arg[0] == (size_t)&ic[-3]) { |
ic[-1].arg[0] == (size_t)&ic[-3]) { |
2103 |
ic[-3].f = instr(netbsd_cacheclean); |
ic[-3].f = instr(netbsd_cacheclean); |
|
combined; |
|
2104 |
} |
} |
2105 |
} |
} |
2106 |
} |
} |
2125 |
ic[-1].f == instr(subs) && |
ic[-1].f == instr(subs) && |
2126 |
ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) { |
ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) { |
2127 |
ic[-4].f = instr(netbsd_cacheclean2); |
ic[-4].f = instr(netbsd_cacheclean2); |
|
combined; |
|
2128 |
} |
} |
2129 |
} |
} |
2130 |
} |
} |
2151 |
ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 && |
ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 && |
2152 |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) { |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) { |
2153 |
ic[-2].f = instr(netbsd_scanc); |
ic[-2].f = instr(netbsd_scanc); |
|
combined; |
|
2154 |
} |
} |
2155 |
} |
} |
2156 |
|
|
2174 |
ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) && |
ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) && |
2175 |
ic[-1].arg[1] == 0) { |
ic[-1].arg[1] == 0) { |
2176 |
ic[-2].f = instr(strlen); |
ic[-2].f = instr(strlen); |
|
combined; |
|
2177 |
} |
} |
2178 |
} |
} |
2179 |
|
|
2199 |
ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a && |
ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a && |
2200 |
ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) { |
ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) { |
2201 |
ic[-2].f = instr(xchg); |
ic[-2].f = instr(xchg); |
|
combined; |
|
2202 |
} |
} |
2203 |
} |
} |
2204 |
|
|
2229 |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) && |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) && |
2230 |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) { |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) { |
2231 |
ic[-5].f = instr(netbsd_copyin); |
ic[-5].f = instr(netbsd_copyin); |
|
combined; |
|
2232 |
} |
} |
2233 |
#endif |
#endif |
2234 |
} |
} |
2260 |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) && |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) && |
2261 |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) { |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) { |
2262 |
ic[-5].f = instr(netbsd_copyout); |
ic[-5].f = instr(netbsd_copyout); |
|
combined; |
|
2263 |
} |
} |
2264 |
#endif |
#endif |
2265 |
} |
} |
2283 |
ic[-1].f = instr(cmps_neg_beq); |
ic[-1].f = instr(cmps_neg_beq); |
2284 |
else |
else |
2285 |
ic[-1].f = instr(cmps_pos_beq); |
ic[-1].f = instr(cmps_pos_beq); |
|
combined; |
|
2286 |
} |
} |
2287 |
return; |
return; |
2288 |
} |
} |
2292 |
ic[-1].f = instr(cmps0_beq_samepage); |
ic[-1].f = instr(cmps0_beq_samepage); |
2293 |
else |
else |
2294 |
ic[-1].f = instr(cmps_beq_samepage); |
ic[-1].f = instr(cmps_beq_samepage); |
|
combined; |
|
2295 |
} |
} |
2296 |
if (ic[-1].f == instr(tsts) && |
if (ic[-1].f == instr(tsts) && |
2297 |
!(ic[-1].arg[1] & 0x80000000)) { |
!(ic[-1].arg[1] & 0x80000000)) { |
2298 |
ic[-1].f = instr(tsts_lo_beq_samepage); |
ic[-1].f = instr(tsts_lo_beq_samepage); |
|
combined; |
|
2299 |
} |
} |
2300 |
if (ic[-1].f == instr(teqs)) { |
if (ic[-1].f == instr(teqs)) { |
2301 |
ic[-1].f = instr(teqs_beq_samepage); |
ic[-1].f = instr(teqs_beq_samepage); |
|
combined; |
|
2302 |
} |
} |
2303 |
return; |
return; |
2304 |
} |
} |
2308 |
ic[-1].f = instr(cmps0_bne_samepage); |
ic[-1].f = instr(cmps0_bne_samepage); |
2309 |
else |
else |
2310 |
ic[-1].f = instr(cmps_bne_samepage); |
ic[-1].f = instr(cmps_bne_samepage); |
|
combined; |
|
2311 |
} |
} |
2312 |
if (ic[-1].f == instr(tsts) && |
if (ic[-1].f == instr(tsts) && |
2313 |
!(ic[-1].arg[1] & 0x80000000)) { |
!(ic[-1].arg[1] & 0x80000000)) { |
2314 |
ic[-1].f = instr(tsts_lo_bne_samepage); |
ic[-1].f = instr(tsts_lo_bne_samepage); |
|
combined; |
|
2315 |
} |
} |
2316 |
if (ic[-1].f == instr(teqs)) { |
if (ic[-1].f == instr(teqs)) { |
2317 |
ic[-1].f = instr(teqs_bne_samepage); |
ic[-1].f = instr(teqs_bne_samepage); |
|
combined; |
|
2318 |
} |
} |
2319 |
return; |
return; |
2320 |
} |
} |
2321 |
if (ic[0].f == instr(b_samepage__cc)) { |
if (ic[0].f == instr(b_samepage__cc)) { |
2322 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2323 |
ic[-1].f = instr(cmps_bcc_samepage); |
ic[-1].f = instr(cmps_bcc_samepage); |
|
combined; |
|
2324 |
} |
} |
2325 |
if (ic[-1].f == instr(cmps_regshort)) { |
if (ic[-1].f == instr(cmps_regshort)) { |
2326 |
ic[-1].f = instr(cmps_reg_bcc_samepage); |
ic[-1].f = instr(cmps_reg_bcc_samepage); |
|
combined; |
|
2327 |
} |
} |
2328 |
return; |
return; |
2329 |
} |
} |
2330 |
if (ic[0].f == instr(b_samepage__hi)) { |
if (ic[0].f == instr(b_samepage__hi)) { |
2331 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2332 |
ic[-1].f = instr(cmps_bhi_samepage); |
ic[-1].f = instr(cmps_bhi_samepage); |
|
combined; |
|
2333 |
} |
} |
2334 |
if (ic[-1].f == instr(cmps_regshort)) { |
if (ic[-1].f == instr(cmps_regshort)) { |
2335 |
ic[-1].f = instr(cmps_reg_bhi_samepage); |
ic[-1].f = instr(cmps_reg_bhi_samepage); |
|
combined; |
|
2336 |
} |
} |
2337 |
return; |
return; |
2338 |
} |
} |
2339 |
if (ic[0].f == instr(b_samepage__gt)) { |
if (ic[0].f == instr(b_samepage__gt)) { |
2340 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2341 |
ic[-1].f = instr(cmps_bgt_samepage); |
ic[-1].f = instr(cmps_bgt_samepage); |
|
combined; |
|
2342 |
} |
} |
2343 |
return; |
return; |
2344 |
} |
} |
2345 |
if (ic[0].f == instr(b_samepage__le)) { |
if (ic[0].f == instr(b_samepage__le)) { |
2346 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2347 |
ic[-1].f = instr(cmps_ble_samepage); |
ic[-1].f = instr(cmps_ble_samepage); |
|
combined; |
|
2348 |
} |
} |
2349 |
return; |
return; |
2350 |
} |
} |
2437 |
X(to_be_translated) |
X(to_be_translated) |
2438 |
{ |
{ |
2439 |
uint32_t addr, low_pc, iword, imm = 0; |
uint32_t addr, low_pc, iword, imm = 0; |
|
#ifdef DYNTRANS_BACKEND |
|
|
int simple = 0; |
|
|
#endif |
|
2440 |
unsigned char *page; |
unsigned char *page; |
2441 |
unsigned char ib[4]; |
unsigned char ib[4]; |
2442 |
int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8; |
int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8; |
2617 |
(iword & 0x0fb0f000) == 0x0320f000) { |
(iword & 0x0fb0f000) == 0x0320f000) { |
2618 |
/* msr: move to [S|C]PSR from a register or |
/* msr: move to [S|C]PSR from a register or |
2619 |
immediate value */ |
immediate value */ |
|
if (rm == ARM_PC) { |
|
|
fatal("msr PC?\n"); |
|
|
goto bad; |
|
|
} |
|
2620 |
if (iword & 0x02000000) { |
if (iword & 0x02000000) { |
2621 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2622 |
ic->f = cond_instr(msr_imm_spsr); |
ic->f = cond_instr(msr_imm_spsr); |
2623 |
else |
else |
2624 |
ic->f = cond_instr(msr_imm); |
ic->f = cond_instr(msr_imm); |
2625 |
} else { |
} else { |
2626 |
|
if (rm == ARM_PC) { |
2627 |
|
fatal("msr PC?\n"); |
2628 |
|
goto bad; |
2629 |
|
} |
2630 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2631 |
ic->f = cond_instr(msr_spsr); |
ic->f = cond_instr(msr_spsr); |
2632 |
else |
else |
2724 |
/* "mov reg,#0": */ |
/* "mov reg,#0": */ |
2725 |
if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) { |
if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) { |
2726 |
arm_switch_clear(ic, rd, condition_code); |
arm_switch_clear(ic, rd, condition_code); |
|
#ifdef DYNTRANS_BACKEND |
|
|
simple = 1; |
|
|
#endif |
|
2727 |
break; |
break; |
2728 |
} |
} |
2729 |
|
|
2730 |
/* "mov reg,#1": */ |
/* "mov reg,#1": */ |
2731 |
if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) { |
if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) { |
2732 |
arm_switch_mov1(ic, rd, condition_code); |
arm_switch_mov1(ic, rd, condition_code); |
|
#ifdef DYNTRANS_BACKEND |
|
|
simple = 1; |
|
|
#endif |
|
2733 |
break; |
break; |
2734 |
} |
} |
2735 |
|
|
2737 |
if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC |
if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC |
2738 |
&& rn == rd) { |
&& rn == rd) { |
2739 |
arm_switch_add1(ic, rd, condition_code); |
arm_switch_add1(ic, rd, condition_code); |
|
#ifdef DYNTRANS_BACKEND |
|
|
simple = 1; |
|
|
#endif |
|
2740 |
break; |
break; |
2741 |
} |
} |
2742 |
|
|