1 |
/* |
/* |
2 |
* Copyright (C) 2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_arm_instr.c,v 1.54 2005/11/19 18:53:07 debug Exp $ |
* $Id: cpu_arm_instr.c,v 1.69 2006/09/09 09:04:32 debug Exp $ |
29 |
* |
* |
30 |
* ARM instructions. |
* ARM instructions. |
31 |
* |
* |
33 |
* (If no instruction was executed, then it should be decreased. If, say, 4 |
* (If no instruction was executed, then it should be decreased. If, say, 4 |
34 |
* instructions were combined into one function and executed, then it should |
* instructions were combined into one function and executed, then it should |
35 |
* be increased by 3.) |
* be increased by 3.) |
36 |
|
* |
37 |
|
* Note: cpu->pc is prefered over r[ARM_PC]. r[ARM_PC] is only used in a |
38 |
|
* few places, and should always be kept in synch with the real |
39 |
|
* program counter. |
40 |
*/ |
*/ |
41 |
|
|
42 |
|
|
|
#include "arm_quick_pc_to_pointers.h" |
|
|
|
|
43 |
/* #define GATHER_BDT_STATISTICS */ |
/* #define GATHER_BDT_STATISTICS */ |
44 |
|
|
45 |
|
|
205 |
|
|
206 |
|
|
207 |
/* |
/* |
|
* nop: Do nothing. |
|
208 |
* invalid: Invalid instructions end up here. |
* invalid: Invalid instructions end up here. |
209 |
*/ |
*/ |
|
X(nop) { } |
|
210 |
X(invalid) { |
X(invalid) { |
211 |
uint32_t low_pc; |
uint32_t low_pc; |
212 |
low_pc = ((size_t)ic - (size_t) |
low_pc = ((size_t)ic - (size_t) |
215 |
<< ARM_INSTR_ALIGNMENT_SHIFT); |
<< ARM_INSTR_ALIGNMENT_SHIFT); |
216 |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
217 |
|
|
218 |
fatal("Invalid ARM instruction: pc=0x%08x\n", (int)cpu->pc); |
fatal("FATAL ERROR: An internal error occured in the ARM" |
219 |
|
" dyntrans code. Please contact the author with detailed" |
220 |
|
" repro steps on how to trigger this bug. pc = 0x%08"PRIx32"\n", |
221 |
|
(uint32_t)cpu->pc); |
222 |
|
|
|
cpu->running = 0; |
|
|
cpu->running_translated = 0; |
|
|
cpu->n_translated_instrs --; |
|
223 |
cpu->cd.arm.next_ic = ¬hing_call; |
cpu->cd.arm.next_ic = ¬hing_call; |
224 |
} |
} |
225 |
|
|
226 |
|
|
227 |
/* |
/* |
228 |
|
* nop: Do nothing. |
229 |
|
*/ |
230 |
|
X(nop) |
231 |
|
{ |
232 |
|
} |
233 |
|
|
234 |
|
|
235 |
|
/* |
236 |
* b: Branch (to a different translated page) |
* b: Branch (to a different translated page) |
237 |
* |
* |
238 |
* arg[0] = relative offset |
* arg[0] = relative offset |
595 |
|
|
596 |
|
|
597 |
/* |
/* |
598 |
|
* smulXY: 16-bit * 16-bit multiplication (32-bit result) |
599 |
|
* |
600 |
|
* arg[0] = ptr to rm |
601 |
|
* arg[1] = ptr to rs |
602 |
|
* arg[2] = ptr to rd |
603 |
|
*/ |
604 |
|
X(smulbb) |
605 |
|
{ |
606 |
|
reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) * |
607 |
|
(int32_t)(int16_t)reg(ic->arg[1]); |
608 |
|
} |
609 |
|
Y(smulbb) |
610 |
|
X(smultb) |
611 |
|
{ |
612 |
|
reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) * |
613 |
|
(int32_t)(int16_t)reg(ic->arg[1]); |
614 |
|
} |
615 |
|
Y(smultb) |
616 |
|
X(smulbt) |
617 |
|
{ |
618 |
|
reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) * |
619 |
|
(int32_t)(int16_t)(reg(ic->arg[1]) >> 16); |
620 |
|
} |
621 |
|
Y(smulbt) |
622 |
|
X(smultt) |
623 |
|
{ |
624 |
|
reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) * |
625 |
|
(int32_t)(int16_t)(reg(ic->arg[1]) >> 16); |
626 |
|
} |
627 |
|
Y(smultt) |
628 |
|
|
629 |
|
|
630 |
|
/* |
631 |
* mov_reg_reg: Move a register to another. |
* mov_reg_reg: Move a register to another. |
632 |
* |
* |
633 |
* arg[0] = ptr to source register |
* arg[0] = ptr to source register |
766 |
cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); |
767 |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); |
768 |
old_pc = cpu->pc; |
old_pc = cpu->pc; |
769 |
printf("msr_spsr: old pc = 0x%08x\n", old_pc); |
printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc); |
770 |
} |
} |
771 |
exit(1); |
exit(1); |
772 |
} |
} |
861 |
X(reboot) |
X(reboot) |
862 |
{ |
{ |
863 |
cpu->running = 0; |
cpu->running = 0; |
|
cpu->running_translated = 0; |
|
864 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
865 |
cpu->cd.arm.next_ic = ¬hing_call; |
cpu->cd.arm.next_ic = ¬hing_call; |
866 |
} |
} |
884 |
useremul_syscall(cpu, ic->arg[0]); |
useremul_syscall(cpu, ic->arg[0]); |
885 |
|
|
886 |
if (!cpu->running) { |
if (!cpu->running) { |
|
cpu->running_translated = 0; |
|
887 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
888 |
cpu->cd.arm.next_ic = ¬hing_call; |
cpu->cd.arm.next_ic = ¬hing_call; |
889 |
} else if (cpu->pc != old_pc) { |
} else if (cpu->pc != old_pc) { |
1328 |
|
|
1329 |
|
|
1330 |
/* Various load/store multiple instructions: */ |
/* Various load/store multiple instructions: */ |
1331 |
uint32_t *multi_opcode[256]; |
extern uint32_t *multi_opcode[256]; |
1332 |
void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *); |
extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *); |
1333 |
X(multi_0x08b15018); |
X(multi_0x08b15018); |
1334 |
X(multi_0x08ac000c__ge); |
X(multi_0x08ac000c__ge); |
1335 |
X(multi_0x08a05018); |
X(multi_0x08a05018); |
2030 |
|
|
2031 |
|
|
2032 |
/* |
/* |
2033 |
* arm_combine_netbsd_memset(): |
* Combine: netbsd_memset(): |
2034 |
* |
* |
2035 |
* Check for the core of a NetBSD/arm memset; large memsets use a sequence |
* Check for the core of a NetBSD/arm memset; large memsets use a sequence |
2036 |
* of 16 store-multiple instructions, each storing 2 registers at a time. |
* of 16 store-multiple instructions, each storing 2 registers at a time. |
2037 |
*/ |
*/ |
2038 |
void arm_combine_netbsd_memset(struct cpu *cpu, |
void COMBINE(netbsd_memset)(struct cpu *cpu, |
2039 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2040 |
{ |
{ |
2041 |
#ifdef HOST_LITTLE_ENDIAN |
#ifdef HOST_LITTLE_ENDIAN |
2052 |
ic[ 0].f == instr(b_samepage__gt) && |
ic[ 0].f == instr(b_samepage__gt) && |
2053 |
ic[ 0].arg[0] == (size_t)&ic[-17]) { |
ic[ 0].arg[0] == (size_t)&ic[-17]) { |
2054 |
ic[-17].f = instr(netbsd_memset); |
ic[-17].f = instr(netbsd_memset); |
|
combined; |
|
2055 |
} |
} |
2056 |
} |
} |
2057 |
#endif |
#endif |
2059 |
|
|
2060 |
|
|
2061 |
/* |
/* |
2062 |
* arm_combine_netbsd_memcpy(): |
* Combine: netbsd_memcpy(): |
2063 |
* |
* |
2064 |
* Check for the core of a NetBSD/arm memcpy; large memcpys use a |
* Check for the core of a NetBSD/arm memcpy; large memcpys use a |
2065 |
* sequence of ldmia instructions. |
* sequence of ldmia instructions. |
2066 |
*/ |
*/ |
2067 |
void arm_combine_netbsd_memcpy(struct cpu *cpu, |
void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic, |
2068 |
struct arm_instr_call *ic, int low_addr) |
int low_addr) |
2069 |
{ |
{ |
2070 |
#ifdef HOST_LITTLE_ENDIAN |
#ifdef HOST_LITTLE_ENDIAN |
2071 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2081 |
ic[ 0].f == instr(b_samepage__ge) && |
ic[ 0].f == instr(b_samepage__ge) && |
2082 |
ic[ 0].arg[0] == (size_t)&ic[-5]) { |
ic[ 0].arg[0] == (size_t)&ic[-5]) { |
2083 |
ic[-5].f = instr(netbsd_memcpy); |
ic[-5].f = instr(netbsd_memcpy); |
|
combined; |
|
2084 |
} |
} |
2085 |
} |
} |
2086 |
#endif |
#endif |
2088 |
|
|
2089 |
|
|
2090 |
/* |
/* |
2091 |
* arm_combine_netbsd_cacheclean(): |
* Combine: netbsd_cacheclean(): |
2092 |
* |
* |
2093 |
* Check for the core of a NetBSD/arm cache clean. (There are two variants.) |
* Check for the core of a NetBSD/arm cache clean. (There are two variants.) |
2094 |
*/ |
*/ |
2095 |
void arm_combine_netbsd_cacheclean(struct cpu *cpu, |
void COMBINE(netbsd_cacheclean)(struct cpu *cpu, |
2096 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2097 |
{ |
{ |
2098 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2105 |
ic[-1].f == instr(b_samepage__ne) && |
ic[-1].f == instr(b_samepage__ne) && |
2106 |
ic[-1].arg[0] == (size_t)&ic[-3]) { |
ic[-1].arg[0] == (size_t)&ic[-3]) { |
2107 |
ic[-3].f = instr(netbsd_cacheclean); |
ic[-3].f = instr(netbsd_cacheclean); |
|
combined; |
|
2108 |
} |
} |
2109 |
} |
} |
2110 |
} |
} |
2111 |
|
|
2112 |
|
|
2113 |
/* |
/* |
2114 |
* arm_combine_netbsd_cacheclean2(): |
* Combine: netbsd_cacheclean2(): |
2115 |
* |
* |
2116 |
* Check for the core of a NetBSD/arm cache clean. (Second variant.) |
* Check for the core of a NetBSD/arm cache clean. (Second variant.) |
2117 |
*/ |
*/ |
2118 |
void arm_combine_netbsd_cacheclean2(struct cpu *cpu, |
void COMBINE(netbsd_cacheclean2)(struct cpu *cpu, |
2119 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2120 |
{ |
{ |
2121 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2129 |
ic[-1].f == instr(subs) && |
ic[-1].f == instr(subs) && |
2130 |
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) { |
2131 |
ic[-4].f = instr(netbsd_cacheclean2); |
ic[-4].f = instr(netbsd_cacheclean2); |
|
combined; |
|
2132 |
} |
} |
2133 |
} |
} |
2134 |
} |
} |
2135 |
|
|
2136 |
|
|
2137 |
/* |
/* |
2138 |
* arm_combine_netbsd_scanc(): |
* Combine: netbsd_scanc(): |
2139 |
*/ |
*/ |
2140 |
void arm_combine_netbsd_scanc(struct cpu *cpu, |
void COMBINE(netbsd_scanc)(struct cpu *cpu, |
2141 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2142 |
{ |
{ |
2143 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2155 |
ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 && |
ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 && |
2156 |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) { |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) { |
2157 |
ic[-2].f = instr(netbsd_scanc); |
ic[-2].f = instr(netbsd_scanc); |
|
combined; |
|
2158 |
} |
} |
2159 |
} |
} |
2160 |
|
|
2161 |
|
|
2162 |
/* |
/* |
2163 |
* arm_combine_strlen(): |
* Combine: strlen(): |
2164 |
*/ |
*/ |
2165 |
void arm_combine_strlen(struct cpu *cpu, |
void COMBINE(strlen)(struct cpu *cpu, |
2166 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2167 |
{ |
{ |
2168 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2178 |
ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) && |
ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) && |
2179 |
ic[-1].arg[1] == 0) { |
ic[-1].arg[1] == 0) { |
2180 |
ic[-2].f = instr(strlen); |
ic[-2].f = instr(strlen); |
|
combined; |
|
2181 |
} |
} |
2182 |
} |
} |
2183 |
|
|
2184 |
|
|
2185 |
/* |
/* |
2186 |
* arm_combine_xchg(): |
* Combine: xchg(): |
2187 |
*/ |
*/ |
2188 |
void arm_combine_xchg(struct cpu *cpu, |
void COMBINE(xchg)(struct cpu *cpu, |
2189 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2190 |
{ |
{ |
2191 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2203 |
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 && |
2204 |
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) { |
2205 |
ic[-2].f = instr(xchg); |
ic[-2].f = instr(xchg); |
|
combined; |
|
2206 |
} |
} |
2207 |
} |
} |
2208 |
|
|
2209 |
|
|
2210 |
/* |
/* |
2211 |
* arm_combine_netbsd_copyin(): |
* Combine: netbsd_copyin(): |
2212 |
*/ |
*/ |
2213 |
void arm_combine_netbsd_copyin(struct cpu *cpu, |
void COMBINE(netbsd_copyin)(struct cpu *cpu, |
2214 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2215 |
{ |
{ |
2216 |
#ifdef HOST_LITTLE_ENDIAN |
#ifdef HOST_LITTLE_ENDIAN |
2233 |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) && |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) && |
2234 |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) { |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) { |
2235 |
ic[-5].f = instr(netbsd_copyin); |
ic[-5].f = instr(netbsd_copyin); |
|
combined; |
|
2236 |
} |
} |
2237 |
#endif |
#endif |
2238 |
} |
} |
2239 |
|
|
2240 |
|
|
2241 |
/* |
/* |
2242 |
* arm_combine_netbsd_copyout(): |
* Combine: netbsd_copyout(): |
2243 |
*/ |
*/ |
2244 |
void arm_combine_netbsd_copyout(struct cpu *cpu, |
void COMBINE(netbsd_copyout)(struct cpu *cpu, |
2245 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2246 |
{ |
{ |
2247 |
#ifdef HOST_LITTLE_ENDIAN |
#ifdef HOST_LITTLE_ENDIAN |
2264 |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) && |
ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) && |
2265 |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) { |
ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) { |
2266 |
ic[-5].f = instr(netbsd_copyout); |
ic[-5].f = instr(netbsd_copyout); |
|
combined; |
|
2267 |
} |
} |
2268 |
#endif |
#endif |
2269 |
} |
} |
2270 |
|
|
2271 |
|
|
2272 |
/* |
/* |
2273 |
* arm_combine_cmps_b(): |
* Combine: cmps_b(): |
2274 |
*/ |
*/ |
2275 |
void arm_combine_cmps_b(struct cpu *cpu, |
void COMBINE(cmps_b)(struct cpu *cpu, |
2276 |
struct arm_instr_call *ic, int low_addr) |
struct arm_instr_call *ic, int low_addr) |
2277 |
{ |
{ |
2278 |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) |
2287 |
ic[-1].f = instr(cmps_neg_beq); |
ic[-1].f = instr(cmps_neg_beq); |
2288 |
else |
else |
2289 |
ic[-1].f = instr(cmps_pos_beq); |
ic[-1].f = instr(cmps_pos_beq); |
|
combined; |
|
2290 |
} |
} |
2291 |
return; |
return; |
2292 |
} |
} |
2296 |
ic[-1].f = instr(cmps0_beq_samepage); |
ic[-1].f = instr(cmps0_beq_samepage); |
2297 |
else |
else |
2298 |
ic[-1].f = instr(cmps_beq_samepage); |
ic[-1].f = instr(cmps_beq_samepage); |
|
combined; |
|
2299 |
} |
} |
2300 |
if (ic[-1].f == instr(tsts) && |
if (ic[-1].f == instr(tsts) && |
2301 |
!(ic[-1].arg[1] & 0x80000000)) { |
!(ic[-1].arg[1] & 0x80000000)) { |
2302 |
ic[-1].f = instr(tsts_lo_beq_samepage); |
ic[-1].f = instr(tsts_lo_beq_samepage); |
|
combined; |
|
2303 |
} |
} |
2304 |
if (ic[-1].f == instr(teqs)) { |
if (ic[-1].f == instr(teqs)) { |
2305 |
ic[-1].f = instr(teqs_beq_samepage); |
ic[-1].f = instr(teqs_beq_samepage); |
|
combined; |
|
2306 |
} |
} |
2307 |
return; |
return; |
2308 |
} |
} |
2312 |
ic[-1].f = instr(cmps0_bne_samepage); |
ic[-1].f = instr(cmps0_bne_samepage); |
2313 |
else |
else |
2314 |
ic[-1].f = instr(cmps_bne_samepage); |
ic[-1].f = instr(cmps_bne_samepage); |
|
combined; |
|
2315 |
} |
} |
2316 |
if (ic[-1].f == instr(tsts) && |
if (ic[-1].f == instr(tsts) && |
2317 |
!(ic[-1].arg[1] & 0x80000000)) { |
!(ic[-1].arg[1] & 0x80000000)) { |
2318 |
ic[-1].f = instr(tsts_lo_bne_samepage); |
ic[-1].f = instr(tsts_lo_bne_samepage); |
|
combined; |
|
2319 |
} |
} |
2320 |
if (ic[-1].f == instr(teqs)) { |
if (ic[-1].f == instr(teqs)) { |
2321 |
ic[-1].f = instr(teqs_bne_samepage); |
ic[-1].f = instr(teqs_bne_samepage); |
|
combined; |
|
2322 |
} |
} |
2323 |
return; |
return; |
2324 |
} |
} |
2325 |
if (ic[0].f == instr(b_samepage__cc)) { |
if (ic[0].f == instr(b_samepage__cc)) { |
2326 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2327 |
ic[-1].f = instr(cmps_bcc_samepage); |
ic[-1].f = instr(cmps_bcc_samepage); |
|
combined; |
|
2328 |
} |
} |
2329 |
if (ic[-1].f == instr(cmps_regshort)) { |
if (ic[-1].f == instr(cmps_regshort)) { |
2330 |
ic[-1].f = instr(cmps_reg_bcc_samepage); |
ic[-1].f = instr(cmps_reg_bcc_samepage); |
|
combined; |
|
2331 |
} |
} |
2332 |
return; |
return; |
2333 |
} |
} |
2334 |
if (ic[0].f == instr(b_samepage__hi)) { |
if (ic[0].f == instr(b_samepage__hi)) { |
2335 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2336 |
ic[-1].f = instr(cmps_bhi_samepage); |
ic[-1].f = instr(cmps_bhi_samepage); |
|
combined; |
|
2337 |
} |
} |
2338 |
if (ic[-1].f == instr(cmps_regshort)) { |
if (ic[-1].f == instr(cmps_regshort)) { |
2339 |
ic[-1].f = instr(cmps_reg_bhi_samepage); |
ic[-1].f = instr(cmps_reg_bhi_samepage); |
|
combined; |
|
2340 |
} |
} |
2341 |
return; |
return; |
2342 |
} |
} |
2343 |
if (ic[0].f == instr(b_samepage__gt)) { |
if (ic[0].f == instr(b_samepage__gt)) { |
2344 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2345 |
ic[-1].f = instr(cmps_bgt_samepage); |
ic[-1].f = instr(cmps_bgt_samepage); |
|
combined; |
|
2346 |
} |
} |
2347 |
return; |
return; |
2348 |
} |
} |
2349 |
if (ic[0].f == instr(b_samepage__le)) { |
if (ic[0].f == instr(b_samepage__le)) { |
2350 |
if (ic[-1].f == instr(cmps)) { |
if (ic[-1].f == instr(cmps)) { |
2351 |
ic[-1].f = instr(cmps_ble_samepage); |
ic[-1].f = instr(cmps_ble_samepage); |
|
combined; |
|
2352 |
} |
} |
2353 |
return; |
return; |
2354 |
} |
} |
2601 |
goto bad; |
goto bad; |
2602 |
} |
} |
2603 |
if ((iword & 0x0ff0f090) == 0x01600080) { |
if ((iword & 0x0ff0f090) == 0x01600080) { |
2604 |
/* TODO: smulXY */ |
/* smulXY (16-bit * 16-bit => 32-bit) */ |
2605 |
goto bad; |
switch (iword & 0x60) { |
2606 |
|
case 0x00: ic->f = cond_instr(smulbb); break; |
2607 |
|
case 0x20: ic->f = cond_instr(smultb); break; |
2608 |
|
case 0x40: ic->f = cond_instr(smulbt); break; |
2609 |
|
default: ic->f = cond_instr(smultt); break; |
2610 |
|
} |
2611 |
|
ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]); |
2612 |
|
ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]); |
2613 |
|
ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /* Rd */ |
2614 |
|
break; |
2615 |
} |
} |
2616 |
if ((iword & 0x0ff0f0b0) == 0x012000a0) { |
if ((iword & 0x0ff0f0b0) == 0x012000a0) { |
2617 |
/* TODO: smulwY */ |
/* TODO: smulwY */ |
2621 |
(iword & 0x0fb0f000) == 0x0320f000) { |
(iword & 0x0fb0f000) == 0x0320f000) { |
2622 |
/* msr: move to [S|C]PSR from a register or |
/* msr: move to [S|C]PSR from a register or |
2623 |
immediate value */ |
immediate value */ |
|
if (rm == ARM_PC) { |
|
|
fatal("msr PC?\n"); |
|
|
goto bad; |
|
|
} |
|
2624 |
if (iword & 0x02000000) { |
if (iword & 0x02000000) { |
2625 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2626 |
ic->f = cond_instr(msr_imm_spsr); |
ic->f = cond_instr(msr_imm_spsr); |
2627 |
else |
else |
2628 |
ic->f = cond_instr(msr_imm); |
ic->f = cond_instr(msr_imm); |
2629 |
} else { |
} else { |
2630 |
|
if (rm == ARM_PC) { |
2631 |
|
fatal("msr PC?\n"); |
2632 |
|
goto bad; |
2633 |
|
} |
2634 |
if (iword & 0x00400000) |
if (iword & 0x00400000) |
2635 |
ic->f = cond_instr(msr_spsr); |
ic->f = cond_instr(msr_spsr); |
2636 |
else |
else |
2793 |
(any_pc_reg? 512 : 0) + (regform? 1024 : 0)]; |
(any_pc_reg? 512 : 0) + (regform? 1024 : 0)]; |
2794 |
|
|
2795 |
if (ic->f == instr(eor_regshort)) |
if (ic->f == instr(eor_regshort)) |
2796 |
cpu->cd.arm.combination_check = arm_combine_xchg; |
cpu->cd.arm.combination_check = COMBINE(xchg); |
2797 |
if (iword == 0xe113000c) |
if (iword == 0xe113000c) |
2798 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = COMBINE(netbsd_scanc); |
|
arm_combine_netbsd_scanc; |
|
2799 |
break; |
break; |
2800 |
|
|
2801 |
case 0x4: /* Load and store... */ |
case 0x4: /* Load and store... */ |
2867 |
} |
} |
2868 |
} |
} |
2869 |
if (iword == 0xe4b09004) |
if (iword == 0xe4b09004) |
2870 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = COMBINE(netbsd_copyin); |
|
arm_combine_netbsd_copyin; |
|
2871 |
if (iword == 0xe4a17004) |
if (iword == 0xe4a17004) |
2872 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = COMBINE(netbsd_copyout); |
|
arm_combine_netbsd_copyout; |
|
2873 |
break; |
break; |
2874 |
|
|
2875 |
case 0x8: /* Multiple load/store... (Block data transfer) */ |
case 0x8: /* Multiple load/store... (Block data transfer) */ |
2922 |
samepage_function = cond_instr(b_samepage); |
samepage_function = cond_instr(b_samepage); |
2923 |
if (iword == 0xcaffffed) |
if (iword == 0xcaffffed) |
2924 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = |
2925 |
arm_combine_netbsd_memset; |
COMBINE(netbsd_memset); |
2926 |
if (iword == 0xaafffff9) |
if (iword == 0xaafffff9) |
2927 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = |
2928 |
arm_combine_netbsd_memcpy; |
COMBINE(netbsd_memcpy); |
2929 |
} else { |
} else { |
2930 |
if (cpu->machine->show_trace_tree) { |
if (cpu->machine->show_trace_tree) { |
2931 |
ic->f = cond_instr(bl_trace); |
ic->f = cond_instr(bl_trace); |
2984 |
if (main_opcode == 0xa && (condition_code <= 1 |
if (main_opcode == 0xa && (condition_code <= 1 |
2985 |
|| condition_code == 3 || condition_code == 8 |
|| condition_code == 3 || condition_code == 8 |
2986 |
|| condition_code == 12 || condition_code == 13)) |
|| condition_code == 12 || condition_code == 13)) |
2987 |
cpu->cd.arm.combination_check = arm_combine_cmps_b; |
cpu->cd.arm.combination_check = COMBINE(cmps_b); |
2988 |
|
|
2989 |
if (iword == 0x1afffffc) |
if (iword == 0x1afffffc) |
2990 |
cpu->cd.arm.combination_check = arm_combine_strlen; |
cpu->cd.arm.combination_check = COMBINE(strlen); |
2991 |
|
|
2992 |
/* Hm. Does this really increase performance? */ |
/* Hm. Does this really increase performance? */ |
2993 |
if (iword == 0x8afffffa) |
if (iword == 0x8afffffa) |
2994 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = |
2995 |
arm_combine_netbsd_cacheclean2; |
COMBINE(netbsd_cacheclean2); |
2996 |
break; |
break; |
2997 |
|
|
2998 |
case 0xc: |
case 0xc: |
3001 |
* xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm |
* xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm |
3002 |
* xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm |
* xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm |
3003 |
*/ |
*/ |
3004 |
|
if ((iword & 0x0fe00fff) == 0x0c400000) { |
3005 |
|
/* Special case: mar/mra DSP instructions */ |
3006 |
|
fatal("TODO: mar/mra DSP instructions!\n"); |
3007 |
|
/* Perhaps these are actually identical to MCRR/MRRC */ |
3008 |
|
goto bad; |
3009 |
|
} |
3010 |
|
|
3011 |
if ((iword & 0x0fe00000) == 0x0c400000) { |
if ((iword & 0x0fe00000) == 0x0c400000) { |
3012 |
fatal("MCRR/MRRC: TODO\n"); |
fatal("MCRR/MRRC: TODO\n"); |
3013 |
goto bad; |
goto bad; |
3019 |
* For now, treat as Undefined instructions. This causes e.g. |
* For now, treat as Undefined instructions. This causes e.g. |
3020 |
* Linux/ARM to emulate these instructions (floating point). |
* Linux/ARM to emulate these instructions (floating point). |
3021 |
*/ |
*/ |
3022 |
|
#if 0 |
3023 |
ic->f = cond_instr(und); |
ic->f = cond_instr(und); |
3024 |
ic->arg[0] = addr & 0xfff; |
ic->arg[0] = addr & 0xfff; |
3025 |
|
#else |
3026 |
|
fatal("LDC/STC: TODO\n"); |
3027 |
|
goto bad; |
3028 |
|
#endif |
3029 |
break; |
break; |
3030 |
|
|
3031 |
case 0xe: |
case 0xe: |
3032 |
|
if ((iword & 0x0ff00ff0) == 0x0e200010) { |
3033 |
|
/* Special case: mia* DSP instructions */ |
3034 |
|
/* See Intel's 27343601.pdf, page 16-20 */ |
3035 |
|
fatal("TODO: mia* DSP instructions!\n"); |
3036 |
|
goto bad; |
3037 |
|
} |
3038 |
if (iword & 0x10) { |
if (iword & 0x10) { |
3039 |
/* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */ |
/* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */ |
3040 |
ic->arg[0] = iword; |
ic->arg[0] = iword; |
3046 |
} |
} |
3047 |
if (iword == 0xee070f9a) |
if (iword == 0xee070f9a) |
3048 |
cpu->cd.arm.combination_check = |
cpu->cd.arm.combination_check = |
3049 |
arm_combine_netbsd_cacheclean; |
COMBINE(netbsd_cacheclean); |
3050 |
break; |
break; |
3051 |
|
|
3052 |
case 0xf: |
case 0xf: |