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