2823a4c8 |
1 | /* gameplaySP |
2 | * |
3 | * Copyright (C) 2006 Exophase <exophase@gmail.com> |
4 | * |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation; either version 2 of |
8 | * the License, or (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ |
19 | |
20 | // Not-so-important todo: |
21 | // - stm reglist writeback when base is in the list needs adjustment |
22 | // - block memory needs psr swapping and user mode reg swapping |
23 | |
2823a4c8 |
24 | #include "common.h" |
25 | |
26 | u8 rom_translation_cache[ROM_TRANSLATION_CACHE_SIZE]; |
27 | u8 *rom_translation_ptr = rom_translation_cache; |
28 | |
29 | u8 ram_translation_cache[RAM_TRANSLATION_CACHE_SIZE]; |
30 | u8 *ram_translation_ptr = ram_translation_cache; |
31 | u32 iwram_code_min = 0xFFFFFFFF; |
32 | u32 iwram_code_max = 0xFFFFFFFF; |
33 | u32 ewram_code_min = 0xFFFFFFFF; |
34 | u32 ewram_code_max = 0xFFFFFFFF; |
35 | |
36 | u8 bios_translation_cache[BIOS_TRANSLATION_CACHE_SIZE]; |
37 | u8 *bios_translation_ptr = bios_translation_cache; |
38 | |
39 | u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE]; |
40 | |
41 | // Default |
42 | u32 idle_loop_target_pc = 0xFFFFFFFF; |
43 | u32 force_pc_update_target = 0xFFFFFFFF; |
44 | u32 translation_gate_target_pc[MAX_TRANSLATION_GATES]; |
45 | u32 translation_gate_targets = 0; |
46 | u32 iwram_stack_optimize = 1; |
47 | u32 allow_smc_ram_u8 = 1; |
48 | u32 allow_smc_ram_u16 = 1; |
49 | u32 allow_smc_ram_u32 = 1; |
50 | |
51 | typedef struct |
52 | { |
53 | u8 *block_offset; |
54 | u16 flag_data; |
55 | u8 condition; |
56 | u8 update_cycles; |
57 | } block_data_type; |
58 | |
59 | typedef struct |
60 | { |
61 | u32 branch_target; |
62 | u8 *branch_source; |
63 | } block_exit_type; |
64 | |
65 | extern u8 bit_count[256]; |
66 | |
67 | #define arm_decode_data_proc_reg() \ |
68 | u32 rn = (opcode >> 16) & 0x0F; \ |
69 | u32 rd = (opcode >> 12) & 0x0F; \ |
70 | u32 rm = opcode & 0x0F \ |
71 | |
72 | #define arm_decode_data_proc_imm() \ |
73 | u32 rn = (opcode >> 16) & 0x0F; \ |
74 | u32 rd = (opcode >> 12) & 0x0F; \ |
75 | u32 imm = opcode & 0xFF; \ |
76 | u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \ |
77 | |
78 | #define arm_decode_psr_reg() \ |
79 | u32 psr_field = (opcode >> 16) & 0x0F; \ |
80 | u32 rd = (opcode >> 12) & 0x0F; \ |
81 | u32 rm = opcode & 0x0F \ |
82 | |
83 | #define arm_decode_psr_imm() \ |
84 | u32 psr_field = (opcode >> 16) & 0x0F; \ |
85 | u32 rd = (opcode >> 12) & 0x0F; \ |
86 | u32 imm = opcode & 0xFF; \ |
87 | u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \ |
88 | |
89 | #define arm_decode_branchx() \ |
90 | u32 rn = opcode & 0x0F \ |
91 | |
92 | #define arm_decode_multiply() \ |
93 | u32 rd = (opcode >> 16) & 0x0F; \ |
94 | u32 rn = (opcode >> 12) & 0x0F; \ |
95 | u32 rs = (opcode >> 8) & 0x0F; \ |
96 | u32 rm = opcode & 0x0F \ |
97 | |
98 | #define arm_decode_multiply_long() \ |
99 | u32 rdhi = (opcode >> 16) & 0x0F; \ |
100 | u32 rdlo = (opcode >> 12) & 0x0F; \ |
101 | u32 rs = (opcode >> 8) & 0x0F; \ |
102 | u32 rm = opcode & 0x0F \ |
103 | |
104 | #define arm_decode_swap() \ |
105 | u32 rn = (opcode >> 16) & 0x0F; \ |
106 | u32 rd = (opcode >> 12) & 0x0F; \ |
107 | u32 rm = opcode & 0x0F \ |
108 | |
109 | #define arm_decode_half_trans_r() \ |
110 | u32 rn = (opcode >> 16) & 0x0F; \ |
111 | u32 rd = (opcode >> 12) & 0x0F; \ |
112 | u32 rm = opcode & 0x0F \ |
113 | |
114 | #define arm_decode_half_trans_of() \ |
115 | u32 rn = (opcode >> 16) & 0x0F; \ |
116 | u32 rd = (opcode >> 12) & 0x0F; \ |
117 | u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F) \ |
118 | |
119 | #define arm_decode_data_trans_imm() \ |
120 | u32 rn = (opcode >> 16) & 0x0F; \ |
121 | u32 rd = (opcode >> 12) & 0x0F; \ |
122 | u32 offset = opcode & 0x0FFF \ |
123 | |
124 | #define arm_decode_data_trans_reg() \ |
125 | u32 rn = (opcode >> 16) & 0x0F; \ |
126 | u32 rd = (opcode >> 12) & 0x0F; \ |
127 | u32 rm = opcode & 0x0F \ |
128 | |
129 | #define arm_decode_block_trans() \ |
130 | u32 rn = (opcode >> 16) & 0x0F; \ |
131 | u32 reg_list = opcode & 0xFFFF \ |
132 | |
133 | #define arm_decode_branch() \ |
134 | s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \ |
135 | |
136 | #define thumb_decode_shift() \ |
137 | u32 imm = (opcode >> 6) & 0x1F; \ |
138 | u32 rs = (opcode >> 3) & 0x07; \ |
139 | u32 rd = opcode & 0x07 \ |
140 | |
141 | #define thumb_decode_add_sub() \ |
142 | u32 rn = (opcode >> 6) & 0x07; \ |
143 | u32 rs = (opcode >> 3) & 0x07; \ |
144 | u32 rd = opcode & 0x07 \ |
145 | |
146 | #define thumb_decode_add_sub_imm() \ |
147 | u32 imm = (opcode >> 6) & 0x07; \ |
148 | u32 rs = (opcode >> 3) & 0x07; \ |
149 | u32 rd = opcode & 0x07 \ |
150 | |
151 | #define thumb_decode_imm() \ |
152 | u32 imm = opcode & 0xFF \ |
153 | |
154 | #define thumb_decode_alu_op() \ |
155 | u32 rs = (opcode >> 3) & 0x07; \ |
156 | u32 rd = opcode & 0x07 \ |
157 | |
158 | #define thumb_decode_hireg_op() \ |
159 | u32 rs = (opcode >> 3) & 0x0F; \ |
160 | u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07) \ |
161 | |
162 | #define thumb_decode_mem_reg() \ |
163 | u32 ro = (opcode >> 6) & 0x07; \ |
164 | u32 rb = (opcode >> 3) & 0x07; \ |
165 | u32 rd = opcode & 0x07 \ |
166 | |
167 | #define thumb_decode_mem_imm() \ |
168 | u32 imm = (opcode >> 6) & 0x1F; \ |
169 | u32 rb = (opcode >> 3) & 0x07; \ |
170 | u32 rd = opcode & 0x07 \ |
171 | |
172 | #define thumb_decode_add_sp() \ |
173 | u32 imm = opcode & 0x7F \ |
174 | |
175 | #define thumb_decode_rlist() \ |
176 | u32 reg_list = opcode & 0xFF \ |
177 | |
178 | #define thumb_decode_branch_cond() \ |
179 | s32 offset = (s8)(opcode & 0xFF) \ |
180 | |
181 | #define thumb_decode_swi() \ |
182 | u32 comment = opcode & 0xFF \ |
183 | |
184 | #define thumb_decode_branch() \ |
185 | u32 offset = opcode & 0x07FF \ |
186 | |
187 | |
188 | #ifdef PSP_BUILD |
189 | |
190 | #include "psp/mips_emit.h" |
191 | |
d5e0983c |
192 | #elif defined(ARM_ARCH) |
2823a4c8 |
193 | |
d5e0983c |
194 | #include "arm/arm_emit.h" |
2823a4c8 |
195 | |
196 | #else |
197 | |
198 | #include "x86/x86_emit.h" |
199 | |
200 | #endif |
201 | |
202 | |
203 | #define check_pc_region(pc) \ |
204 | new_pc_region = (pc >> 15); \ |
205 | if(new_pc_region != pc_region) \ |
206 | { \ |
207 | pc_region = new_pc_region; \ |
208 | pc_address_block = memory_map_read[new_pc_region]; \ |
209 | \ |
210 | if(pc_address_block == NULL) \ |
211 | pc_address_block = load_gamepak_page(pc_region & 0x3FF); \ |
212 | } \ |
213 | |
214 | #define translate_arm_instruction() \ |
215 | check_pc_region(pc); \ |
216 | opcode = address32(pc_address_block, (pc & 0x7FFF)); \ |
217 | condition = block_data[block_data_position].condition; \ |
218 | \ |
219 | if((condition != last_condition) || (condition >= 0x20)) \ |
220 | { \ |
221 | if((last_condition & 0x0F) != 0x0E) \ |
222 | { \ |
223 | generate_branch_patch_conditional(backpatch_address, translation_ptr); \ |
224 | } \ |
225 | \ |
226 | last_condition = condition; \ |
227 | \ |
228 | condition &= 0x0F; \ |
229 | \ |
230 | if(condition != 0x0E) \ |
231 | { \ |
232 | arm_conditional_block_header(); \ |
233 | } \ |
234 | } \ |
235 | \ |
236 | switch((opcode >> 20) & 0xFF) \ |
237 | { \ |
238 | case 0x00: \ |
239 | if((opcode & 0x90) == 0x90) \ |
240 | { \ |
241 | if(opcode & 0x20) \ |
242 | { \ |
243 | /* STRH rd, [rn], -rm */ \ |
244 | arm_access_memory(store, down, post, u16, half_reg); \ |
245 | } \ |
246 | else \ |
247 | { \ |
248 | /* MUL rd, rm, rs */ \ |
249 | arm_multiply(no, no); \ |
250 | } \ |
251 | } \ |
252 | else \ |
253 | { \ |
254 | /* AND rd, rn, reg_op */ \ |
255 | arm_data_proc(and, reg, no_flags); \ |
256 | } \ |
257 | break; \ |
258 | \ |
259 | case 0x01: \ |
260 | if((opcode & 0x90) == 0x90) \ |
261 | { \ |
262 | switch((opcode >> 5) & 0x03) \ |
263 | { \ |
264 | case 0: \ |
265 | /* MULS rd, rm, rs */ \ |
266 | arm_multiply(no, yes); \ |
267 | break; \ |
268 | \ |
269 | case 1: \ |
270 | /* LDRH rd, [rn], -rm */ \ |
271 | arm_access_memory(load, down, post, u16, half_reg); \ |
272 | break; \ |
273 | \ |
274 | case 2: \ |
275 | /* LDRSB rd, [rn], -rm */ \ |
276 | arm_access_memory(load, down, post, s8, half_reg); \ |
277 | break; \ |
278 | \ |
279 | case 3: \ |
280 | /* LDRSH rd, [rn], -rm */ \ |
281 | arm_access_memory(load, down, post, s16, half_reg); \ |
282 | break; \ |
283 | } \ |
284 | } \ |
285 | else \ |
286 | { \ |
287 | /* ANDS rd, rn, reg_op */ \ |
288 | arm_data_proc(ands, reg_flags, flags); \ |
289 | } \ |
290 | break; \ |
291 | \ |
292 | case 0x02: \ |
293 | if((opcode & 0x90) == 0x90) \ |
294 | { \ |
295 | if(opcode & 0x20) \ |
296 | { \ |
297 | /* STRH rd, [rn], -rm */ \ |
298 | arm_access_memory(store, down, post, u16, half_reg); \ |
299 | } \ |
300 | else \ |
301 | { \ |
302 | /* MLA rd, rm, rs, rn */ \ |
303 | arm_multiply(yes, no); \ |
304 | } \ |
305 | } \ |
306 | else \ |
307 | { \ |
308 | /* EOR rd, rn, reg_op */ \ |
309 | arm_data_proc(eor, reg, no_flags); \ |
310 | } \ |
311 | break; \ |
312 | \ |
313 | case 0x03: \ |
314 | if((opcode & 0x90) == 0x90) \ |
315 | { \ |
316 | switch((opcode >> 5) & 0x03) \ |
317 | { \ |
318 | case 0: \ |
319 | /* MLAS rd, rm, rs, rn */ \ |
320 | arm_multiply(yes, yes); \ |
321 | break; \ |
322 | \ |
323 | case 1: \ |
324 | /* LDRH rd, [rn], -rm */ \ |
325 | arm_access_memory(load, down, post, u16, half_reg); \ |
326 | break; \ |
327 | \ |
328 | case 2: \ |
329 | /* LDRSB rd, [rn], -rm */ \ |
330 | arm_access_memory(load, down, post, s8, half_reg); \ |
331 | break; \ |
332 | \ |
333 | case 3: \ |
334 | /* LDRSH rd, [rn], -rm */ \ |
335 | arm_access_memory(load, down, post, s16, half_reg); \ |
336 | break; \ |
337 | } \ |
338 | } \ |
339 | else \ |
340 | { \ |
341 | /* EORS rd, rn, reg_op */ \ |
342 | arm_data_proc(eors, reg_flags, flags); \ |
343 | } \ |
344 | break; \ |
345 | \ |
346 | case 0x04: \ |
347 | if((opcode & 0x90) == 0x90) \ |
348 | { \ |
349 | /* STRH rd, [rn], -imm */ \ |
350 | arm_access_memory(store, down, post, u16, half_imm); \ |
351 | } \ |
352 | else \ |
353 | { \ |
354 | /* SUB rd, rn, reg_op */ \ |
355 | arm_data_proc(sub, reg, no_flags); \ |
356 | } \ |
357 | break; \ |
358 | \ |
359 | case 0x05: \ |
360 | if((opcode & 0x90) == 0x90) \ |
361 | { \ |
362 | switch((opcode >> 5) & 0x03) \ |
363 | { \ |
364 | case 1: \ |
365 | /* LDRH rd, [rn], -imm */ \ |
366 | arm_access_memory(load, down, post, u16, half_imm); \ |
367 | break; \ |
368 | \ |
369 | case 2: \ |
370 | /* LDRSB rd, [rn], -imm */ \ |
371 | arm_access_memory(load, down, post, s8, half_imm); \ |
372 | break; \ |
373 | \ |
374 | case 3: \ |
375 | /* LDRSH rd, [rn], -imm */ \ |
376 | arm_access_memory(load, down, post, s16, half_imm); \ |
377 | break; \ |
378 | } \ |
379 | } \ |
380 | else \ |
381 | { \ |
382 | /* SUBS rd, rn, reg_op */ \ |
383 | arm_data_proc(subs, reg, flags); \ |
384 | } \ |
385 | break; \ |
386 | \ |
387 | case 0x06: \ |
388 | if((opcode & 0x90) == 0x90) \ |
389 | { \ |
390 | /* STRH rd, [rn], -imm */ \ |
391 | arm_access_memory(store, down, post, u16, half_imm); \ |
392 | } \ |
393 | else \ |
394 | { \ |
395 | /* RSB rd, rn, reg_op */ \ |
396 | arm_data_proc(rsb, reg, no_flags); \ |
397 | } \ |
398 | break; \ |
399 | \ |
400 | case 0x07: \ |
401 | if((opcode & 0x90) == 0x90) \ |
402 | { \ |
403 | switch((opcode >> 5) & 0x03) \ |
404 | { \ |
405 | case 1: \ |
406 | /* LDRH rd, [rn], -imm */ \ |
407 | arm_access_memory(load, down, post, u16, half_imm); \ |
408 | break; \ |
409 | \ |
410 | case 2: \ |
411 | /* LDRSB rd, [rn], -imm */ \ |
412 | arm_access_memory(load, down, post, s8, half_imm); \ |
413 | break; \ |
414 | \ |
415 | case 3: \ |
416 | /* LDRSH rd, [rn], -imm */ \ |
417 | arm_access_memory(load, down, post, s16, half_imm); \ |
418 | break; \ |
419 | } \ |
420 | } \ |
421 | else \ |
422 | { \ |
423 | /* RSBS rd, rn, reg_op */ \ |
424 | arm_data_proc(rsbs, reg, flags); \ |
425 | } \ |
426 | break; \ |
427 | \ |
428 | case 0x08: \ |
429 | if((opcode & 0x90) == 0x90) \ |
430 | { \ |
431 | if(opcode & 0x20) \ |
432 | { \ |
433 | /* STRH rd, [rn], +rm */ \ |
434 | arm_access_memory(store, up, post, u16, half_reg); \ |
435 | } \ |
436 | else \ |
437 | { \ |
438 | /* UMULL rd, rm, rs */ \ |
439 | arm_multiply_long(u64, no, no); \ |
440 | } \ |
441 | } \ |
442 | else \ |
443 | { \ |
444 | /* ADD rd, rn, reg_op */ \ |
445 | arm_data_proc(add, reg, no_flags); \ |
446 | } \ |
447 | break; \ |
448 | \ |
449 | case 0x09: \ |
450 | if((opcode & 0x90) == 0x90) \ |
451 | { \ |
452 | switch((opcode >> 5) & 0x03) \ |
453 | { \ |
454 | case 0: \ |
455 | /* UMULLS rdlo, rdhi, rm, rs */ \ |
456 | arm_multiply_long(u64, no, yes); \ |
457 | break; \ |
458 | \ |
459 | case 1: \ |
460 | /* LDRH rd, [rn], +rm */ \ |
461 | arm_access_memory(load, up, post, u16, half_reg); \ |
462 | break; \ |
463 | \ |
464 | case 2: \ |
465 | /* LDRSB rd, [rn], +rm */ \ |
466 | arm_access_memory(load, up, post, s8, half_reg); \ |
467 | break; \ |
468 | \ |
469 | case 3: \ |
470 | /* LDRSH rd, [rn], +rm */ \ |
471 | arm_access_memory(load, up, post, s16, half_reg); \ |
472 | break; \ |
473 | } \ |
474 | } \ |
475 | else \ |
476 | { \ |
477 | /* ADDS rd, rn, reg_op */ \ |
478 | arm_data_proc(adds, reg, flags); \ |
479 | } \ |
480 | break; \ |
481 | \ |
482 | case 0x0A: \ |
483 | if((opcode & 0x90) == 0x90) \ |
484 | { \ |
485 | if(opcode & 0x20) \ |
486 | { \ |
487 | /* STRH rd, [rn], +rm */ \ |
488 | arm_access_memory(store, up, post, u16, half_reg); \ |
489 | } \ |
490 | else \ |
491 | { \ |
492 | /* UMLAL rd, rm, rs */ \ |
493 | arm_multiply_long(u64_add, yes, no); \ |
494 | } \ |
495 | } \ |
496 | else \ |
497 | { \ |
498 | /* ADC rd, rn, reg_op */ \ |
499 | arm_data_proc(adc, reg, no_flags); \ |
500 | } \ |
501 | break; \ |
502 | \ |
503 | case 0x0B: \ |
504 | if((opcode & 0x90) == 0x90) \ |
505 | { \ |
506 | switch((opcode >> 5) & 0x03) \ |
507 | { \ |
508 | case 0: \ |
509 | /* UMLALS rdlo, rdhi, rm, rs */ \ |
510 | arm_multiply_long(u64_add, yes, yes); \ |
511 | break; \ |
512 | \ |
513 | case 1: \ |
514 | /* LDRH rd, [rn], +rm */ \ |
515 | arm_access_memory(load, up, post, u16, half_reg); \ |
516 | break; \ |
517 | \ |
518 | case 2: \ |
519 | /* LDRSB rd, [rn], +rm */ \ |
520 | arm_access_memory(load, up, post, s8, half_reg); \ |
521 | break; \ |
522 | \ |
523 | case 3: \ |
524 | /* LDRSH rd, [rn], +rm */ \ |
525 | arm_access_memory(load, up, post, s16, half_reg); \ |
526 | break; \ |
527 | } \ |
528 | } \ |
529 | else \ |
530 | { \ |
531 | /* ADCS rd, rn, reg_op */ \ |
532 | arm_data_proc(adcs, reg, flags); \ |
533 | } \ |
534 | break; \ |
535 | \ |
536 | case 0x0C: \ |
537 | if((opcode & 0x90) == 0x90) \ |
538 | { \ |
539 | if(opcode & 0x20) \ |
540 | { \ |
541 | /* STRH rd, [rn], +imm */ \ |
542 | arm_access_memory(store, up, post, u16, half_imm); \ |
543 | } \ |
544 | else \ |
545 | { \ |
546 | /* SMULL rd, rm, rs */ \ |
547 | arm_multiply_long(s64, no, no); \ |
548 | } \ |
549 | } \ |
550 | else \ |
551 | { \ |
552 | /* SBC rd, rn, reg_op */ \ |
553 | arm_data_proc(sbc, reg, no_flags); \ |
554 | } \ |
555 | break; \ |
556 | \ |
557 | case 0x0D: \ |
558 | if((opcode & 0x90) == 0x90) \ |
559 | { \ |
560 | switch((opcode >> 5) & 0x03) \ |
561 | { \ |
562 | case 0: \ |
563 | /* SMULLS rdlo, rdhi, rm, rs */ \ |
564 | arm_multiply_long(s64, no, yes); \ |
565 | break; \ |
566 | \ |
567 | case 1: \ |
568 | /* LDRH rd, [rn], +imm */ \ |
569 | arm_access_memory(load, up, post, u16, half_imm); \ |
570 | break; \ |
571 | \ |
572 | case 2: \ |
573 | /* LDRSB rd, [rn], +imm */ \ |
574 | arm_access_memory(load, up, post, s8, half_imm); \ |
575 | break; \ |
576 | \ |
577 | case 3: \ |
578 | /* LDRSH rd, [rn], +imm */ \ |
579 | arm_access_memory(load, up, post, s16, half_imm); \ |
580 | break; \ |
581 | } \ |
582 | } \ |
583 | else \ |
584 | { \ |
585 | /* SBCS rd, rn, reg_op */ \ |
586 | arm_data_proc(sbcs, reg, flags); \ |
587 | } \ |
588 | break; \ |
589 | \ |
590 | case 0x0E: \ |
591 | if((opcode & 0x90) == 0x90) \ |
592 | { \ |
593 | if(opcode & 0x20) \ |
594 | { \ |
595 | /* STRH rd, [rn], +imm */ \ |
596 | arm_access_memory(store, up, post, u16, half_imm); \ |
597 | } \ |
598 | else \ |
599 | { \ |
600 | /* SMLAL rd, rm, rs */ \ |
601 | arm_multiply_long(s64_add, yes, no); \ |
602 | } \ |
603 | } \ |
604 | else \ |
605 | { \ |
606 | /* RSC rd, rn, reg_op */ \ |
607 | arm_data_proc(rsc, reg, no_flags); \ |
608 | } \ |
609 | break; \ |
610 | \ |
611 | case 0x0F: \ |
612 | if((opcode & 0x90) == 0x90) \ |
613 | { \ |
614 | switch((opcode >> 5) & 0x03) \ |
615 | { \ |
616 | case 0: \ |
617 | /* SMLALS rdlo, rdhi, rm, rs */ \ |
618 | arm_multiply_long(s64_add, yes, yes); \ |
619 | break; \ |
620 | \ |
621 | case 1: \ |
622 | /* LDRH rd, [rn], +imm */ \ |
623 | arm_access_memory(load, up, post, u16, half_imm); \ |
624 | break; \ |
625 | \ |
626 | case 2: \ |
627 | /* LDRSB rd, [rn], +imm */ \ |
628 | arm_access_memory(load, up, post, s8, half_imm); \ |
629 | break; \ |
630 | \ |
631 | case 3: \ |
632 | /* LDRSH rd, [rn], +imm */ \ |
633 | arm_access_memory(load, up, post, s16, half_imm); \ |
634 | break; \ |
635 | } \ |
636 | } \ |
637 | else \ |
638 | { \ |
639 | /* RSCS rd, rn, reg_op */ \ |
640 | arm_data_proc(rscs, reg, flags); \ |
641 | } \ |
642 | break; \ |
643 | \ |
644 | case 0x10: \ |
645 | if((opcode & 0x90) == 0x90) \ |
646 | { \ |
647 | if(opcode & 0x20) \ |
648 | { \ |
649 | /* STRH rd, [rn - rm] */ \ |
650 | arm_access_memory(store, down, pre, u16, half_reg); \ |
651 | } \ |
652 | else \ |
653 | { \ |
654 | /* SWP rd, rm, [rn] */ \ |
655 | arm_swap(u32); \ |
656 | } \ |
657 | } \ |
658 | else \ |
659 | { \ |
660 | /* MRS rd, cpsr */ \ |
661 | arm_psr(reg, read, cpsr); \ |
662 | } \ |
663 | break; \ |
664 | \ |
665 | case 0x11: \ |
666 | if((opcode & 0x90) == 0x90) \ |
667 | { \ |
668 | switch((opcode >> 5) & 0x03) \ |
669 | { \ |
670 | case 1: \ |
671 | /* LDRH rd, [rn - rm] */ \ |
672 | arm_access_memory(load, down, pre, u16, half_reg); \ |
673 | break; \ |
674 | \ |
675 | case 2: \ |
676 | /* LDRSB rd, [rn - rm] */ \ |
677 | arm_access_memory(load, down, pre, s8, half_reg); \ |
678 | break; \ |
679 | \ |
680 | case 3: \ |
681 | /* LDRSH rd, [rn - rm] */ \ |
682 | arm_access_memory(load, down, pre, s16, half_reg); \ |
683 | break; \ |
684 | } \ |
685 | } \ |
686 | else \ |
687 | { \ |
688 | /* TST rd, rn, reg_op */ \ |
689 | arm_data_proc_test(tst, reg_flags); \ |
690 | } \ |
691 | break; \ |
692 | \ |
693 | case 0x12: \ |
694 | if((opcode & 0x90) == 0x90) \ |
695 | { \ |
696 | /* STRH rd, [rn - rm]! */ \ |
697 | arm_access_memory(store, down, pre_wb, u16, half_reg); \ |
698 | } \ |
699 | else \ |
700 | { \ |
701 | if(opcode & 0x10) \ |
702 | { \ |
703 | /* BX rn */ \ |
704 | arm_bx(); \ |
705 | } \ |
706 | else \ |
707 | { \ |
708 | /* MSR cpsr, rm */ \ |
709 | arm_psr(reg, store, cpsr); \ |
710 | } \ |
711 | } \ |
712 | break; \ |
713 | \ |
714 | case 0x13: \ |
715 | if((opcode & 0x90) == 0x90) \ |
716 | { \ |
717 | switch((opcode >> 5) & 0x03) \ |
718 | { \ |
719 | case 1: \ |
720 | /* LDRH rd, [rn - rm]! */ \ |
721 | arm_access_memory(load, down, pre_wb, u16, half_reg); \ |
722 | break; \ |
723 | \ |
724 | case 2: \ |
725 | /* LDRSB rd, [rn - rm]! */ \ |
726 | arm_access_memory(load, down, pre_wb, s8, half_reg); \ |
727 | break; \ |
728 | \ |
729 | case 3: \ |
730 | /* LDRSH rd, [rn - rm]! */ \ |
731 | arm_access_memory(load, down, pre_wb, s16, half_reg); \ |
732 | break; \ |
733 | } \ |
734 | } \ |
735 | else \ |
736 | { \ |
737 | /* TEQ rd, rn, reg_op */ \ |
738 | arm_data_proc_test(teq, reg_flags); \ |
739 | } \ |
740 | break; \ |
741 | \ |
742 | case 0x14: \ |
743 | if((opcode & 0x90) == 0x90) \ |
744 | { \ |
745 | if(opcode & 0x20) \ |
746 | { \ |
747 | /* STRH rd, [rn - imm] */ \ |
748 | arm_access_memory(store, down, pre, u16, half_imm); \ |
749 | } \ |
750 | else \ |
751 | { \ |
752 | /* SWPB rd, rm, [rn] */ \ |
753 | arm_swap(u8); \ |
754 | } \ |
755 | } \ |
756 | else \ |
757 | { \ |
758 | /* MRS rd, spsr */ \ |
759 | arm_psr(reg, read, spsr); \ |
760 | } \ |
761 | break; \ |
762 | \ |
763 | case 0x15: \ |
764 | if((opcode & 0x90) == 0x90) \ |
765 | { \ |
766 | switch((opcode >> 5) & 0x03) \ |
767 | { \ |
768 | case 1: \ |
769 | /* LDRH rd, [rn - imm] */ \ |
770 | arm_access_memory(load, down, pre, u16, half_imm); \ |
771 | break; \ |
772 | \ |
773 | case 2: \ |
774 | /* LDRSB rd, [rn - imm] */ \ |
775 | arm_access_memory(load, down, pre, s8, half_imm); \ |
776 | break; \ |
777 | \ |
778 | case 3: \ |
779 | /* LDRSH rd, [rn - imm] */ \ |
780 | arm_access_memory(load, down, pre, s16, half_imm); \ |
781 | break; \ |
782 | } \ |
783 | } \ |
784 | else \ |
785 | { \ |
786 | /* CMP rn, reg_op */ \ |
787 | arm_data_proc_test(cmp, reg); \ |
788 | } \ |
789 | break; \ |
790 | \ |
791 | case 0x16: \ |
792 | if((opcode & 0x90) == 0x90) \ |
793 | { \ |
794 | /* STRH rd, [rn - imm]! */ \ |
795 | arm_access_memory(store, down, pre_wb, u16, half_imm); \ |
796 | } \ |
797 | else \ |
798 | { \ |
799 | /* MSR spsr, rm */ \ |
800 | arm_psr(reg, store, spsr); \ |
801 | } \ |
802 | break; \ |
803 | \ |
804 | case 0x17: \ |
805 | if((opcode & 0x90) == 0x90) \ |
806 | { \ |
807 | switch((opcode >> 5) & 0x03) \ |
808 | { \ |
809 | case 1: \ |
810 | /* LDRH rd, [rn - imm]! */ \ |
811 | arm_access_memory(load, down, pre_wb, u16, half_imm); \ |
812 | break; \ |
813 | \ |
814 | case 2: \ |
815 | /* LDRSB rd, [rn - imm]! */ \ |
816 | arm_access_memory(load, down, pre_wb, s8, half_imm); \ |
817 | break; \ |
818 | \ |
819 | case 3: \ |
820 | /* LDRSH rd, [rn - imm]! */ \ |
821 | arm_access_memory(load, down, pre_wb, s16, half_imm); \ |
822 | break; \ |
823 | } \ |
824 | } \ |
825 | else \ |
826 | { \ |
827 | /* CMN rd, rn, reg_op */ \ |
828 | arm_data_proc_test(cmn, reg); \ |
829 | } \ |
830 | break; \ |
831 | \ |
832 | case 0x18: \ |
833 | if((opcode & 0x90) == 0x90) \ |
834 | { \ |
835 | /* STRH rd, [rn + rm] */ \ |
836 | arm_access_memory(store, up, pre, u16, half_reg); \ |
837 | } \ |
838 | else \ |
839 | { \ |
840 | /* ORR rd, rn, reg_op */ \ |
841 | arm_data_proc(orr, reg, no_flags); \ |
842 | } \ |
843 | break; \ |
844 | \ |
845 | case 0x19: \ |
846 | if((opcode & 0x90) == 0x90) \ |
847 | { \ |
848 | switch((opcode >> 5) & 0x03) \ |
849 | { \ |
850 | case 1: \ |
851 | /* LDRH rd, [rn + rm] */ \ |
852 | arm_access_memory(load, up, pre, u16, half_reg); \ |
853 | break; \ |
854 | \ |
855 | case 2: \ |
856 | /* LDRSB rd, [rn + rm] */ \ |
857 | arm_access_memory(load, up, pre, s8, half_reg); \ |
858 | break; \ |
859 | \ |
860 | case 3: \ |
861 | /* LDRSH rd, [rn + rm] */ \ |
862 | arm_access_memory(load, up, pre, s16, half_reg); \ |
863 | break; \ |
864 | } \ |
865 | } \ |
866 | else \ |
867 | { \ |
868 | /* ORRS rd, rn, reg_op */ \ |
869 | arm_data_proc(orrs, reg_flags, flags); \ |
870 | } \ |
871 | break; \ |
872 | \ |
873 | case 0x1A: \ |
874 | if((opcode & 0x90) == 0x90) \ |
875 | { \ |
876 | /* STRH rd, [rn + rm]! */ \ |
877 | arm_access_memory(store, up, pre_wb, u16, half_reg); \ |
878 | } \ |
879 | else \ |
880 | { \ |
881 | /* MOV rd, reg_op */ \ |
882 | arm_data_proc_unary(mov, reg, no_flags); \ |
883 | } \ |
884 | break; \ |
885 | \ |
886 | case 0x1B: \ |
887 | if((opcode & 0x90) == 0x90) \ |
888 | { \ |
889 | switch((opcode >> 5) & 0x03) \ |
890 | { \ |
891 | case 1: \ |
892 | /* LDRH rd, [rn + rm]! */ \ |
893 | arm_access_memory(load, up, pre_wb, u16, half_reg); \ |
894 | break; \ |
895 | \ |
896 | case 2: \ |
897 | /* LDRSB rd, [rn + rm]! */ \ |
898 | arm_access_memory(load, up, pre_wb, s8, half_reg); \ |
899 | break; \ |
900 | \ |
901 | case 3: \ |
902 | /* LDRSH rd, [rn + rm]! */ \ |
903 | arm_access_memory(load, up, pre_wb, s16, half_reg); \ |
904 | break; \ |
905 | } \ |
906 | } \ |
907 | else \ |
908 | { \ |
909 | /* MOVS rd, reg_op */ \ |
910 | arm_data_proc_unary(movs, reg_flags, flags); \ |
911 | } \ |
912 | break; \ |
913 | \ |
914 | case 0x1C: \ |
915 | if((opcode & 0x90) == 0x90) \ |
916 | { \ |
917 | /* STRH rd, [rn + imm] */ \ |
918 | arm_access_memory(store, up, pre, u16, half_imm); \ |
919 | } \ |
920 | else \ |
921 | { \ |
922 | /* BIC rd, rn, reg_op */ \ |
923 | arm_data_proc(bic, reg, no_flags); \ |
924 | } \ |
925 | break; \ |
926 | \ |
927 | case 0x1D: \ |
928 | if((opcode & 0x90) == 0x90) \ |
929 | { \ |
930 | switch((opcode >> 5) & 0x03) \ |
931 | { \ |
932 | case 1: \ |
933 | /* LDRH rd, [rn + imm] */ \ |
934 | arm_access_memory(load, up, pre, u16, half_imm); \ |
935 | break; \ |
936 | \ |
937 | case 2: \ |
938 | /* LDRSB rd, [rn + imm] */ \ |
939 | arm_access_memory(load, up, pre, s8, half_imm); \ |
940 | break; \ |
941 | \ |
942 | case 3: \ |
943 | /* LDRSH rd, [rn + imm] */ \ |
944 | arm_access_memory(load, up, pre, s16, half_imm); \ |
945 | break; \ |
946 | } \ |
947 | } \ |
948 | else \ |
949 | { \ |
950 | /* BICS rd, rn, reg_op */ \ |
951 | arm_data_proc(bics, reg_flags, flags); \ |
952 | } \ |
953 | break; \ |
954 | \ |
955 | case 0x1E: \ |
956 | if((opcode & 0x90) == 0x90) \ |
957 | { \ |
958 | /* STRH rd, [rn + imm]! */ \ |
959 | arm_access_memory(store, up, pre_wb, u16, half_imm); \ |
960 | } \ |
961 | else \ |
962 | { \ |
963 | /* MVN rd, reg_op */ \ |
964 | arm_data_proc_unary(mvn, reg, no_flags); \ |
965 | } \ |
966 | break; \ |
967 | \ |
968 | case 0x1F: \ |
969 | if((opcode & 0x90) == 0x90) \ |
970 | { \ |
971 | switch((opcode >> 5) & 0x03) \ |
972 | { \ |
973 | case 1: \ |
974 | /* LDRH rd, [rn + imm]! */ \ |
975 | arm_access_memory(load, up, pre_wb, u16, half_imm); \ |
976 | break; \ |
977 | \ |
978 | case 2: \ |
979 | /* LDRSB rd, [rn + imm]! */ \ |
980 | arm_access_memory(load, up, pre_wb, s8, half_imm); \ |
981 | break; \ |
982 | \ |
983 | case 3: \ |
984 | /* LDRSH rd, [rn + imm]! */ \ |
985 | arm_access_memory(load, up, pre_wb, s16, half_imm); \ |
986 | break; \ |
987 | } \ |
988 | } \ |
989 | else \ |
990 | { \ |
991 | /* MVNS rd, rn, reg_op */ \ |
992 | arm_data_proc_unary(mvns, reg_flags, flags); \ |
993 | } \ |
994 | break; \ |
995 | \ |
996 | case 0x20: \ |
997 | /* AND rd, rn, imm */ \ |
998 | arm_data_proc(and, imm, no_flags); \ |
999 | break; \ |
1000 | \ |
1001 | case 0x21: \ |
1002 | /* ANDS rd, rn, imm */ \ |
1003 | arm_data_proc(ands, imm_flags, flags); \ |
1004 | break; \ |
1005 | \ |
1006 | case 0x22: \ |
1007 | /* EOR rd, rn, imm */ \ |
1008 | arm_data_proc(eor, imm, no_flags); \ |
1009 | break; \ |
1010 | \ |
1011 | case 0x23: \ |
1012 | /* EORS rd, rn, imm */ \ |
1013 | arm_data_proc(eors, imm_flags, flags); \ |
1014 | break; \ |
1015 | \ |
1016 | case 0x24: \ |
1017 | /* SUB rd, rn, imm */ \ |
1018 | arm_data_proc(sub, imm, no_flags); \ |
1019 | break; \ |
1020 | \ |
1021 | case 0x25: \ |
1022 | /* SUBS rd, rn, imm */ \ |
1023 | arm_data_proc(subs, imm, flags); \ |
1024 | break; \ |
1025 | \ |
1026 | case 0x26: \ |
1027 | /* RSB rd, rn, imm */ \ |
1028 | arm_data_proc(rsb, imm, no_flags); \ |
1029 | break; \ |
1030 | \ |
1031 | case 0x27: \ |
1032 | /* RSBS rd, rn, imm */ \ |
1033 | arm_data_proc(rsbs, imm, flags); \ |
1034 | break; \ |
1035 | \ |
1036 | case 0x28: \ |
1037 | /* ADD rd, rn, imm */ \ |
1038 | arm_data_proc(add, imm, no_flags); \ |
1039 | break; \ |
1040 | \ |
1041 | case 0x29: \ |
1042 | /* ADDS rd, rn, imm */ \ |
1043 | arm_data_proc(adds, imm, flags); \ |
1044 | break; \ |
1045 | \ |
1046 | case 0x2A: \ |
1047 | /* ADC rd, rn, imm */ \ |
1048 | arm_data_proc(adc, imm, no_flags); \ |
1049 | break; \ |
1050 | \ |
1051 | case 0x2B: \ |
1052 | /* ADCS rd, rn, imm */ \ |
1053 | arm_data_proc(adcs, imm, flags); \ |
1054 | break; \ |
1055 | \ |
1056 | case 0x2C: \ |
1057 | /* SBC rd, rn, imm */ \ |
1058 | arm_data_proc(sbc, imm, no_flags); \ |
1059 | break; \ |
1060 | \ |
1061 | case 0x2D: \ |
1062 | /* SBCS rd, rn, imm */ \ |
1063 | arm_data_proc(sbcs, imm, flags); \ |
1064 | break; \ |
1065 | \ |
1066 | case 0x2E: \ |
1067 | /* RSC rd, rn, imm */ \ |
1068 | arm_data_proc(rsc, imm, no_flags); \ |
1069 | break; \ |
1070 | \ |
1071 | case 0x2F: \ |
1072 | /* RSCS rd, rn, imm */ \ |
1073 | arm_data_proc(rscs, imm, flags); \ |
1074 | break; \ |
1075 | \ |
1076 | case 0x30 ... 0x31: \ |
1077 | /* TST rn, imm */ \ |
1078 | arm_data_proc_test(tst, imm); \ |
1079 | break; \ |
1080 | \ |
1081 | case 0x32: \ |
1082 | /* MSR cpsr, imm */ \ |
1083 | arm_psr(imm, store, cpsr); \ |
1084 | break; \ |
1085 | \ |
1086 | case 0x33: \ |
1087 | /* TEQ rn, imm */ \ |
1088 | arm_data_proc_test(teq, imm); \ |
1089 | break; \ |
1090 | \ |
1091 | case 0x34 ... 0x35: \ |
1092 | /* CMP rn, imm */ \ |
1093 | arm_data_proc_test(cmp, imm); \ |
1094 | break; \ |
1095 | \ |
1096 | case 0x36: \ |
1097 | /* MSR spsr, imm */ \ |
1098 | arm_psr(imm, store, spsr); \ |
1099 | break; \ |
1100 | \ |
1101 | case 0x37: \ |
1102 | /* CMN rn, imm */ \ |
1103 | arm_data_proc_test(cmn, imm); \ |
1104 | break; \ |
1105 | \ |
1106 | case 0x38: \ |
1107 | /* ORR rd, rn, imm */ \ |
1108 | arm_data_proc(orr, imm, no_flags); \ |
1109 | break; \ |
1110 | \ |
1111 | case 0x39: \ |
1112 | /* ORRS rd, rn, imm */ \ |
1113 | arm_data_proc(orrs, imm_flags, flags); \ |
1114 | break; \ |
1115 | \ |
1116 | case 0x3A: \ |
1117 | /* MOV rd, imm */ \ |
1118 | arm_data_proc_unary(mov, imm, no_flags); \ |
1119 | break; \ |
1120 | \ |
1121 | case 0x3B: \ |
1122 | /* MOVS rd, imm */ \ |
1123 | arm_data_proc_unary(movs, imm_flags, flags); \ |
1124 | break; \ |
1125 | \ |
1126 | case 0x3C: \ |
1127 | /* BIC rd, rn, imm */ \ |
1128 | arm_data_proc(bic, imm, no_flags); \ |
1129 | break; \ |
1130 | \ |
1131 | case 0x3D: \ |
1132 | /* BICS rd, rn, imm */ \ |
1133 | arm_data_proc(bics, imm_flags, flags); \ |
1134 | break; \ |
1135 | \ |
1136 | case 0x3E: \ |
1137 | /* MVN rd, imm */ \ |
1138 | arm_data_proc_unary(mvn, imm, no_flags); \ |
1139 | break; \ |
1140 | \ |
1141 | case 0x3F: \ |
1142 | /* MVNS rd, imm */ \ |
1143 | arm_data_proc_unary(mvns, imm_flags, flags); \ |
1144 | break; \ |
1145 | \ |
1146 | case 0x40: \ |
1147 | /* STR rd, [rn], -imm */ \ |
1148 | arm_access_memory(store, down, post, u32, imm); \ |
1149 | break; \ |
1150 | \ |
1151 | case 0x41: \ |
1152 | /* LDR rd, [rn], -imm */ \ |
1153 | arm_access_memory(load, down, post, u32, imm); \ |
1154 | break; \ |
1155 | \ |
1156 | case 0x42: \ |
1157 | /* STRT rd, [rn], -imm */ \ |
1158 | arm_access_memory(store, down, post, u32, imm); \ |
1159 | break; \ |
1160 | \ |
1161 | case 0x43: \ |
1162 | /* LDRT rd, [rn], -imm */ \ |
1163 | arm_access_memory(load, down, post, u32, imm); \ |
1164 | break; \ |
1165 | \ |
1166 | case 0x44: \ |
1167 | /* STRB rd, [rn], -imm */ \ |
1168 | arm_access_memory(store, down, post, u8, imm); \ |
1169 | break; \ |
1170 | \ |
1171 | case 0x45: \ |
1172 | /* LDRB rd, [rn], -imm */ \ |
1173 | arm_access_memory(load, down, post, u8, imm); \ |
1174 | break; \ |
1175 | \ |
1176 | case 0x46: \ |
1177 | /* STRBT rd, [rn], -imm */ \ |
1178 | arm_access_memory(store, down, post, u8, imm); \ |
1179 | break; \ |
1180 | \ |
1181 | case 0x47: \ |
1182 | /* LDRBT rd, [rn], -imm */ \ |
1183 | arm_access_memory(load, down, post, u8, imm); \ |
1184 | break; \ |
1185 | \ |
1186 | case 0x48: \ |
1187 | /* STR rd, [rn], +imm */ \ |
1188 | arm_access_memory(store, up, post, u32, imm); \ |
1189 | break; \ |
1190 | \ |
1191 | case 0x49: \ |
1192 | /* LDR rd, [rn], +imm */ \ |
1193 | arm_access_memory(load, up, post, u32, imm); \ |
1194 | break; \ |
1195 | \ |
1196 | case 0x4A: \ |
1197 | /* STRT rd, [rn], +imm */ \ |
1198 | arm_access_memory(store, up, post, u32, imm); \ |
1199 | break; \ |
1200 | \ |
1201 | case 0x4B: \ |
1202 | /* LDRT rd, [rn], +imm */ \ |
1203 | arm_access_memory(load, up, post, u32, imm); \ |
1204 | break; \ |
1205 | \ |
1206 | case 0x4C: \ |
1207 | /* STRB rd, [rn], +imm */ \ |
1208 | arm_access_memory(store, up, post, u8, imm); \ |
1209 | break; \ |
1210 | \ |
1211 | case 0x4D: \ |
1212 | /* LDRB rd, [rn], +imm */ \ |
1213 | arm_access_memory(load, up, post, u8, imm); \ |
1214 | break; \ |
1215 | \ |
1216 | case 0x4E: \ |
1217 | /* STRBT rd, [rn], +imm */ \ |
1218 | arm_access_memory(store, up, post, u8, imm); \ |
1219 | break; \ |
1220 | \ |
1221 | case 0x4F: \ |
1222 | /* LDRBT rd, [rn], +imm */ \ |
1223 | arm_access_memory(load, up, post, u8, imm); \ |
1224 | break; \ |
1225 | \ |
1226 | case 0x50: \ |
1227 | /* STR rd, [rn - imm] */ \ |
1228 | arm_access_memory(store, down, pre, u32, imm); \ |
1229 | break; \ |
1230 | \ |
1231 | case 0x51: \ |
1232 | /* LDR rd, [rn - imm] */ \ |
1233 | arm_access_memory(load, down, pre, u32, imm); \ |
1234 | break; \ |
1235 | \ |
1236 | case 0x52: \ |
1237 | /* STR rd, [rn - imm]! */ \ |
1238 | arm_access_memory(store, down, pre_wb, u32, imm); \ |
1239 | break; \ |
1240 | \ |
1241 | case 0x53: \ |
1242 | /* LDR rd, [rn - imm]! */ \ |
1243 | arm_access_memory(load, down, pre_wb, u32, imm); \ |
1244 | break; \ |
1245 | \ |
1246 | case 0x54: \ |
1247 | /* STRB rd, [rn - imm] */ \ |
1248 | arm_access_memory(store, down, pre, u8, imm); \ |
1249 | break; \ |
1250 | \ |
1251 | case 0x55: \ |
1252 | /* LDRB rd, [rn - imm] */ \ |
1253 | arm_access_memory(load, down, pre, u8, imm); \ |
1254 | break; \ |
1255 | \ |
1256 | case 0x56: \ |
1257 | /* STRB rd, [rn - imm]! */ \ |
1258 | arm_access_memory(store, down, pre_wb, u8, imm); \ |
1259 | break; \ |
1260 | \ |
1261 | case 0x57: \ |
1262 | /* LDRB rd, [rn - imm]! */ \ |
1263 | arm_access_memory(load, down, pre_wb, u8, imm); \ |
1264 | break; \ |
1265 | \ |
1266 | case 0x58: \ |
1267 | /* STR rd, [rn + imm] */ \ |
1268 | arm_access_memory(store, up, pre, u32, imm); \ |
1269 | break; \ |
1270 | \ |
1271 | case 0x59: \ |
1272 | /* LDR rd, [rn + imm] */ \ |
1273 | arm_access_memory(load, up, pre, u32, imm); \ |
1274 | break; \ |
1275 | \ |
1276 | case 0x5A: \ |
1277 | /* STR rd, [rn + imm]! */ \ |
1278 | arm_access_memory(store, up, pre_wb, u32, imm); \ |
1279 | break; \ |
1280 | \ |
1281 | case 0x5B: \ |
1282 | /* LDR rd, [rn + imm]! */ \ |
1283 | arm_access_memory(load, up, pre_wb, u32, imm); \ |
1284 | break; \ |
1285 | \ |
1286 | case 0x5C: \ |
1287 | /* STRB rd, [rn + imm] */ \ |
1288 | arm_access_memory(store, up, pre, u8, imm); \ |
1289 | break; \ |
1290 | \ |
1291 | case 0x5D: \ |
1292 | /* LDRB rd, [rn + imm] */ \ |
1293 | arm_access_memory(load, up, pre, u8, imm); \ |
1294 | break; \ |
1295 | \ |
1296 | case 0x5E: \ |
1297 | /* STRB rd, [rn + imm]! */ \ |
1298 | arm_access_memory(store, up, pre_wb, u8, imm); \ |
1299 | break; \ |
1300 | \ |
1301 | case 0x5F: \ |
1302 | /* LDRBT rd, [rn + imm]! */ \ |
1303 | arm_access_memory(load, up, pre_wb, u8, imm); \ |
1304 | break; \ |
1305 | \ |
1306 | case 0x60: \ |
1307 | /* STR rd, [rn], -rm */ \ |
1308 | arm_access_memory(store, down, post, u32, reg); \ |
1309 | break; \ |
1310 | \ |
1311 | case 0x61: \ |
1312 | /* LDR rd, [rn], -rm */ \ |
1313 | arm_access_memory(load, down, post, u32, reg); \ |
1314 | break; \ |
1315 | \ |
1316 | case 0x62: \ |
1317 | /* STRT rd, [rn], -rm */ \ |
1318 | arm_access_memory(store, down, post, u32, reg); \ |
1319 | break; \ |
1320 | \ |
1321 | case 0x63: \ |
1322 | /* LDRT rd, [rn], -rm */ \ |
1323 | arm_access_memory(load, down, post, u32, reg); \ |
1324 | break; \ |
1325 | \ |
1326 | case 0x64: \ |
1327 | /* STRB rd, [rn], -rm */ \ |
1328 | arm_access_memory(store, down, post, u8, reg); \ |
1329 | break; \ |
1330 | \ |
1331 | case 0x65: \ |
1332 | /* LDRB rd, [rn], -rm */ \ |
1333 | arm_access_memory(load, down, post, u8, reg); \ |
1334 | break; \ |
1335 | \ |
1336 | case 0x66: \ |
1337 | /* STRBT rd, [rn], -rm */ \ |
1338 | arm_access_memory(store, down, post, u8, reg); \ |
1339 | break; \ |
1340 | \ |
1341 | case 0x67: \ |
1342 | /* LDRBT rd, [rn], -rm */ \ |
1343 | arm_access_memory(load, down, post, u8, reg); \ |
1344 | break; \ |
1345 | \ |
1346 | case 0x68: \ |
1347 | /* STR rd, [rn], +rm */ \ |
1348 | arm_access_memory(store, up, post, u32, reg); \ |
1349 | break; \ |
1350 | \ |
1351 | case 0x69: \ |
1352 | /* LDR rd, [rn], +rm */ \ |
1353 | arm_access_memory(load, up, post, u32, reg); \ |
1354 | break; \ |
1355 | \ |
1356 | case 0x6A: \ |
1357 | /* STRT rd, [rn], +rm */ \ |
1358 | arm_access_memory(store, up, post, u32, reg); \ |
1359 | break; \ |
1360 | \ |
1361 | case 0x6B: \ |
1362 | /* LDRT rd, [rn], +rm */ \ |
1363 | arm_access_memory(load, up, post, u32, reg); \ |
1364 | break; \ |
1365 | \ |
1366 | case 0x6C: \ |
1367 | /* STRB rd, [rn], +rm */ \ |
1368 | arm_access_memory(store, up, post, u8, reg); \ |
1369 | break; \ |
1370 | \ |
1371 | case 0x6D: \ |
1372 | /* LDRB rd, [rn], +rm */ \ |
1373 | arm_access_memory(load, up, post, u8, reg); \ |
1374 | break; \ |
1375 | \ |
1376 | case 0x6E: \ |
1377 | /* STRBT rd, [rn], +rm */ \ |
1378 | arm_access_memory(store, up, post, u8, reg); \ |
1379 | break; \ |
1380 | \ |
1381 | case 0x6F: \ |
1382 | /* LDRBT rd, [rn], +rm */ \ |
1383 | arm_access_memory(load, up, post, u8, reg); \ |
1384 | break; \ |
1385 | \ |
1386 | case 0x70: \ |
1387 | /* STR rd, [rn - rm] */ \ |
1388 | arm_access_memory(store, down, pre, u32, reg); \ |
1389 | break; \ |
1390 | \ |
1391 | case 0x71: \ |
1392 | /* LDR rd, [rn - rm] */ \ |
1393 | arm_access_memory(load, down, pre, u32, reg); \ |
1394 | break; \ |
1395 | \ |
1396 | case 0x72: \ |
1397 | /* STR rd, [rn - rm]! */ \ |
1398 | arm_access_memory(store, down, pre_wb, u32, reg); \ |
1399 | break; \ |
1400 | \ |
1401 | case 0x73: \ |
1402 | /* LDR rd, [rn - rm]! */ \ |
1403 | arm_access_memory(load, down, pre_wb, u32, reg); \ |
1404 | break; \ |
1405 | \ |
1406 | case 0x74: \ |
1407 | /* STRB rd, [rn - rm] */ \ |
1408 | arm_access_memory(store, down, pre, u8, reg); \ |
1409 | break; \ |
1410 | \ |
1411 | case 0x75: \ |
1412 | /* LDRB rd, [rn - rm] */ \ |
1413 | arm_access_memory(load, down, pre, u8, reg); \ |
1414 | break; \ |
1415 | \ |
1416 | case 0x76: \ |
1417 | /* STRB rd, [rn - rm]! */ \ |
1418 | arm_access_memory(store, down, pre_wb, u8, reg); \ |
1419 | break; \ |
1420 | \ |
1421 | case 0x77: \ |
1422 | /* LDRB rd, [rn - rm]! */ \ |
1423 | arm_access_memory(load, down, pre_wb, u8, reg); \ |
1424 | break; \ |
1425 | \ |
1426 | case 0x78: \ |
1427 | /* STR rd, [rn + rm] */ \ |
1428 | arm_access_memory(store, up, pre, u32, reg); \ |
1429 | break; \ |
1430 | \ |
1431 | case 0x79: \ |
1432 | /* LDR rd, [rn + rm] */ \ |
1433 | arm_access_memory(load, up, pre, u32, reg); \ |
1434 | break; \ |
1435 | \ |
1436 | case 0x7A: \ |
1437 | /* STR rd, [rn + rm]! */ \ |
1438 | arm_access_memory(store, up, pre_wb, u32, reg); \ |
1439 | break; \ |
1440 | \ |
1441 | case 0x7B: \ |
1442 | /* LDR rd, [rn + rm]! */ \ |
1443 | arm_access_memory(load, up, pre_wb, u32, reg); \ |
1444 | break; \ |
1445 | \ |
1446 | case 0x7C: \ |
1447 | /* STRB rd, [rn + rm] */ \ |
1448 | arm_access_memory(store, up, pre, u8, reg); \ |
1449 | break; \ |
1450 | \ |
1451 | case 0x7D: \ |
1452 | /* LDRB rd, [rn + rm] */ \ |
1453 | arm_access_memory(load, up, pre, u8, reg); \ |
1454 | break; \ |
1455 | \ |
1456 | case 0x7E: \ |
1457 | /* STRB rd, [rn + rm]! */ \ |
1458 | arm_access_memory(store, up, pre_wb, u8, reg); \ |
1459 | break; \ |
1460 | \ |
1461 | case 0x7F: \ |
1462 | /* LDRBT rd, [rn + rm]! */ \ |
1463 | arm_access_memory(load, up, pre_wb, u8, reg); \ |
1464 | break; \ |
1465 | \ |
1466 | case 0x80: \ |
1467 | /* STMDA rn, rlist */ \ |
1468 | arm_block_memory(store, down_a, no, no); \ |
1469 | break; \ |
1470 | \ |
1471 | case 0x81: \ |
1472 | /* LDMDA rn, rlist */ \ |
1473 | arm_block_memory(load, down_a, no, no); \ |
1474 | break; \ |
1475 | \ |
1476 | case 0x82: \ |
1477 | /* STMDA rn!, rlist */ \ |
1478 | arm_block_memory(store, down_a, down, no); \ |
1479 | break; \ |
1480 | \ |
1481 | case 0x83: \ |
1482 | /* LDMDA rn!, rlist */ \ |
1483 | arm_block_memory(load, down_a, down, no); \ |
1484 | break; \ |
1485 | \ |
1486 | case 0x84: \ |
1487 | /* STMDA rn, rlist^ */ \ |
1488 | arm_block_memory(store, down_a, no, yes); \ |
1489 | break; \ |
1490 | \ |
1491 | case 0x85: \ |
1492 | /* LDMDA rn, rlist^ */ \ |
1493 | arm_block_memory(load, down_a, no, yes); \ |
1494 | break; \ |
1495 | \ |
1496 | case 0x86: \ |
1497 | /* STMDA rn!, rlist^ */ \ |
1498 | arm_block_memory(store, down_a, down, yes); \ |
1499 | break; \ |
1500 | \ |
1501 | case 0x87: \ |
1502 | /* LDMDA rn!, rlist^ */ \ |
1503 | arm_block_memory(load, down_a, down, yes); \ |
1504 | break; \ |
1505 | \ |
1506 | case 0x88: \ |
1507 | /* STMIA rn, rlist */ \ |
1508 | arm_block_memory(store, no, no, no); \ |
1509 | break; \ |
1510 | \ |
1511 | case 0x89: \ |
1512 | /* LDMIA rn, rlist */ \ |
1513 | arm_block_memory(load, no, no, no); \ |
1514 | break; \ |
1515 | \ |
1516 | case 0x8A: \ |
1517 | /* STMIA rn!, rlist */ \ |
1518 | arm_block_memory(store, no, up, no); \ |
1519 | break; \ |
1520 | \ |
1521 | case 0x8B: \ |
1522 | /* LDMIA rn!, rlist */ \ |
1523 | arm_block_memory(load, no, up, no); \ |
1524 | break; \ |
1525 | \ |
1526 | case 0x8C: \ |
1527 | /* STMIA rn, rlist^ */ \ |
1528 | arm_block_memory(store, no, no, yes); \ |
1529 | break; \ |
1530 | \ |
1531 | case 0x8D: \ |
1532 | /* LDMIA rn, rlist^ */ \ |
1533 | arm_block_memory(load, no, no, yes); \ |
1534 | break; \ |
1535 | \ |
1536 | case 0x8E: \ |
1537 | /* STMIA rn!, rlist^ */ \ |
1538 | arm_block_memory(store, no, up, yes); \ |
1539 | break; \ |
1540 | \ |
1541 | case 0x8F: \ |
1542 | /* LDMIA rn!, rlist^ */ \ |
1543 | arm_block_memory(load, no, up, yes); \ |
1544 | break; \ |
1545 | \ |
1546 | case 0x90: \ |
1547 | /* STMDB rn, rlist */ \ |
1548 | arm_block_memory(store, down_b, no, no); \ |
1549 | break; \ |
1550 | \ |
1551 | case 0x91: \ |
1552 | /* LDMDB rn, rlist */ \ |
1553 | arm_block_memory(load, down_b, no, no); \ |
1554 | break; \ |
1555 | \ |
1556 | case 0x92: \ |
1557 | /* STMDB rn!, rlist */ \ |
1558 | arm_block_memory(store, down_b, down, no); \ |
1559 | break; \ |
1560 | \ |
1561 | case 0x93: \ |
1562 | /* LDMDB rn!, rlist */ \ |
1563 | arm_block_memory(load, down_b, down, no); \ |
1564 | break; \ |
1565 | \ |
1566 | case 0x94: \ |
1567 | /* STMDB rn, rlist^ */ \ |
1568 | arm_block_memory(store, down_b, no, yes); \ |
1569 | break; \ |
1570 | \ |
1571 | case 0x95: \ |
1572 | /* LDMDB rn, rlist^ */ \ |
1573 | arm_block_memory(load, down_b, no, yes); \ |
1574 | break; \ |
1575 | \ |
1576 | case 0x96: \ |
1577 | /* STMDB rn!, rlist^ */ \ |
1578 | arm_block_memory(store, down_b, down, yes); \ |
1579 | break; \ |
1580 | \ |
1581 | case 0x97: \ |
1582 | /* LDMDB rn!, rlist^ */ \ |
1583 | arm_block_memory(load, down_b, down, yes); \ |
1584 | break; \ |
1585 | \ |
1586 | case 0x98: \ |
1587 | /* STMIB rn, rlist */ \ |
1588 | arm_block_memory(store, up, no, no); \ |
1589 | break; \ |
1590 | \ |
1591 | case 0x99: \ |
1592 | /* LDMIB rn, rlist */ \ |
1593 | arm_block_memory(load, up, no, no); \ |
1594 | break; \ |
1595 | \ |
1596 | case 0x9A: \ |
1597 | /* STMIB rn!, rlist */ \ |
1598 | arm_block_memory(store, up, up, no); \ |
1599 | break; \ |
1600 | \ |
1601 | case 0x9B: \ |
1602 | /* LDMIB rn!, rlist */ \ |
1603 | arm_block_memory(load, up, up, no); \ |
1604 | break; \ |
1605 | \ |
1606 | case 0x9C: \ |
1607 | /* STMIB rn, rlist^ */ \ |
1608 | arm_block_memory(store, up, no, yes); \ |
1609 | break; \ |
1610 | \ |
1611 | case 0x9D: \ |
1612 | /* LDMIB rn, rlist^ */ \ |
1613 | arm_block_memory(load, up, no, yes); \ |
1614 | break; \ |
1615 | \ |
1616 | case 0x9E: \ |
1617 | /* STMIB rn!, rlist^ */ \ |
1618 | arm_block_memory(store, up, up, yes); \ |
1619 | break; \ |
1620 | \ |
1621 | case 0x9F: \ |
1622 | /* LDMIB rn!, rlist^ */ \ |
1623 | arm_block_memory(load, up, up, yes); \ |
1624 | break; \ |
1625 | \ |
1626 | case 0xA0 ... 0xAF: \ |
1627 | { \ |
1628 | /* B offset */ \ |
1629 | arm_b(); \ |
1630 | break; \ |
1631 | } \ |
1632 | \ |
1633 | case 0xB0 ... 0xBF: \ |
1634 | { \ |
1635 | /* BL offset */ \ |
1636 | arm_bl(); \ |
1637 | break; \ |
1638 | } \ |
1639 | \ |
1640 | case 0xC0 ... 0xEF: \ |
1641 | /* coprocessor instructions, reserved on GBA */ \ |
1642 | break; \ |
1643 | \ |
1644 | case 0xF0 ... 0xFF: \ |
1645 | { \ |
1646 | /* SWI comment */ \ |
1647 | arm_swi(); \ |
1648 | break; \ |
1649 | } \ |
1650 | } \ |
1651 | \ |
1652 | pc += 4 \ |
1653 | |
1654 | #define arm_flag_status() \ |
1655 | |
1656 | #define translate_thumb_instruction() \ |
1657 | flag_status = block_data[block_data_position].flag_data; \ |
1658 | check_pc_region(pc); \ |
1659 | last_opcode = opcode; \ |
1660 | opcode = address16(pc_address_block, (pc & 0x7FFF)); \ |
1661 | \ |
1662 | switch((opcode >> 8) & 0xFF) \ |
1663 | { \ |
1664 | case 0x00 ... 0x07: \ |
1665 | /* LSL rd, rs, imm */ \ |
1666 | thumb_shift(shift, lsl, imm); \ |
1667 | break; \ |
1668 | \ |
1669 | case 0x08 ... 0x0F: \ |
1670 | /* LSR rd, rs, imm */ \ |
1671 | thumb_shift(shift, lsr, imm); \ |
1672 | break; \ |
1673 | \ |
1674 | case 0x10 ... 0x17: \ |
1675 | /* ASR rd, rs, imm */ \ |
1676 | thumb_shift(shift, asr, imm); \ |
1677 | break; \ |
1678 | \ |
1679 | case 0x18 ... 0x19: \ |
1680 | /* ADD rd, rs, rn */ \ |
1681 | thumb_data_proc(add_sub, adds, reg, rd, rs, rn); \ |
1682 | break; \ |
1683 | \ |
1684 | case 0x1A ... 0x1B: \ |
1685 | /* SUB rd, rs, rn */ \ |
1686 | thumb_data_proc(add_sub, subs, reg, rd, rs, rn); \ |
1687 | break; \ |
1688 | \ |
1689 | case 0x1C ... 0x1D: \ |
1690 | /* ADD rd, rs, imm */ \ |
1691 | thumb_data_proc(add_sub_imm, adds, imm, rd, rs, imm); \ |
1692 | break; \ |
1693 | \ |
1694 | case 0x1E ... 0x1F: \ |
1695 | /* SUB rd, rs, imm */ \ |
1696 | thumb_data_proc(add_sub_imm, subs, imm, rd, rs, imm); \ |
1697 | break; \ |
1698 | \ |
1699 | case 0x20: \ |
1700 | /* MOV r0, imm */ \ |
1701 | thumb_data_proc_unary(imm, movs, imm, 0, imm); \ |
1702 | break; \ |
1703 | \ |
1704 | case 0x21: \ |
1705 | /* MOV r1, imm */ \ |
1706 | thumb_data_proc_unary(imm, movs, imm, 1, imm); \ |
1707 | break; \ |
1708 | \ |
1709 | case 0x22: \ |
1710 | /* MOV r2, imm */ \ |
1711 | thumb_data_proc_unary(imm, movs, imm, 2, imm); \ |
1712 | break; \ |
1713 | \ |
1714 | case 0x23: \ |
1715 | /* MOV r3, imm */ \ |
1716 | thumb_data_proc_unary(imm, movs, imm, 3, imm); \ |
1717 | break; \ |
1718 | \ |
1719 | case 0x24: \ |
1720 | /* MOV r4, imm */ \ |
1721 | thumb_data_proc_unary(imm, movs, imm, 4, imm); \ |
1722 | break; \ |
1723 | \ |
1724 | case 0x25: \ |
1725 | /* MOV r5, imm */ \ |
1726 | thumb_data_proc_unary(imm, movs, imm, 5, imm); \ |
1727 | break; \ |
1728 | \ |
1729 | case 0x26: \ |
1730 | /* MOV r6, imm */ \ |
1731 | thumb_data_proc_unary(imm, movs, imm, 6, imm); \ |
1732 | break; \ |
1733 | \ |
1734 | case 0x27: \ |
1735 | /* MOV r7, imm */ \ |
1736 | thumb_data_proc_unary(imm, movs, imm, 7, imm); \ |
1737 | break; \ |
1738 | \ |
1739 | case 0x28: \ |
1740 | /* CMP r0, imm */ \ |
1741 | thumb_data_proc_test(imm, cmp, imm, 0, imm); \ |
1742 | break; \ |
1743 | \ |
1744 | case 0x29: \ |
1745 | /* CMP r1, imm */ \ |
1746 | thumb_data_proc_test(imm, cmp, imm, 1, imm); \ |
1747 | break; \ |
1748 | \ |
1749 | case 0x2A: \ |
1750 | /* CMP r2, imm */ \ |
1751 | thumb_data_proc_test(imm, cmp, imm, 2, imm); \ |
1752 | break; \ |
1753 | \ |
1754 | case 0x2B: \ |
1755 | /* CMP r3, imm */ \ |
1756 | thumb_data_proc_test(imm, cmp, imm, 3, imm); \ |
1757 | break; \ |
1758 | \ |
1759 | case 0x2C: \ |
1760 | /* CMP r4, imm */ \ |
1761 | thumb_data_proc_test(imm, cmp, imm, 4, imm); \ |
1762 | break; \ |
1763 | \ |
1764 | case 0x2D: \ |
1765 | /* CMP r5, imm */ \ |
1766 | thumb_data_proc_test(imm, cmp, imm, 5, imm); \ |
1767 | break; \ |
1768 | \ |
1769 | case 0x2E: \ |
1770 | /* CMP r6, imm */ \ |
1771 | thumb_data_proc_test(imm, cmp, imm, 6, imm); \ |
1772 | break; \ |
1773 | \ |
1774 | case 0x2F: \ |
1775 | /* CMP r7, imm */ \ |
1776 | thumb_data_proc_test(imm, cmp, imm, 7, imm); \ |
1777 | break; \ |
1778 | \ |
1779 | case 0x30: \ |
1780 | /* ADD r0, imm */ \ |
1781 | thumb_data_proc(imm, adds, imm, 0, 0, imm); \ |
1782 | break; \ |
1783 | \ |
1784 | case 0x31: \ |
1785 | /* ADD r1, imm */ \ |
1786 | thumb_data_proc(imm, adds, imm, 1, 1, imm); \ |
1787 | break; \ |
1788 | \ |
1789 | case 0x32: \ |
1790 | /* ADD r2, imm */ \ |
1791 | thumb_data_proc(imm, adds, imm, 2, 2, imm); \ |
1792 | break; \ |
1793 | \ |
1794 | case 0x33: \ |
1795 | /* ADD r3, imm */ \ |
1796 | thumb_data_proc(imm, adds, imm, 3, 3, imm); \ |
1797 | break; \ |
1798 | \ |
1799 | case 0x34: \ |
1800 | /* ADD r4, imm */ \ |
1801 | thumb_data_proc(imm, adds, imm, 4, 4, imm); \ |
1802 | break; \ |
1803 | \ |
1804 | case 0x35: \ |
1805 | /* ADD r5, imm */ \ |
1806 | thumb_data_proc(imm, adds, imm, 5, 5, imm); \ |
1807 | break; \ |
1808 | \ |
1809 | case 0x36: \ |
1810 | /* ADD r6, imm */ \ |
1811 | thumb_data_proc(imm, adds, imm, 6, 6, imm); \ |
1812 | break; \ |
1813 | \ |
1814 | case 0x37: \ |
1815 | /* ADD r7, imm */ \ |
1816 | thumb_data_proc(imm, adds, imm, 7, 7, imm); \ |
1817 | break; \ |
1818 | \ |
1819 | case 0x38: \ |
1820 | /* SUB r0, imm */ \ |
1821 | thumb_data_proc(imm, subs, imm, 0, 0, imm); \ |
1822 | break; \ |
1823 | \ |
1824 | case 0x39: \ |
1825 | /* SUB r1, imm */ \ |
1826 | thumb_data_proc(imm, subs, imm, 1, 1, imm); \ |
1827 | break; \ |
1828 | \ |
1829 | case 0x3A: \ |
1830 | /* SUB r2, imm */ \ |
1831 | thumb_data_proc(imm, subs, imm, 2, 2, imm); \ |
1832 | break; \ |
1833 | \ |
1834 | case 0x3B: \ |
1835 | /* SUB r3, imm */ \ |
1836 | thumb_data_proc(imm, subs, imm, 3, 3, imm); \ |
1837 | break; \ |
1838 | \ |
1839 | case 0x3C: \ |
1840 | /* SUB r4, imm */ \ |
1841 | thumb_data_proc(imm, subs, imm, 4, 4, imm); \ |
1842 | break; \ |
1843 | \ |
1844 | case 0x3D: \ |
1845 | /* SUB r5, imm */ \ |
1846 | thumb_data_proc(imm, subs, imm, 5, 5, imm); \ |
1847 | break; \ |
1848 | \ |
1849 | case 0x3E: \ |
1850 | /* SUB r6, imm */ \ |
1851 | thumb_data_proc(imm, subs, imm, 6, 6, imm); \ |
1852 | break; \ |
1853 | \ |
1854 | case 0x3F: \ |
1855 | /* SUB r7, imm */ \ |
1856 | thumb_data_proc(imm, subs, imm, 7, 7, imm); \ |
1857 | break; \ |
1858 | \ |
1859 | case 0x40: \ |
1860 | switch((opcode >> 6) & 0x03) \ |
1861 | { \ |
1862 | case 0x00: \ |
1863 | /* AND rd, rs */ \ |
1864 | thumb_data_proc(alu_op, ands, reg, rd, rd, rs); \ |
1865 | break; \ |
1866 | \ |
1867 | case 0x01: \ |
1868 | /* EOR rd, rs */ \ |
1869 | thumb_data_proc(alu_op, eors, reg, rd, rd, rs); \ |
1870 | break; \ |
1871 | \ |
1872 | case 0x02: \ |
1873 | /* LSL rd, rs */ \ |
1874 | thumb_shift(alu_op, lsl, reg); \ |
1875 | break; \ |
1876 | \ |
1877 | case 0x03: \ |
1878 | /* LSR rd, rs */ \ |
1879 | thumb_shift(alu_op, lsr, reg); \ |
1880 | break; \ |
1881 | } \ |
1882 | break; \ |
1883 | \ |
1884 | case 0x41: \ |
1885 | switch((opcode >> 6) & 0x03) \ |
1886 | { \ |
1887 | case 0x00: \ |
1888 | /* ASR rd, rs */ \ |
1889 | thumb_shift(alu_op, asr, reg); \ |
1890 | break; \ |
1891 | \ |
1892 | case 0x01: \ |
1893 | /* ADC rd, rs */ \ |
1894 | thumb_data_proc(alu_op, adcs, reg, rd, rd, rs); \ |
1895 | break; \ |
1896 | \ |
1897 | case 0x02: \ |
1898 | /* SBC rd, rs */ \ |
1899 | thumb_data_proc(alu_op, sbcs, reg, rd, rd, rs); \ |
1900 | break; \ |
1901 | \ |
1902 | case 0x03: \ |
1903 | /* ROR rd, rs */ \ |
1904 | thumb_shift(alu_op, ror, reg); \ |
1905 | break; \ |
1906 | } \ |
1907 | break; \ |
1908 | \ |
1909 | case 0x42: \ |
1910 | switch((opcode >> 6) & 0x03) \ |
1911 | { \ |
1912 | case 0x00: \ |
1913 | /* TST rd, rs */ \ |
1914 | thumb_data_proc_test(alu_op, tst, reg, rd, rs); \ |
1915 | break; \ |
1916 | \ |
1917 | case 0x01: \ |
1918 | /* NEG rd, rs */ \ |
1919 | thumb_data_proc_unary(alu_op, neg, reg, rd, rs); \ |
1920 | break; \ |
1921 | \ |
1922 | case 0x02: \ |
1923 | /* CMP rd, rs */ \ |
1924 | thumb_data_proc_test(alu_op, cmp, reg, rd, rs); \ |
1925 | break; \ |
1926 | \ |
1927 | case 0x03: \ |
1928 | /* CMN rd, rs */ \ |
1929 | thumb_data_proc_test(alu_op, cmn, reg, rd, rs); \ |
1930 | break; \ |
1931 | } \ |
1932 | break; \ |
1933 | \ |
1934 | case 0x43: \ |
1935 | switch((opcode >> 6) & 0x03) \ |
1936 | { \ |
1937 | case 0x00: \ |
1938 | /* ORR rd, rs */ \ |
1939 | thumb_data_proc(alu_op, orrs, reg, rd, rd, rs); \ |
1940 | break; \ |
1941 | \ |
1942 | case 0x01: \ |
1943 | /* MUL rd, rs */ \ |
1944 | thumb_data_proc(alu_op, muls, reg, rd, rd, rs); \ |
1945 | break; \ |
1946 | \ |
1947 | case 0x02: \ |
1948 | /* BIC rd, rs */ \ |
1949 | thumb_data_proc(alu_op, bics, reg, rd, rd, rs); \ |
1950 | break; \ |
1951 | \ |
1952 | case 0x03: \ |
1953 | /* MVN rd, rs */ \ |
1954 | thumb_data_proc_unary(alu_op, mvns, reg, rd, rs); \ |
1955 | break; \ |
1956 | } \ |
1957 | break; \ |
1958 | \ |
1959 | case 0x44: \ |
1960 | /* ADD rd, rs */ \ |
1961 | thumb_data_proc_hi(add); \ |
1962 | break; \ |
1963 | \ |
1964 | case 0x45: \ |
1965 | /* CMP rd, rs */ \ |
1966 | thumb_data_proc_test_hi(cmp); \ |
1967 | break; \ |
1968 | \ |
1969 | case 0x46: \ |
1970 | /* MOV rd, rs */ \ |
1971 | thumb_data_proc_mov_hi(); \ |
1972 | break; \ |
1973 | \ |
1974 | case 0x47: \ |
1975 | /* BX rs */ \ |
1976 | thumb_bx(); \ |
1977 | break; \ |
1978 | \ |
1979 | case 0x48: \ |
1980 | /* LDR r0, [pc + imm] */ \ |
1981 | thumb_access_memory(load, imm, 0, 0, 0, pc_relative, \ |
1982 | (pc & ~2) + (imm * 4) + 4, u32); \ |
1983 | break; \ |
1984 | \ |
1985 | case 0x49: \ |
1986 | /* LDR r1, [pc + imm] */ \ |
1987 | thumb_access_memory(load, imm, 1, 0, 0, pc_relative, \ |
1988 | (pc & ~2) + (imm * 4) + 4, u32); \ |
1989 | break; \ |
1990 | \ |
1991 | case 0x4A: \ |
1992 | /* LDR r2, [pc + imm] */ \ |
1993 | thumb_access_memory(load, imm, 2, 0, 0, pc_relative, \ |
1994 | (pc & ~2) + (imm * 4) + 4, u32); \ |
1995 | break; \ |
1996 | \ |
1997 | case 0x4B: \ |
1998 | /* LDR r3, [pc + imm] */ \ |
1999 | thumb_access_memory(load, imm, 3, 0, 0, pc_relative, \ |
2000 | (pc & ~2) + (imm * 4) + 4, u32); \ |
2001 | break; \ |
2002 | \ |
2003 | case 0x4C: \ |
2004 | /* LDR r4, [pc + imm] */ \ |
2005 | thumb_access_memory(load, imm, 4, 0, 0, pc_relative, \ |
2006 | (pc & ~2) + (imm * 4) + 4, u32); \ |
2007 | break; \ |
2008 | \ |
2009 | case 0x4D: \ |
2010 | /* LDR r5, [pc + imm] */ \ |
2011 | thumb_access_memory(load, imm, 5, 0, 0, pc_relative, \ |
2012 | (pc & ~2) + (imm * 4) + 4, u32); \ |
2013 | break; \ |
2014 | \ |
2015 | case 0x4E: \ |
2016 | /* LDR r6, [pc + imm] */ \ |
2017 | thumb_access_memory(load, imm, 6, 0, 0, pc_relative, \ |
2018 | (pc & ~2) + (imm * 4) + 4, u32); \ |
2019 | break; \ |
2020 | \ |
2021 | case 0x4F: \ |
2022 | /* LDR r7, [pc + imm] */ \ |
2023 | thumb_access_memory(load, imm, 7, 0, 0, pc_relative, \ |
2024 | (pc & ~2) + (imm * 4) + 4, u32); \ |
2025 | break; \ |
2026 | \ |
2027 | case 0x50 ... 0x51: \ |
2028 | /* STR rd, [rb + ro] */ \ |
2029 | thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u32); \ |
2030 | break; \ |
2031 | \ |
2032 | case 0x52 ... 0x53: \ |
2033 | /* STRH rd, [rb + ro] */ \ |
2034 | thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u16); \ |
2035 | break; \ |
2036 | \ |
2037 | case 0x54 ... 0x55: \ |
2038 | /* STRB rd, [rb + ro] */ \ |
2039 | thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u8); \ |
2040 | break; \ |
2041 | \ |
2042 | case 0x56 ... 0x57: \ |
2043 | /* LDSB rd, [rb + ro] */ \ |
2044 | thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s8); \ |
2045 | break; \ |
2046 | \ |
2047 | case 0x58 ... 0x59: \ |
2048 | /* LDR rd, [rb + ro] */ \ |
2049 | thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u32); \ |
2050 | break; \ |
2051 | \ |
2052 | case 0x5A ... 0x5B: \ |
2053 | /* LDRH rd, [rb + ro] */ \ |
2054 | thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u16); \ |
2055 | break; \ |
2056 | \ |
2057 | case 0x5C ... 0x5D: \ |
2058 | /* LDRB rd, [rb + ro] */ \ |
2059 | thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u8); \ |
2060 | break; \ |
2061 | \ |
2062 | case 0x5E ... 0x5F: \ |
2063 | /* LDSH rd, [rb + ro] */ \ |
2064 | thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s16); \ |
2065 | break; \ |
2066 | \ |
2067 | case 0x60 ... 0x67: \ |
2068 | /* STR rd, [rb + imm] */ \ |
2069 | thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, (imm * 4), \ |
2070 | u32); \ |
2071 | break; \ |
2072 | \ |
2073 | case 0x68 ... 0x6F: \ |
2074 | /* LDR rd, [rb + imm] */ \ |
2075 | thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 4), u32); \ |
2076 | break; \ |
2077 | \ |
2078 | case 0x70 ... 0x77: \ |
2079 | /* STRB rd, [rb + imm] */ \ |
2080 | thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, imm, u8); \ |
2081 | break; \ |
2082 | \ |
2083 | case 0x78 ... 0x7F: \ |
2084 | /* LDRB rd, [rb + imm] */ \ |
2085 | thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, imm, u8); \ |
2086 | break; \ |
2087 | \ |
2088 | case 0x80 ... 0x87: \ |
2089 | /* STRH rd, [rb + imm] */ \ |
2090 | thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, \ |
2091 | (imm * 2), u16); \ |
2092 | break; \ |
2093 | \ |
2094 | case 0x88 ... 0x8F: \ |
2095 | /* LDRH rd, [rb + imm] */ \ |
2096 | thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \ |
2097 | break; \ |
2098 | \ |
2099 | case 0x90: \ |
2100 | /* STR r0, [sp + imm] */ \ |
2101 | thumb_access_memory(store, imm, 0, 13, 0, reg_imm_sp, imm, u32); \ |
2102 | break; \ |
2103 | \ |
2104 | case 0x91: \ |
2105 | /* STR r1, [sp + imm] */ \ |
2106 | thumb_access_memory(store, imm, 1, 13, 0, reg_imm_sp, imm, u32); \ |
2107 | break; \ |
2108 | \ |
2109 | case 0x92: \ |
2110 | /* STR r2, [sp + imm] */ \ |
2111 | thumb_access_memory(store, imm, 2, 13, 0, reg_imm_sp, imm, u32); \ |
2112 | break; \ |
2113 | \ |
2114 | case 0x93: \ |
2115 | /* STR r3, [sp + imm] */ \ |
2116 | thumb_access_memory(store, imm, 3, 13, 0, reg_imm_sp, imm, u32); \ |
2117 | break; \ |
2118 | \ |
2119 | case 0x94: \ |
2120 | /* STR r4, [sp + imm] */ \ |
2121 | thumb_access_memory(store, imm, 4, 13, 0, reg_imm_sp, imm, u32); \ |
2122 | break; \ |
2123 | \ |
2124 | case 0x95: \ |
2125 | /* STR r5, [sp + imm] */ \ |
2126 | thumb_access_memory(store, imm, 5, 13, 0, reg_imm_sp, imm, u32); \ |
2127 | break; \ |
2128 | \ |
2129 | case 0x96: \ |
2130 | /* STR r6, [sp + imm] */ \ |
2131 | thumb_access_memory(store, imm, 6, 13, 0, reg_imm_sp, imm, u32); \ |
2132 | break; \ |
2133 | \ |
2134 | case 0x97: \ |
2135 | /* STR r7, [sp + imm] */ \ |
2136 | thumb_access_memory(store, imm, 7, 13, 0, reg_imm_sp, imm, u32); \ |
2137 | break; \ |
2138 | \ |
2139 | case 0x98: \ |
2140 | /* LDR r0, [sp + imm] */ \ |
2141 | thumb_access_memory(load, imm, 0, 13, 0, reg_imm_sp, imm, u32); \ |
2142 | break; \ |
2143 | \ |
2144 | case 0x99: \ |
2145 | /* LDR r1, [sp + imm] */ \ |
2146 | thumb_access_memory(load, imm, 1, 13, 0, reg_imm_sp, imm, u32); \ |
2147 | break; \ |
2148 | \ |
2149 | case 0x9A: \ |
2150 | /* LDR r2, [sp + imm] */ \ |
2151 | thumb_access_memory(load, imm, 2, 13, 0, reg_imm_sp, imm, u32); \ |
2152 | break; \ |
2153 | \ |
2154 | case 0x9B: \ |
2155 | /* LDR r3, [sp + imm] */ \ |
2156 | thumb_access_memory(load, imm, 3, 13, 0, reg_imm_sp, imm, u32); \ |
2157 | break; \ |
2158 | \ |
2159 | case 0x9C: \ |
2160 | /* LDR r4, [sp + imm] */ \ |
2161 | thumb_access_memory(load, imm, 4, 13, 0, reg_imm_sp, imm, u32); \ |
2162 | break; \ |
2163 | \ |
2164 | case 0x9D: \ |
2165 | /* LDR r5, [sp + imm] */ \ |
2166 | thumb_access_memory(load, imm, 5, 13, 0, reg_imm_sp, imm, u32); \ |
2167 | break; \ |
2168 | \ |
2169 | case 0x9E: \ |
2170 | /* LDR r6, [sp + imm] */ \ |
2171 | thumb_access_memory(load, imm, 6, 13, 0, reg_imm_sp, imm, u32); \ |
2172 | break; \ |
2173 | \ |
2174 | case 0x9F: \ |
2175 | /* LDR r7, [sp + imm] */ \ |
2176 | thumb_access_memory(load, imm, 7, 13, 0, reg_imm_sp, imm, u32); \ |
2177 | break; \ |
2178 | \ |
2179 | case 0xA0: \ |
2180 | /* ADD r0, pc, +imm */ \ |
2181 | thumb_load_pc(0); \ |
2182 | break; \ |
2183 | \ |
2184 | case 0xA1: \ |
2185 | /* ADD r1, pc, +imm */ \ |
2186 | thumb_load_pc(1); \ |
2187 | break; \ |
2188 | \ |
2189 | case 0xA2: \ |
2190 | /* ADD r2, pc, +imm */ \ |
2191 | thumb_load_pc(2); \ |
2192 | break; \ |
2193 | \ |
2194 | case 0xA3: \ |
2195 | /* ADD r3, pc, +imm */ \ |
2196 | thumb_load_pc(3); \ |
2197 | break; \ |
2198 | \ |
2199 | case 0xA4: \ |
2200 | /* ADD r4, pc, +imm */ \ |
2201 | thumb_load_pc(4); \ |
2202 | break; \ |
2203 | \ |
2204 | case 0xA5: \ |
2205 | /* ADD r5, pc, +imm */ \ |
2206 | thumb_load_pc(5); \ |
2207 | break; \ |
2208 | \ |
2209 | case 0xA6: \ |
2210 | /* ADD r6, pc, +imm */ \ |
2211 | thumb_load_pc(6); \ |
2212 | break; \ |
2213 | \ |
2214 | case 0xA7: \ |
2215 | /* ADD r7, pc, +imm */ \ |
2216 | thumb_load_pc(7); \ |
2217 | break; \ |
2218 | \ |
2219 | case 0xA8: \ |
2220 | /* ADD r0, sp, +imm */ \ |
2221 | thumb_load_sp(0); \ |
2222 | break; \ |
2223 | \ |
2224 | case 0xA9: \ |
2225 | /* ADD r1, sp, +imm */ \ |
2226 | thumb_load_sp(1); \ |
2227 | break; \ |
2228 | \ |
2229 | case 0xAA: \ |
2230 | /* ADD r2, sp, +imm */ \ |
2231 | thumb_load_sp(2); \ |
2232 | break; \ |
2233 | \ |
2234 | case 0xAB: \ |
2235 | /* ADD r3, sp, +imm */ \ |
2236 | thumb_load_sp(3); \ |
2237 | break; \ |
2238 | \ |
2239 | case 0xAC: \ |
2240 | /* ADD r4, sp, +imm */ \ |
2241 | thumb_load_sp(4); \ |
2242 | break; \ |
2243 | \ |
2244 | case 0xAD: \ |
2245 | /* ADD r5, sp, +imm */ \ |
2246 | thumb_load_sp(5); \ |
2247 | break; \ |
2248 | \ |
2249 | case 0xAE: \ |
2250 | /* ADD r6, sp, +imm */ \ |
2251 | thumb_load_sp(6); \ |
2252 | break; \ |
2253 | \ |
2254 | case 0xAF: \ |
2255 | /* ADD r7, sp, +imm */ \ |
2256 | thumb_load_sp(7); \ |
2257 | break; \ |
2258 | \ |
2259 | case 0xB0 ... 0xB3: \ |
2260 | if((opcode >> 7) & 0x01) \ |
2261 | { \ |
2262 | /* ADD sp, -imm */ \ |
2263 | thumb_adjust_sp(down); \ |
2264 | } \ |
2265 | else \ |
2266 | { \ |
2267 | /* ADD sp, +imm */ \ |
2268 | thumb_adjust_sp(up); \ |
2269 | } \ |
2270 | break; \ |
2271 | \ |
2272 | case 0xB4: \ |
2273 | /* PUSH rlist */ \ |
2274 | thumb_block_memory(store, down, no, 13); \ |
2275 | break; \ |
2276 | \ |
2277 | case 0xB5: \ |
2278 | /* PUSH rlist, lr */ \ |
2279 | thumb_block_memory(store, push_lr, push_lr, 13); \ |
2280 | break; \ |
2281 | \ |
2282 | case 0xBC: \ |
2283 | /* POP rlist */ \ |
2284 | thumb_block_memory(load, no, up, 13); \ |
2285 | break; \ |
2286 | \ |
2287 | case 0xBD: \ |
2288 | /* POP rlist, pc */ \ |
2289 | thumb_block_memory(load, no, pop_pc, 13); \ |
2290 | break; \ |
2291 | \ |
2292 | case 0xC0: \ |
2293 | /* STMIA r0!, rlist */ \ |
2294 | thumb_block_memory(store, no, up, 0); \ |
2295 | break; \ |
2296 | \ |
2297 | case 0xC1: \ |
2298 | /* STMIA r1!, rlist */ \ |
2299 | thumb_block_memory(store, no, up, 1); \ |
2300 | break; \ |
2301 | \ |
2302 | case 0xC2: \ |
2303 | /* STMIA r2!, rlist */ \ |
2304 | thumb_block_memory(store, no, up, 2); \ |
2305 | break; \ |
2306 | \ |
2307 | case 0xC3: \ |
2308 | /* STMIA r3!, rlist */ \ |
2309 | thumb_block_memory(store, no, up, 3); \ |
2310 | break; \ |
2311 | \ |
2312 | case 0xC4: \ |
2313 | /* STMIA r4!, rlist */ \ |
2314 | thumb_block_memory(store, no, up, 4); \ |
2315 | break; \ |
2316 | \ |
2317 | case 0xC5: \ |
2318 | /* STMIA r5!, rlist */ \ |
2319 | thumb_block_memory(store, no, up, 5); \ |
2320 | break; \ |
2321 | \ |
2322 | case 0xC6: \ |
2323 | /* STMIA r6!, rlist */ \ |
2324 | thumb_block_memory(store, no, up, 6); \ |
2325 | break; \ |
2326 | \ |
2327 | case 0xC7: \ |
2328 | /* STMIA r7!, rlist */ \ |
2329 | thumb_block_memory(store, no, up, 7); \ |
2330 | break; \ |
2331 | \ |
2332 | case 0xC8: \ |
2333 | /* LDMIA r0!, rlist */ \ |
2334 | thumb_block_memory(load, no, up, 0); \ |
2335 | break; \ |
2336 | \ |
2337 | case 0xC9: \ |
2338 | /* LDMIA r1!, rlist */ \ |
2339 | thumb_block_memory(load, no, up, 1); \ |
2340 | break; \ |
2341 | \ |
2342 | case 0xCA: \ |
2343 | /* LDMIA r2!, rlist */ \ |
2344 | thumb_block_memory(load, no, up, 2); \ |
2345 | break; \ |
2346 | \ |
2347 | case 0xCB: \ |
2348 | /* LDMIA r3!, rlist */ \ |
2349 | thumb_block_memory(load, no, up, 3); \ |
2350 | break; \ |
2351 | \ |
2352 | case 0xCC: \ |
2353 | /* LDMIA r4!, rlist */ \ |
2354 | thumb_block_memory(load, no, up, 4); \ |
2355 | break; \ |
2356 | \ |
2357 | case 0xCD: \ |
2358 | /* LDMIA r5!, rlist */ \ |
2359 | thumb_block_memory(load, no, up, 5); \ |
2360 | break; \ |
2361 | \ |
2362 | case 0xCE: \ |
2363 | /* LDMIA r6!, rlist */ \ |
2364 | thumb_block_memory(load, no, up, 6); \ |
2365 | break; \ |
2366 | \ |
2367 | case 0xCF: \ |
2368 | /* LDMIA r7!, rlist */ \ |
2369 | thumb_block_memory(load, no, up, 7); \ |
2370 | break; \ |
2371 | \ |
2372 | case 0xD0: \ |
2373 | /* BEQ label */ \ |
2374 | thumb_conditional_branch(eq); \ |
2375 | break; \ |
2376 | \ |
2377 | case 0xD1: \ |
2378 | /* BNE label */ \ |
2379 | thumb_conditional_branch(ne); \ |
2380 | break; \ |
2381 | \ |
2382 | case 0xD2: \ |
2383 | /* BCS label */ \ |
2384 | thumb_conditional_branch(cs); \ |
2385 | break; \ |
2386 | \ |
2387 | case 0xD3: \ |
2388 | /* BCC label */ \ |
2389 | thumb_conditional_branch(cc); \ |
2390 | break; \ |
2391 | \ |
2392 | case 0xD4: \ |
2393 | /* BMI label */ \ |
2394 | thumb_conditional_branch(mi); \ |
2395 | break; \ |
2396 | \ |
2397 | case 0xD5: \ |
2398 | /* BPL label */ \ |
2399 | thumb_conditional_branch(pl); \ |
2400 | break; \ |
2401 | \ |
2402 | case 0xD6: \ |
2403 | /* BVS label */ \ |
2404 | thumb_conditional_branch(vs); \ |
2405 | break; \ |
2406 | \ |
2407 | case 0xD7: \ |
2408 | /* BVC label */ \ |
2409 | thumb_conditional_branch(vc); \ |
2410 | break; \ |
2411 | \ |
2412 | case 0xD8: \ |
2413 | /* BHI label */ \ |
2414 | thumb_conditional_branch(hi); \ |
2415 | break; \ |
2416 | \ |
2417 | case 0xD9: \ |
2418 | /* BLS label */ \ |
2419 | thumb_conditional_branch(ls); \ |
2420 | break; \ |
2421 | \ |
2422 | case 0xDA: \ |
2423 | /* BGE label */ \ |
2424 | thumb_conditional_branch(ge); \ |
2425 | break; \ |
2426 | \ |
2427 | case 0xDB: \ |
2428 | /* BLT label */ \ |
2429 | thumb_conditional_branch(lt); \ |
2430 | break; \ |
2431 | \ |
2432 | case 0xDC: \ |
2433 | /* BGT label */ \ |
2434 | thumb_conditional_branch(gt); \ |
2435 | break; \ |
2436 | \ |
2437 | case 0xDD: \ |
2438 | /* BLE label */ \ |
2439 | thumb_conditional_branch(le); \ |
2440 | break; \ |
2441 | \ |
2442 | case 0xDF: \ |
2443 | { \ |
2444 | /* SWI comment */ \ |
2445 | thumb_swi(); \ |
2446 | break; \ |
2447 | } \ |
2448 | \ |
2449 | case 0xE0 ... 0xE7: \ |
2450 | { \ |
2451 | /* B label */ \ |
2452 | thumb_b(); \ |
2453 | break; \ |
2454 | } \ |
2455 | \ |
2456 | case 0xF0 ... 0xF7: \ |
2457 | { \ |
2458 | /* (low word) BL label */ \ |
2459 | /* This should possibly generate code if not in conjunction with a BLH \ |
2460 | next, but I don't think anyone will do that. */ \ |
2461 | break; \ |
2462 | } \ |
2463 | \ |
2464 | case 0xF8 ... 0xFF: \ |
2465 | { \ |
2466 | /* (high word) BL label */ \ |
2467 | /* This might not be preceeding a BL low word (Golden Sun 2), if so \ |
2468 | it must be handled like an indirect branch. */ \ |
2469 | if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \ |
2470 | { \ |
2471 | thumb_bl(); \ |
2472 | } \ |
2473 | else \ |
2474 | { \ |
2475 | thumb_blh(); \ |
2476 | } \ |
2477 | break; \ |
2478 | } \ |
2479 | } \ |
2480 | \ |
2481 | pc += 2 \ |
2482 | |
2483 | #define thumb_flag_modifies_all() \ |
2484 | flag_status |= 0xFF \ |
2485 | |
2486 | #define thumb_flag_modifies_zn() \ |
2487 | flag_status |= 0xCC \ |
2488 | |
2489 | #define thumb_flag_modifies_znc() \ |
2490 | flag_status |= 0xEE \ |
2491 | |
2492 | #define thumb_flag_modifies_zn_maybe_c() \ |
2493 | flag_status |= 0xCE \ |
2494 | |
2495 | #define thumb_flag_modifies_c() \ |
2496 | flag_status |= 0x22 \ |
2497 | |
2498 | #define thumb_flag_requires_c() \ |
2499 | flag_status |= 0x200 \ |
2500 | |
2501 | #define thumb_flag_requires_all() \ |
2502 | flag_status |= 0xF00 \ |
2503 | |
2504 | #define thumb_flag_status() \ |
2505 | { \ |
2506 | u16 flag_status = 0; \ |
2507 | switch((opcode >> 8) & 0xFF) \ |
2508 | { \ |
2509 | /* left shift by imm */ \ |
2510 | case 0x00 ... 0x07: \ |
2511 | thumb_flag_modifies_zn(); \ |
2512 | if(((opcode >> 6) & 0x1F) != 0) \ |
2513 | { \ |
2514 | thumb_flag_modifies_c(); \ |
2515 | } \ |
2516 | break; \ |
2517 | \ |
2518 | /* right shift by imm */ \ |
2519 | case 0x08 ... 0x17: \ |
2520 | thumb_flag_modifies_znc(); \ |
2521 | break; \ |
2522 | \ |
2523 | /* add, subtract */ \ |
2524 | case 0x18 ... 0x1F: \ |
2525 | thumb_flag_modifies_all(); \ |
2526 | break; \ |
2527 | \ |
2528 | /* mov reg, imm */ \ |
2529 | case 0x20 ... 0x27: \ |
2530 | thumb_flag_modifies_zn(); \ |
2531 | break; \ |
2532 | \ |
2533 | /* cmp reg, imm; add, subtract */ \ |
2534 | case 0x28 ... 0x3F: \ |
2535 | thumb_flag_modifies_all(); \ |
2536 | break; \ |
2537 | \ |
2538 | case 0x40: \ |
2539 | switch((opcode >> 6) & 0x03) \ |
2540 | { \ |
2541 | case 0x00: \ |
2542 | /* AND rd, rs */ \ |
2543 | thumb_flag_modifies_zn(); \ |
2544 | break; \ |
2545 | \ |
2546 | case 0x01: \ |
2547 | /* EOR rd, rs */ \ |
2548 | thumb_flag_modifies_zn(); \ |
2549 | break; \ |
2550 | \ |
2551 | case 0x02: \ |
2552 | /* LSL rd, rs */ \ |
2553 | thumb_flag_modifies_zn_maybe_c(); \ |
2554 | break; \ |
2555 | \ |
2556 | case 0x03: \ |
2557 | /* LSR rd, rs */ \ |
2558 | thumb_flag_modifies_zn_maybe_c(); \ |
2559 | break; \ |
2560 | } \ |
2561 | break; \ |
2562 | \ |
2563 | case 0x41: \ |
2564 | switch((opcode >> 6) & 0x03) \ |
2565 | { \ |
2566 | case 0x00: \ |
2567 | /* ASR rd, rs */ \ |
2568 | thumb_flag_modifies_zn_maybe_c(); \ |
2569 | break; \ |
2570 | \ |
2571 | case 0x01: \ |
2572 | /* ADC rd, rs */ \ |
2573 | thumb_flag_modifies_all(); \ |
2574 | thumb_flag_requires_c(); \ |
2575 | break; \ |
2576 | \ |
2577 | case 0x02: \ |
2578 | /* SBC rd, rs */ \ |
2579 | thumb_flag_modifies_all(); \ |
2580 | thumb_flag_requires_c(); \ |
2581 | break; \ |
2582 | \ |
2583 | case 0x03: \ |
2584 | /* ROR rd, rs */ \ |
2585 | thumb_flag_modifies_zn_maybe_c(); \ |
2586 | break; \ |
2587 | } \ |
2588 | break; \ |
2589 | \ |
2590 | /* TST, NEG, CMP, CMN */ \ |
2591 | case 0x42: \ |
2592 | thumb_flag_modifies_all(); \ |
2593 | break; \ |
2594 | \ |
2595 | /* ORR, MUL, BIC, MVN */ \ |
2596 | case 0x43: \ |
2597 | thumb_flag_modifies_zn(); \ |
2598 | break; \ |
2599 | \ |
2600 | case 0x45: \ |
2601 | /* CMP rd, rs */ \ |
2602 | thumb_flag_modifies_all(); \ |
2603 | break; \ |
2604 | \ |
2605 | /* mov might change PC (fall through if so) */ \ |
2606 | case 0x46: \ |
2607 | if((opcode & 0xFF87) != 0x4687) \ |
2608 | break; \ |
2609 | \ |
2610 | /* branches (can change PC) */ \ |
2611 | case 0x47: \ |
2612 | case 0xBD: \ |
2613 | case 0xD0 ... 0xE7: \ |
2614 | case 0xF0 ... 0xFF: \ |
2615 | thumb_flag_requires_all(); \ |
2616 | break; \ |
2617 | } \ |
2618 | block_data[block_data_position].flag_data = flag_status; \ |
2619 | } \ |
2620 | |
2621 | u8 *ram_block_ptrs[1024 * 64]; |
2622 | u32 ram_block_tag_top = 0x0101; |
2623 | |
2624 | u8 *bios_block_ptrs[1024 * 8]; |
2625 | u32 bios_block_tag_top = 0x0101; |
2626 | |
2627 | // This function will return a pointer to a translated block of code. If it |
2628 | // doesn't exist it will translate it, if it does it will pass it back. |
2629 | |
2630 | // type should be "arm", "thumb", or "dual." For arm or thumb the PC should |
2631 | // be a real PC, for dual the least significant bit will determine if it's |
2632 | // ARM or Thumb mode. |
2633 | |
2634 | #define block_lookup_address_pc_arm() \ |
2635 | pc &= ~0x03 |
2636 | |
2637 | #define block_lookup_address_pc_thumb() \ |
2638 | pc &= ~0x01 \ |
2639 | |
2640 | #define block_lookup_address_pc_dual() \ |
2641 | u32 thumb = pc & 0x01; \ |
2642 | \ |
2643 | if(thumb) \ |
2644 | { \ |
2645 | pc--; \ |
2646 | reg[REG_CPSR] |= 0x20; \ |
2647 | } \ |
2648 | else \ |
2649 | { \ |
2650 | pc = (pc + 2) & ~0x03; \ |
2651 | reg[REG_CPSR] &= ~0x20; \ |
2652 | } \ |
2653 | |
2654 | #define ram_translation_region TRANSLATION_REGION_RAM |
2655 | #define rom_translation_region TRANSLATION_REGION_ROM |
2656 | #define bios_translation_region TRANSLATION_REGION_BIOS |
2657 | |
2658 | #define block_lookup_translate_arm(mem_type, smc_enable) \ |
2659 | translation_result = translate_block_arm(pc, mem_type##_translation_region, \ |
2660 | smc_enable) \ |
2661 | |
2662 | #define block_lookup_translate_thumb(mem_type, smc_enable) \ |
2663 | translation_result = translate_block_thumb(pc, \ |
2664 | mem_type##_translation_region, smc_enable) \ |
2665 | |
2666 | #define block_lookup_translate_dual(mem_type, smc_enable) \ |
2667 | if(thumb) \ |
2668 | { \ |
2669 | translation_result = translate_block_thumb(pc, \ |
2670 | mem_type##_translation_region, smc_enable); \ |
2671 | } \ |
2672 | else \ |
2673 | { \ |
2674 | translation_result = translate_block_arm(pc, \ |
2675 | mem_type##_translation_region, smc_enable); \ |
2676 | } \ |
2677 | |
2678 | // 0x0101 is the smallest tag that can be used. 0xFFFF is marked |
2679 | // in the middle of blocks and used for write guarding, it doesn't |
2680 | // indicate a valid block either (it's okay to compile a new block |
2681 | // that overlaps the earlier one, although this should be relatively |
2682 | // uncommon) |
2683 | |
2684 | #define fill_tag_arm(mem_type) \ |
2685 | location[0] = mem_type##_block_tag_top; \ |
2686 | location[1] = 0xFFFF \ |
2687 | |
2688 | #define fill_tag_thumb(mem_type) \ |
2689 | *location = mem_type##_block_tag_top \ |
2690 | |
2691 | #define fill_tag_dual(mem_type) \ |
2692 | if(thumb) \ |
2693 | fill_tag_thumb(mem_type); \ |
2694 | else \ |
2695 | fill_tag_arm(mem_type) \ |
2696 | |
2697 | #define block_lookup_translate(instruction_type, mem_type, smc_enable) \ |
2698 | block_tag = *location; \ |
2699 | if((block_tag < 0x0101) || (block_tag == 0xFFFF)) \ |
2700 | { \ |
2701 | __label__ redo; \ |
2702 | s32 translation_result; \ |
2703 | \ |
2704 | redo: \ |
2705 | \ |
2706 | translation_recursion_level++; \ |
2707 | block_address = mem_type##_translation_ptr + block_prologue_size; \ |
2708 | mem_type##_block_ptrs[mem_type##_block_tag_top] = block_address; \ |
2709 | fill_tag_##instruction_type(mem_type); \ |
2710 | mem_type##_block_tag_top++; \ |
2711 | \ |
2712 | block_lookup_translate_##instruction_type(mem_type, smc_enable); \ |
2713 | translation_recursion_level--; \ |
2714 | \ |
2715 | /* If the translation failed then pass that failure on if we're in \ |
2716 | a recursive level, or try again if we've hit the bottom. */ \ |
2717 | if(translation_result == -1) \ |
2718 | { \ |
2719 | if(translation_recursion_level) \ |
2720 | return NULL; \ |
2721 | \ |
2722 | goto redo; \ |
2723 | } \ |
2724 | \ |
2725 | if(translation_recursion_level == 0) \ |
2726 | translate_invalidate_dcache(); \ |
2727 | } \ |
2728 | else \ |
2729 | { \ |
2730 | block_address = mem_type##_block_ptrs[block_tag]; \ |
2731 | } \ |
2732 | |
2733 | u32 translation_recursion_level = 0; |
2734 | u32 translation_flush_count = 0; |
2735 | |
2736 | |
2737 | #define block_lookup_address_builder(type) \ |
2738 | u8 function_cc *block_lookup_address_##type(u32 pc) \ |
2739 | { \ |
2740 | u16 *location; \ |
2741 | u32 block_tag; \ |
2742 | u8 *block_address; \ |
2743 | \ |
2744 | /* Starting at the beginning, we allow for one translation cache flush. */ \ |
2745 | if(translation_recursion_level == 0) \ |
2746 | translation_flush_count = 0; \ |
2747 | block_lookup_address_pc_##type(); \ |
2748 | \ |
2749 | switch(pc >> 24) \ |
2750 | { \ |
2751 | case 0x0: \ |
2752 | bios_region_read_allow(); \ |
2753 | location = (u16 *)(bios_rom + pc + 0x4000); \ |
2754 | block_lookup_translate(type, bios, 0); \ |
2755 | if(translation_recursion_level == 0) \ |
2756 | bios_region_read_allow(); \ |
2757 | break; \ |
2758 | \ |
2759 | case 0x2: \ |
2760 | location = (u16 *)(ewram + (pc & 0x7FFF) + ((pc & 0x38000) * 2)); \ |
2761 | block_lookup_translate(type, ram, 1); \ |
2762 | if(translation_recursion_level == 0) \ |
2763 | bios_region_read_protect(); \ |
2764 | break; \ |
2765 | \ |
2766 | case 0x3: \ |
2767 | location = (u16 *)(iwram + (pc & 0x7FFF)); \ |
2768 | block_lookup_translate(type, ram, 1); \ |
2769 | if(translation_recursion_level == 0) \ |
2770 | bios_region_read_protect(); \ |
2771 | break; \ |
2772 | \ |
2773 | case 0x8 ... 0xD: \ |
2774 | { \ |
2775 | u32 hash_target = ((pc * 2654435761U) >> 16) & \ |
2776 | (ROM_BRANCH_HASH_SIZE - 1); \ |
2777 | u32 *block_ptr = rom_branch_hash[hash_target]; \ |
2778 | u32 **block_ptr_address = rom_branch_hash + hash_target; \ |
2779 | \ |
2780 | while(block_ptr) \ |
2781 | { \ |
2782 | if(block_ptr[0] == pc) \ |
2783 | { \ |
2784 | block_address = (u8 *)(block_ptr + 2) + block_prologue_size; \ |
2785 | break; \ |
2786 | } \ |
2787 | \ |
2788 | block_ptr_address = (u32 **)(block_ptr + 1); \ |
2789 | block_ptr = (u32 *)block_ptr[1]; \ |
2790 | } \ |
2791 | \ |
2792 | if(block_ptr == NULL) \ |
2793 | { \ |
2794 | __label__ redo; \ |
2795 | s32 translation_result; \ |
2796 | \ |
2797 | redo: \ |
2798 | \ |
2799 | translation_recursion_level++; \ |
2800 | ((u32 *)rom_translation_ptr)[0] = pc; \ |
2801 | ((u32 **)rom_translation_ptr)[1] = NULL; \ |
2802 | *block_ptr_address = (u32 *)rom_translation_ptr; \ |
2803 | rom_translation_ptr += 8; \ |
2804 | block_address = rom_translation_ptr + block_prologue_size; \ |
2805 | block_lookup_translate_##type(rom, 0); \ |
2806 | translation_recursion_level--; \ |
2807 | \ |
2808 | /* If the translation failed then pass that failure on if we're in \ |
2809 | a recursive level, or try again if we've hit the bottom. */ \ |
2810 | if(translation_result == -1) \ |
2811 | { \ |
2812 | if(translation_recursion_level) \ |
2813 | return NULL; \ |
2814 | \ |
2815 | goto redo; \ |
2816 | } \ |
2817 | \ |
2818 | if(translation_recursion_level == 0) \ |
2819 | translate_invalidate_dcache(); \ |
2820 | } \ |
2821 | if(translation_recursion_level == 0) \ |
2822 | bios_region_read_protect(); \ |
2823 | break; \ |
2824 | } \ |
2825 | \ |
2826 | default: \ |
2827 | /* If we're at the bottom, it means we're actually trying to jump to an \ |
2828 | address that we can't handle. Otherwise, it means that code scanned \ |
2829 | has reached an address that can't be handled, which means that we \ |
2830 | have most likely hit an area that doesn't contain code yet (for \ |
2831 | instance, in RAM). If such a thing happens, return -1 and the \ |
2832 | block translater will naively link it (it'll be okay, since it \ |
2833 | should never be hit) */ \ |
2834 | if(translation_recursion_level == 0) \ |
2835 | { \ |
2836 | char buffer[256]; \ |
2837 | sprintf(buffer, "bad jump %x (%x) (%x)\n", pc, reg[REG_PC], \ |
2838 | last_instruction); \ |
eac69717 |
2839 | printf("%s", buffer); \ |
2823a4c8 |
2840 | quit(); \ |
2841 | } \ |
2842 | block_address = (u8 *)(-1); \ |
2843 | break; \ |
2844 | } \ |
2845 | \ |
2846 | return block_address; \ |
2847 | } \ |
2848 | |
2849 | block_lookup_address_builder(arm); |
2850 | block_lookup_address_builder(thumb); |
2851 | block_lookup_address_builder(dual); |
2852 | |
2853 | // Potential exit point: If the rd field is pc for instructions is 0x0F, |
2854 | // the instruction is b/bl/bx, or the instruction is ldm with PC in the |
2855 | // register list. |
2856 | // All instructions with upper 3 bits less than 100b have an rd field |
2857 | // except bx, where the bits must be 0xF there anyway, multiplies, |
2858 | // which cannot have 0xF in the corresponding fields, and msr, which |
2859 | // has 0x0F there but doesn't end things (therefore must be special |
2860 | // checked against). Because MSR and BX overlap both are checked for. |
2861 | |
2862 | #define arm_exit_point \ |
2863 | (((opcode < 0x8000000) && ((opcode & 0x000F000) == 0x000F000) && \ |
2864 | ((opcode & 0xDB0F000) != 0x120F000)) || \ |
2865 | ((opcode & 0x12FFF10) == 0x12FFF10) || \ |
2866 | ((opcode & 0x8108000) == 0x8108000) || \ |
2867 | ((opcode >= 0xA000000) && (opcode < 0xF000000)) || \ |
2868 | ((opcode > 0xF000000) && (!swi_hle_handle[((opcode >> 16) & 0xFF)]))) \ |
2869 | |
2870 | #define arm_opcode_branch \ |
2871 | ((opcode & 0xE000000) == 0xA000000) \ |
2872 | |
2873 | #define arm_opcode_swi \ |
2874 | ((opcode & 0xF000000) == 0xF000000) \ |
2875 | |
2876 | #define arm_opcode_unconditional_branch \ |
2877 | (condition == 0x0E) \ |
2878 | |
2879 | #define arm_load_opcode() \ |
2880 | opcode = address32(pc_address_block, (block_end_pc & 0x7FFF)); \ |
2881 | condition = opcode >> 28; \ |
2882 | \ |
2883 | opcode &= 0xFFFFFFF; \ |
2884 | \ |
2885 | block_end_pc += 4 \ |
2886 | |
2887 | #define arm_branch_target() \ |
2888 | branch_target = (block_end_pc + 4 + (((s32)(opcode & 0xFFFFFF) << 8) >> 6)) \ |
2889 | |
2890 | // Contiguous conditional block flags modification - it will set 0x20 in the |
2891 | // condition's bits if this instruction modifies flags. Taken from the CPU |
2892 | // switch so it'd better be right this time. |
2893 | |
2894 | #define arm_set_condition(_condition) \ |
2895 | block_data[block_data_position].condition = _condition; \ |
2896 | switch((opcode >> 20) & 0xFF) \ |
2897 | { \ |
2898 | case 0x01: \ |
2899 | case 0x03: \ |
2900 | case 0x09: \ |
2901 | case 0x0B: \ |
2902 | case 0x0D: \ |
2903 | case 0x0F: \ |
2904 | if((((opcode >> 5) & 0x03) == 0) || ((opcode & 0x90) != 0x90)) \ |
2905 | block_data[block_data_position].condition |= 0x20; \ |
2906 | break; \ |
2907 | \ |
2908 | case 0x05: \ |
2909 | case 0x07: \ |
2910 | case 0x11: \ |
2911 | case 0x13: \ |
2912 | case 0x15 ... 0x17: \ |
2913 | case 0x19: \ |
2914 | case 0x1B: \ |
2915 | case 0x1D: \ |
2916 | case 0x1F: \ |
2917 | if((opcode & 0x90) != 0x90) \ |
2918 | block_data[block_data_position].condition |= 0x20; \ |
2919 | break; \ |
2920 | \ |
2921 | case 0x12: \ |
2922 | if(((opcode & 0x90) != 0x90) && !(opcode & 0x10)) \ |
2923 | block_data[block_data_position].condition |= 0x20; \ |
2924 | break; \ |
2925 | \ |
2926 | case 0x21: \ |
2927 | case 0x23: \ |
2928 | case 0x25: \ |
2929 | case 0x27: \ |
2930 | case 0x29: \ |
2931 | case 0x2B: \ |
2932 | case 0x2D: \ |
2933 | case 0x2F ... 0x37: \ |
2934 | case 0x39: \ |
2935 | case 0x3B: \ |
2936 | case 0x3D: \ |
2937 | case 0x3F: \ |
2938 | block_data[block_data_position].condition |= 0x20; \ |
2939 | break; \ |
2940 | } \ |
2941 | |
2942 | #define arm_link_block() \ |
2943 | translation_target = block_lookup_address_arm(branch_target) \ |
2944 | |
2945 | #define arm_instruction_width 4 |
2946 | |
2947 | #define arm_base_cycles() \ |
2948 | cycle_count += waitstate_cycles_sequential[pc >> 24][2] \ |
2949 | |
2950 | // For now this just sets a variable that says flags should always be |
2951 | // computed. |
2952 | |
2953 | #define arm_dead_flag_eliminate() \ |
2954 | flag_status = 0xF \ |
2955 | |
2956 | // The following Thumb instructions can exit: |
2957 | // b, bl, bx, swi, pop {... pc}, and mov pc, ..., the latter being a hireg |
2958 | // op only. Rather simpler to identify than the ARM set. |
2959 | |
2960 | #define thumb_exit_point \ |
2961 | (((opcode >= 0xD000) && (opcode < 0xDF00)) || \ |
2962 | (((opcode & 0xFF00) == 0xDF00) && \ |
2963 | (!swi_hle_handle[opcode & 0xFF])) || \ |
2964 | ((opcode >= 0xE000) && (opcode < 0xE800)) || \ |
2965 | ((opcode & 0xFF00) == 0x4700) || \ |
2966 | ((opcode & 0xFF00) == 0xBD00) || \ |
2967 | ((opcode & 0xFF87) == 0x4687) || \ |
2968 | ((opcode >= 0xF800))) \ |
2969 | |
2970 | #define thumb_opcode_branch \ |
2971 | (((opcode >= 0xD000) && (opcode < 0xDF00)) || \ |
2972 | ((opcode >= 0xE000) && (opcode < 0xE800)) || \ |
2973 | (opcode >= 0xF800)) \ |
2974 | |
2975 | #define thumb_opcode_swi \ |
2976 | ((opcode & 0xFF00) == 0xDF00) \ |
2977 | |
2978 | #define thumb_opcode_unconditional_branch \ |
2979 | ((opcode < 0xD000) || (opcode >= 0xDF00)) \ |
2980 | |
2981 | #define thumb_load_opcode() \ |
2982 | last_opcode = opcode; \ |
2983 | opcode = address16(pc_address_block, (block_end_pc & 0x7FFF)); \ |
2984 | \ |
2985 | block_end_pc += 2 \ |
2986 | |
2987 | #define thumb_branch_target() \ |
2988 | if(opcode < 0xE000) \ |
2989 | { \ |
2990 | branch_target = block_end_pc + 2 + ((s8)(opcode & 0xFF) * 2); \ |
2991 | } \ |
2992 | else \ |
2993 | \ |
2994 | if(opcode < 0xF800) \ |
2995 | { \ |
2996 | branch_target = block_end_pc + 2 + ((s32)((opcode & 0x7FF) << 21) >> 20); \ |
2997 | } \ |
2998 | else \ |
2999 | { \ |
3000 | if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \ |
3001 | { \ |
3002 | branch_target = \ |
3003 | (block_end_pc + ((s32)((last_opcode & 0x07FF) << 21) >> 9) + \ |
3004 | ((opcode & 0x07FF) * 2)); \ |
3005 | } \ |
3006 | else \ |
3007 | { \ |
3008 | goto no_direct_branch; \ |
3009 | } \ |
3010 | } \ |
3011 | |
3012 | #define thumb_set_condition(_condition) \ |
3013 | |
3014 | #define thumb_link_block() \ |
3015 | if(branch_target != 0x00000008) \ |
3016 | translation_target = block_lookup_address_thumb(branch_target); \ |
3017 | else \ |
3018 | translation_target = block_lookup_address_arm(branch_target) \ |
3019 | |
3020 | #define thumb_instruction_width 2 |
3021 | |
3022 | #define thumb_base_cycles() \ |
3023 | cycle_count += waitstate_cycles_sequential[pc >> 24][1] \ |
3024 | |
3025 | // Here's how this works: each instruction has three different sets of flag |
3026 | // attributes, each consisiting of a 4bit mask describing how that instruction |
3027 | // interacts with the 4 main flags (N/Z/C/V). |
3028 | // The first set, in bits 0:3, is the set of flags the instruction may |
3029 | // modify. After this pass this is changed to the set of flags the instruction |
3030 | // should modify - if the bit for the corresponding flag is not set then code |
3031 | // does not have to be generated to calculate the flag for that instruction. |
3032 | |
3033 | // The second set, in bits 7:4, is the set of flags that the instruction must |
3034 | // modify (ie, for shifts by the register values the instruction may not |
3035 | // always modify the C flag, and thus the C bit won't be set here). |
3036 | |
3037 | // The third set, in bits 11:8, is the set of flags that the instruction uses |
3038 | // in its computation, or the set of flags that will be needed after the |
3039 | // instruction is done. For any instructions that change the PC all of the |
3040 | // bits should be set because it is (for now) unknown what flags will be |
3041 | // needed after it arrives at its destination. Instructions that use the |
3042 | // carry flag as input will have it set as well. |
3043 | |
3044 | // The algorithm is a simple liveness analysis procedure: It starts at the |
3045 | // bottom of the instruction stream and sets a "currently needed" mask to |
3046 | // the flags needed mask of the current instruction. Then it moves down |
3047 | // an instruction, ANDs that instructions "should generate" mask by the |
3048 | // "currently needed" mask, then ANDs the "currently needed" mask by |
3049 | // the 1's complement of the instruction's "must generate" mask, and ORs |
3050 | // the "currently needed" mask by the instruction's "flags needed" mask. |
3051 | |
3052 | #define thumb_dead_flag_eliminate() \ |
3053 | { \ |
3054 | u32 needed_mask; \ |
3055 | needed_mask = block_data[block_data_position].flag_data >> 8; \ |
3056 | \ |
3057 | block_data_position--; \ |
3058 | while(block_data_position >= 0) \ |
3059 | { \ |
3060 | flag_status = block_data[block_data_position].flag_data; \ |
3061 | block_data[block_data_position].flag_data = \ |
3062 | (flag_status & needed_mask); \ |
3063 | needed_mask &= ~((flag_status >> 4) & 0x0F); \ |
3064 | needed_mask |= flag_status >> 8; \ |
3065 | block_data_position--; \ |
3066 | } \ |
3067 | } \ |
3068 | |
3069 | #define MAX_BLOCK_SIZE 8192 |
3070 | #define MAX_EXITS 256 |
3071 | |
3072 | block_data_type block_data[MAX_BLOCK_SIZE]; |
3073 | block_exit_type block_exits[MAX_EXITS]; |
3074 | |
3075 | #define smc_write_arm_yes() \ |
3076 | if(address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \ |
3077 | { \ |
3078 | address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = \ |
3079 | 0xFFFFFFFF; \ |
3080 | } \ |
3081 | |
3082 | #define smc_write_thumb_yes() \ |
3083 | if(address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \ |
3084 | { \ |
3085 | address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = 0xFFFF; \ |
3086 | } \ |
3087 | |
3088 | #define smc_write_arm_no() \ |
3089 | |
3090 | #define smc_write_thumb_no() \ |
3091 | |
3092 | #define scan_block(type, smc_write_op) \ |
3093 | { \ |
3094 | __label__ block_end; \ |
3095 | /* Find the end of the block */ \ |
3096 | do \ |
3097 | { \ |
3098 | check_pc_region(block_end_pc); \ |
3099 | smc_write_##type##_##smc_write_op(); \ |
3100 | type##_load_opcode(); \ |
3101 | type##_flag_status(); \ |
3102 | \ |
3103 | if(type##_exit_point) \ |
3104 | { \ |
3105 | /* Branch/branch with link */ \ |
3106 | if(type##_opcode_branch) \ |
3107 | { \ |
3108 | __label__ no_direct_branch; \ |
3109 | type##_branch_target(); \ |
3110 | block_exits[block_exit_position].branch_target = branch_target; \ |
3111 | block_exit_position++; \ |
3112 | \ |
3113 | /* Give the branch target macro somewhere to bail if it turns out to \ |
3114 | be an indirect branch (ala malformed Thumb bl) */ \ |
3115 | no_direct_branch:; \ |
3116 | } \ |
3117 | \ |
3118 | /* SWI branches to the BIOS, this will likely change when \ |
3119 | some HLE BIOS is implemented. */ \ |
3120 | if(type##_opcode_swi) \ |
3121 | { \ |
3122 | block_exits[block_exit_position].branch_target = 0x00000008; \ |
3123 | block_exit_position++; \ |
3124 | } \ |
3125 | \ |
3126 | type##_set_condition(condition | 0x10); \ |
3127 | \ |
3128 | /* Only unconditional branches can end the block. */ \ |
3129 | if(type##_opcode_unconditional_branch) \ |
3130 | { \ |
3131 | /* Check to see if any prior block exits branch after here, \ |
3132 | if so don't end the block. Starts from the top and works \ |
3133 | down because the most recent branch is most likely to \ |
3134 | join after the end (if/then form) */ \ |
3135 | for(i = block_exit_position - 2; i >= 0; i--) \ |
3136 | { \ |
3137 | if(block_exits[i].branch_target == block_end_pc) \ |
3138 | break; \ |
3139 | } \ |
3140 | \ |
3141 | if(i < 0) \ |
3142 | break; \ |
3143 | } \ |
3144 | if(block_exit_position == MAX_EXITS) \ |
3145 | break; \ |
3146 | } \ |
3147 | else \ |
3148 | { \ |
3149 | type##_set_condition(condition); \ |
3150 | } \ |
3151 | \ |
3152 | for(i = 0; i < translation_gate_targets; i++) \ |
3153 | { \ |
3154 | if(block_end_pc == translation_gate_target_pc[i]) \ |
3155 | goto block_end; \ |
3156 | } \ |
3157 | \ |
3158 | block_data[block_data_position].update_cycles = 0; \ |
3159 | block_data_position++; \ |
3160 | if((block_data_position == MAX_BLOCK_SIZE) || \ |
3161 | (block_end_pc == 0x3007FF0) || (block_end_pc == 0x203FFFF0)) \ |
3162 | { \ |
3163 | break; \ |
3164 | } \ |
3165 | } while(1); \ |
3166 | \ |
3167 | block_end:; \ |
3168 | } \ |
3169 | |
3170 | #define arm_fix_pc() \ |
3171 | pc &= ~0x03 \ |
3172 | |
3173 | #define thumb_fix_pc() \ |
3174 | pc &= ~0x01 \ |
3175 | |
3176 | #define translate_block_builder(type) \ |
3177 | s32 translate_block_##type(u32 pc, translation_region_type \ |
3178 | translation_region, u32 smc_enable) \ |
3179 | { \ |
bbba3209 |
3180 | u32 opcode = 0; \ |
2823a4c8 |
3181 | u32 last_opcode; \ |
3182 | u32 condition; \ |
3183 | u32 last_condition; \ |
3184 | u32 pc_region = (pc >> 15); \ |
3185 | u32 new_pc_region; \ |
3186 | u8 *pc_address_block = memory_map_read[pc_region]; \ |
3187 | u32 block_start_pc = pc; \ |
3188 | u32 block_end_pc = pc; \ |
3189 | u32 block_exit_position = 0; \ |
3190 | s32 block_data_position = 0; \ |
3191 | u32 external_block_exit_position = 0; \ |
3192 | u32 branch_target; \ |
3193 | u32 cycle_count = 0; \ |
3194 | u8 *translation_target; \ |
bbba3209 |
3195 | u8 *backpatch_address = NULL; \ |
3196 | u8 *translation_ptr = NULL; \ |
3197 | u8 *translation_cache_limit = NULL; \ |
2823a4c8 |
3198 | s32 i; \ |
3199 | u32 flag_status; \ |
3200 | block_exit_type external_block_exits[MAX_EXITS]; \ |
3201 | generate_block_extra_vars_##type(); \ |
3202 | type##_fix_pc(); \ |
3203 | \ |
3204 | if(pc_address_block == NULL) \ |
3205 | pc_address_block = load_gamepak_page(pc_region & 0x3FF); \ |
3206 | \ |
3207 | switch(translation_region) \ |
3208 | { \ |
3209 | case TRANSLATION_REGION_RAM: \ |
3210 | if(pc >= 0x3000000) \ |
3211 | { \ |
3212 | if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \ |
3213 | iwram_code_min = pc; \ |
3214 | } \ |
3215 | else \ |
3216 | \ |
3217 | if(pc >= 0x2000000) \ |
3218 | { \ |
3219 | if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \ |
3220 | ewram_code_min = pc; \ |
3221 | } \ |
3222 | \ |
3223 | translation_ptr = ram_translation_ptr; \ |
3224 | translation_cache_limit = \ |
3225 | ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \ |
3226 | TRANSLATION_CACHE_LIMIT_THRESHOLD; \ |
3227 | break; \ |
3228 | \ |
3229 | case TRANSLATION_REGION_ROM: \ |
3230 | translation_ptr = rom_translation_ptr; \ |
3231 | translation_cache_limit = \ |
3232 | rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \ |
3233 | TRANSLATION_CACHE_LIMIT_THRESHOLD; \ |
3234 | break; \ |
3235 | \ |
3236 | case TRANSLATION_REGION_BIOS: \ |
3237 | translation_ptr = bios_translation_ptr; \ |
3238 | translation_cache_limit = bios_translation_cache + \ |
3239 | BIOS_TRANSLATION_CACHE_SIZE; \ |
3240 | break; \ |
3241 | } \ |
3242 | \ |
3243 | generate_block_prologue(); \ |
3244 | \ |
3245 | /* This is a function because it's used a lot more than it might seem (all \ |
3246 | of the data processing functions can access it), and its expansion was \ |
3247 | massacreing the compiler. */ \ |
3248 | \ |
3249 | if(smc_enable) \ |
3250 | { \ |
3251 | scan_block(type, yes); \ |
3252 | } \ |
3253 | else \ |
3254 | { \ |
3255 | scan_block(type, no); \ |
3256 | } \ |
3257 | \ |
3258 | for(i = 0; i < block_exit_position; i++) \ |
3259 | { \ |
3260 | branch_target = block_exits[i].branch_target; \ |
3261 | \ |
3262 | if((branch_target > block_start_pc) && \ |
3263 | (branch_target < block_end_pc)) \ |
3264 | { \ |
3265 | block_data[(branch_target - block_start_pc) / \ |
3266 | type##_instruction_width].update_cycles = 1; \ |
3267 | } \ |
3268 | } \ |
3269 | \ |
3270 | type##_dead_flag_eliminate(); \ |
3271 | \ |
3272 | block_exit_position = 0; \ |
3273 | block_data_position = 0; \ |
3274 | \ |
3275 | last_condition = 0x0E; \ |
3276 | \ |
3277 | while(pc != block_end_pc) \ |
3278 | { \ |
3279 | block_data[block_data_position].block_offset = translation_ptr; \ |
3280 | type##_base_cycles(); \ |
3281 | /*generate_step_debug();*/ \ |
3282 | \ |
3283 | translate_##type##_instruction(); \ |
3284 | block_data_position++; \ |
3285 | \ |
3286 | /* If it went too far the cache needs to be flushed and the process \ |
3287 | restarted. Because we might already be nested several stages in \ |
3288 | a simple recursive call here won't work, it has to pedal out to \ |
3289 | the beginning. */ \ |
3290 | \ |
3291 | if(translation_ptr > translation_cache_limit) \ |
3292 | { \ |
3293 | translation_flush_count++; \ |
3294 | \ |
3295 | switch(translation_region) \ |
3296 | { \ |
3297 | case TRANSLATION_REGION_RAM: \ |
3298 | flush_translation_cache_ram(); \ |
3299 | break; \ |
3300 | \ |
3301 | case TRANSLATION_REGION_ROM: \ |
3302 | flush_translation_cache_rom(); \ |
3303 | break; \ |
3304 | \ |
3305 | case TRANSLATION_REGION_BIOS: \ |
3306 | flush_translation_cache_bios(); \ |
3307 | break; \ |
3308 | } \ |
3309 | \ |
3310 | return -1; \ |
3311 | } \ |
3312 | \ |
3313 | /* If the next instruction is a block entry point update the \ |
3314 | cycle counter and update */ \ |
3315 | if(block_data[block_data_position].update_cycles == 1) \ |
3316 | { \ |
3317 | generate_cycle_update(); \ |
3318 | } \ |
3319 | } \ |
3320 | for(i = 0; i < translation_gate_targets; i++) \ |
3321 | { \ |
3322 | if(pc == translation_gate_target_pc[i]) \ |
3323 | { \ |
3324 | generate_translation_gate(type); \ |
3325 | break; \ |
3326 | } \ |
3327 | } \ |
3328 | \ |
3329 | for(i = 0; i < block_exit_position; i++) \ |
3330 | { \ |
3331 | branch_target = block_exits[i].branch_target; \ |
3332 | \ |
3333 | if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \ |
3334 | { \ |
3335 | /* Internal branch, patch to recorded address */ \ |
3336 | translation_target = \ |
3337 | block_data[(branch_target - block_start_pc) / \ |
3338 | type##_instruction_width].block_offset; \ |
3339 | \ |
3340 | generate_branch_patch_unconditional(block_exits[i].branch_source, \ |
3341 | translation_target); \ |
3342 | } \ |
3343 | else \ |
3344 | { \ |
3345 | /* External branch, save for later */ \ |
3346 | external_block_exits[external_block_exit_position].branch_target = \ |
3347 | branch_target; \ |
3348 | external_block_exits[external_block_exit_position].branch_source = \ |
3349 | block_exits[i].branch_source; \ |
3350 | external_block_exit_position++; \ |
3351 | } \ |
3352 | } \ |
3353 | \ |
3354 | switch(translation_region) \ |
3355 | { \ |
3356 | case TRANSLATION_REGION_RAM: \ |
3357 | if(pc >= 0x3000000) \ |
3358 | { \ |
3359 | if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \ |
3360 | iwram_code_max = pc; \ |
3361 | } \ |
3362 | else \ |
3363 | \ |
3364 | if(pc >= 0x2000000) \ |
3365 | { \ |
3366 | if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \ |
3367 | ewram_code_max = pc; \ |
3368 | } \ |
3369 | \ |
3370 | ram_translation_ptr = translation_ptr; \ |
3371 | break; \ |
3372 | \ |
3373 | case TRANSLATION_REGION_ROM: \ |
3374 | rom_translation_ptr = translation_ptr; \ |
3375 | break; \ |
3376 | \ |
3377 | case TRANSLATION_REGION_BIOS: \ |
3378 | bios_translation_ptr = translation_ptr; \ |
3379 | break; \ |
3380 | } \ |
3381 | \ |
3382 | for(i = 0; i < external_block_exit_position; i++) \ |
3383 | { \ |
3384 | branch_target = external_block_exits[i].branch_target; \ |
3385 | type##_link_block(); \ |
3386 | if(translation_target == NULL) \ |
3387 | return -1; \ |
3388 | generate_branch_patch_unconditional( \ |
3389 | external_block_exits[i].branch_source, translation_target); \ |
3390 | } \ |
3391 | \ |
3392 | return 0; \ |
3393 | } \ |
3394 | |
3395 | translate_block_builder(arm); |
3396 | translate_block_builder(thumb); |
3397 | |
3398 | void flush_translation_cache_ram() |
3399 | { |
3400 | flush_ram_count++; |
3401 | /* printf("ram flush %d (pc %x), %x to %x, %x to %x\n", |
3402 | flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max, |
3403 | ewram_code_min, ewram_code_max); */ |
3404 | |
3405 | #ifndef PC_BUILD |
3406 | invalidate_icache_region(ram_translation_cache, |
3407 | (ram_translation_ptr - ram_translation_cache) + 0x100); |
3408 | #endif |
eac69717 |
3409 | #ifdef ARM_ARCH |
f50ad10a |
3410 | last_ram_translation_ptr = ram_translation_cache; |
eac69717 |
3411 | #endif |
3412 | ram_translation_ptr = ram_translation_cache; |
2823a4c8 |
3413 | ram_block_tag_top = 0x0101; |
3414 | if(iwram_code_min != 0xFFFFFFFF) |
3415 | { |
3416 | iwram_code_min &= 0x7FFF; |
3417 | iwram_code_max &= 0x7FFF; |
3418 | memset(iwram + iwram_code_min, 0, iwram_code_max - iwram_code_min); |
3419 | } |
3420 | |
3421 | if(ewram_code_min != 0xFFFFFFFF) |
3422 | { |
3423 | u32 ewram_code_min_page; |
3424 | u32 ewram_code_max_page; |
3425 | u32 ewram_code_min_offset; |
3426 | u32 ewram_code_max_offset; |
3427 | u32 i; |
3428 | |
3429 | ewram_code_min &= 0x3FFFF; |
3430 | ewram_code_max &= 0x3FFFF; |
3431 | |
3432 | ewram_code_min_page = ewram_code_min >> 15; |
3433 | ewram_code_max_page = ewram_code_max >> 15; |
3434 | ewram_code_min_offset = ewram_code_min & 0x7FFF; |
3435 | ewram_code_max_offset = ewram_code_max & 0x7FFF; |
3436 | |
3437 | if(ewram_code_min_page == ewram_code_max_page) |
3438 | { |
3439 | memset(ewram + (ewram_code_min_page * 0x10000) + |
3440 | ewram_code_min_offset, 0, |
3441 | ewram_code_max_offset - ewram_code_min_offset); |
3442 | } |
3443 | else |
3444 | { |
3445 | for(i = ewram_code_min_page + 1; i < ewram_code_max_page; i++) |
3446 | { |
3447 | memset(ewram + (i * 0x10000), 0, 0x8000); |
3448 | } |
3449 | |
3450 | memset(ewram, 0, ewram_code_max_offset); |
3451 | } |
3452 | } |
3453 | |
3454 | iwram_code_min = 0xFFFFFFFF; |
3455 | iwram_code_max = 0xFFFFFFFF; |
3456 | ewram_code_min = 0xFFFFFFFF; |
3457 | ewram_code_max = 0xFFFFFFFF; |
3458 | } |
3459 | |
3460 | void flush_translation_cache_rom() |
3461 | { |
3462 | #ifndef PC_BUILD |
3463 | invalidate_icache_region(rom_translation_cache, |
3464 | rom_translation_ptr - rom_translation_cache + 0x100); |
3465 | #endif |
eac69717 |
3466 | #ifdef ARM_ARCH |
3467 | last_rom_translation_ptr = rom_translation_cache; |
3468 | #endif |
2823a4c8 |
3469 | |
3470 | rom_translation_ptr = rom_translation_cache; |
3471 | memset(rom_branch_hash, 0, sizeof(rom_branch_hash)); |
3472 | } |
3473 | |
3474 | void flush_translation_cache_bios() |
3475 | { |
3476 | #ifndef PC_BUILD |
3477 | invalidate_icache_region(bios_translation_cache, |
3478 | bios_translation_ptr - bios_translation_cache + 0x100); |
3479 | #endif |
eac69717 |
3480 | #ifdef ARM_ARCH |
3481 | last_bios_translation_ptr = bios_translation_cache; |
3482 | #endif |
2823a4c8 |
3483 | |
3484 | bios_block_tag_top = 0x0101; |
3485 | bios_translation_ptr = bios_translation_cache; |
3486 | memset(bios_rom + 0x4000, 0, 0x4000); |
3487 | } |
3488 | |
ee0a3871 |
3489 | #define cache_dump_prefix "" |
2823a4c8 |
3490 | |
3491 | void dump_translation_cache() |
3492 | { |
3493 | file_open(ram_cache, cache_dump_prefix "ram_cache.bin", write); |
3494 | file_write(ram_cache, ram_translation_cache, |
3495 | ram_translation_ptr - ram_translation_cache); |
3496 | file_close(ram_cache); |
3497 | |
3498 | file_open(rom_cache, cache_dump_prefix "rom_cache.bin", write); |
3499 | file_write(rom_cache, rom_translation_cache, |
3500 | rom_translation_ptr - rom_translation_cache); |
3501 | file_close(rom_cache); |
3502 | |
3503 | file_open(bios_cache, cache_dump_prefix "bios_cache.bin", write); |
3504 | file_write(bios_cache, bios_translation_cache, |
3505 | bios_translation_ptr - bios_translation_cache); |
3506 | file_close(bios_cache); |
3507 | } |
3508 | |